Click here to Skip to main content
Click here to Skip to main content

View Manipulation in AngularJS Applications

By , 18 Feb 2014
Rate this:
Please Sign up or sign in to vote.

Introduction

This tip describes how to write JavaScript code which performs UI manipulations on the view side, without polluting controller code.

Background

Occasionally, everyone has bad luck to have to manipulate DOM imperatively, based on business logic. It’s a good idea to keep this code away from the controller. Problem comes up when you need access to controllers scope in UI code as soon as it’s created.

There are few rules which need to be followed in order to get the job done AND keep clean separation of concerns:

  1. Get access to controller scope as soon as possible
  2. Don’t make changes to controller which introduce dependency on UI code (it would be possible to call global function from a controller to inform about the event)
  3. Don’t create any global variables

Using the Code

A way to do this (admittedly, ugly way) is to use ngIf directive.

I marked controllers element with an ID so I can find its scope later, and aliased controller name to capture controller reference in a variable. I’ve called it vm here, as in “view-model”.

<div ng-controller="MyController as vm" id="myView">

Then I added script element where I can place UI manipulation code and applied ngIf directive to it. Parameter of ngIf directive is the controller.

<script type="text/javascript" ng-if="vm">
  var view = angular.element('#myView');
  if (view.hasClass('ng-scope')){
    $scope = view.scope();
 
    function viewManipulator($rootScope){
      alert('Controller has loaded');
      $scope.$watch('Name', function (newValue, oldValue){
        if (!newName)
          return;
        alert('Hello ' + newValue + '!');
      });
    }
 
    viewManipulator['$inject'] = ['$rootScope'];
    view.injector().invoke(viewManipulator);
  }
</script>

viewManipulator will be called right after controller is loaded and therefore scope is created and alert will show up. There, we can hook up watches over scope data.

How Does This Work?

Key is in lines 1 and 3. ngIf directive manipulates DOM to remove and add elements depending on the provided expression. The first time that browser loads the script, the script gets executed. Controller is not yet created at this point. For that reason we have line 3, which checks for magic AngularJS class. ng-scope class is a special class that AngularJS applies to elements which have their own scope created (for example, controller elements). First time that line 3 executes, controller is not created and ng-scope class is not applied.

AngularJS continues initializing the controller. Before MyController controller is fully created, ngIf directive on our script element removes the script (because our controller does not exist yet). After creation of controller is finished, ngIf is re-evaluated, vm is available and script element is added to DOM again. Because script is added, it is executed again, but this time line 3 evaluates to true so our UI manipulation code can be executed this time.

I’ve injected $rootScope just to illustrate that we can also get dependency injection. It’s not needed in this example. $scope cannot be injected, so we are closing over variable in which we captured it. Other services can be injected.

You can see a demonstration of the hack in this plunk. Buttons modify model in controller code, but UI is changed from view code which is hooked up to controllers scope. I can already hear some of you say “But you can do this with a filter!”. Yes, I can do what I demonstrated with a filter, but this is just a simplified example. Actual scenarios are not always so simple. Sometimes calculations need to be performed and complex decisions need to be made when changing the UI.

I hope this is useful to someone, and that I didn’t break too many rules with this approach.

History

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

No Biography provided

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web03 | 2.8.140415.2 | Last Updated 18 Feb 2014
Article Copyright 2014 by Nikola Radosavljevic
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid