Initializing Angular controller on markup that is inserted after page load.

46 views
Skip to first unread message

Rob Lacey

unread,
Mar 6, 2015, 12:15:38 PM3/6/15
to ang...@googlegroups.com
I hope someone can point me in the right direction. We have an existing file upload solution which I need to add a feature to, I though I would ease in some more Angular into our application to do this as cleanly as possible. Once a file has uploaded a li representing the uploaded file's state will be added to the dom using jQuery, say something like.

<li id="asset1" 'ng-controller"="assetsPollerController as poller'>
    <span class="status {{status}} ng-init=>"id=1;state='queued';pollVideoAsset(1)">{{state}}</span
</li>

If this was already in the dom at the time that the angular code below was run, all is well.

adminApp = angular.module('adminApp', [])
adminApp.controller 'assetsPollerController', ($scope, $http) ->
  $scope.pollVideoAsset = ->
    if $scope.state == 'queued' || $scope.state == 'awaiting_file'
      $http.get('/api/v1/assets/' + $scope.id)
        .success (response) ->
          if response.video.state == 'queued'
            $timeout($scope.pollVideoAsset, 5000)
          else
            $.log(response.video.state)

However, how would I go about triggering the controller to take note of the newly included element in the page. Is there a way to re-run the controller for the page so that it picks anything new?

Many thanks for any thoughts and comments that might lead me in the right direction.

RobL

Mo Moadeli

unread,
Mar 6, 2015, 12:34:05 PM3/6/15
to ang...@googlegroups.com
You could retrigger the angular $compiler but that is an awfully heavy task fir such a simple thing.  My question is why do you have the ng-controller definition in the added 'li' node in the first place?  Why don't you add it to some parent dom node that is 'persistent'?  Something like this:

<parent-node 'ng-controller"="assetsPollerController as poller'> ....

<li id="asset1">
    <span class="status {{status}} ng-init=>"id=1;state='queued';pollVideoAsset(1)">{{state}}</span
</li>

</parent-node>

where 'parent-node'  is any HTML dom tag.

Rob Lacey

unread,
Mar 7, 2015, 12:59:57 PM3/7/15
to ang...@googlegroups.com
Honestly I'm fairly new to Angular so I might be missing something obvious. I've attached the controller to the <li> because I would expect to have potentially multiple file uploads each <li> being inserted into the dom as each file upload completes which could then tigger the poller. So to me each <li> is a separate instance of the controller. That may or may not be how I should approach the problem however. Perhaps a controller that handles the state of all of the uploads might be more efficient anyway.

Mo Moadeli

unread,
Mar 7, 2015, 1:24:43 PM3/7/15
to ang...@googlegroups.com
Roger that.  We are getting into more architectural issues now, so considering the notions of 'controllers' and 'services' in Angular, you are really maintaining two types of states:

1. The 'data' state of uploads (how many, what, when, where, etc) which is maintained normally in a 'service' that gets injected into any controller that needs that service.  Note, 'services' are normally 'singletons' so they maintain one 'data' state across the app and as they are injected into various client controllers where those controllers have access to the same 'single'ton state.  In MVC terms this is somewhat akin to the 'M'odel.

2. The 'visual' state of uploads (DOM manipulation) which as you have already surmised is handled by the controller.  In MVC this is akin to the combination of 'V'iew and 'C'ontroller combined. As you advance in AngularJS, there is even a better way to do this where this type of DOM manipulation can be delegated to an AngularJS 'directive' where you can replace your 'li' with your custom own HTML element called '<book>' or something like that that would carry out all the DOM manipulations AND interact with the data service.

If you want to start deploying AngularJS cleanly you should start separating the two states as shown above.  As it is right now, you are mingling the two, which of course you can make work, but it will quickly become a problem as your AngularJS app grows.  

If you just want to make it work quickly, just move the controller definition up the DOM parent tree to a persistent node, and away from the dynamic <li>, and you will have a persistent controller that can manage both data and visual states for now.

I hope this helps.

Mo

Rob Lacey

unread,
Mar 11, 2015, 5:26:50 AM3/11/15
to ang...@googlegroups.com
Thank you Mo, much food for thought.

RobL
Reply all
Reply to author
Forward
0 new messages