shared resources amongst mulitples of same controller type

62 views
Skip to first unread message

Jonathan Price

unread,
Sep 12, 2014, 3:17:27 AM9/12/14
to ang...@googlegroups.com
I have a page that has multiple instances of a given controller, all of which need similar data.  Their instantiation looks sort of like this:

<div ng-repeat="noteType in noteTypes" ng-controller="NoteController" ng-init="init('note.noteTypeID')">
blah blah blah
</div>

Initially, I had them all calling a service along these lines

    .controller('NoteController', ['$scope', '$log', '$sce', 'Utility', function($scope, $log, $sce, Utility){

            Utility.getList().success(
                function(shortcutCategory) {
                   ...init some stuff here...
            });
     }]);

where the service calls an https request for some data.  Now that I'm using multiples of this controller in the page, this seems dumb.  I'm guessing the best way to do this would be to populate something in the service itself with the 'getList' array, and just let the controllers access that array.  Thus preventing the multiple, unnecessary calls.

Two Questions:

1) First one is about timing.  The controllers really need that data to be available before some internal initialization.  I'm not sure how to handle the timing of that.  Should the service broadcast an event after it loads up the 'getList' data?

2)  Is my ng-init on the controller line an okay way to handle passing instance specific data to each controller?

Thanks!



dinesh kumar

unread,
Sep 12, 2014, 5:42:46 AM9/12/14
to ang...@googlegroups.com
for q1:
  this is where you use provider.for difference,check this link.
for q2:
  i Think that is ok to do it.

Thanks,
Dinesh kumar.L

Jonathan Price

unread,
Sep 12, 2014, 5:37:43 PM9/12/14
to ang...@googlegroups.com
I'm having trouble making the connection from that article.

Previously, I had:

    .factory('Utility', function($http) {
        return {
            getList: function() {
                return $http.get('getList.html');              
            }
    }

I've just switched to this to prevent the number of remote calls:

    .factory('Utility', function($http) {
        var aList = [];

        $http.get('getList.html').then(
            function(result) {
                aList = result;
            }
        );

          return {
            getList: function() {
                return aList;         
            }
    }

And while this is working, I still feel like I'm just getting lucky with the timing.  Are you saying there's a way I can accomplish this using a provider instead?  I see that they have the benefit of the configuration phase, but aren't other services (i.e. http) unavailable during that time?

Sander Elias

unread,
Sep 13, 2014, 2:31:56 AM9/13/14
to ang...@googlegroups.com

Hi Jonathan,

Yes, if that is working, it’s indeed mostly luck. This is where you need to build your own promise handler.
Something like this:

    .factory('Utility', function($http) { 
        var self = this;
        self.aList =  []; //placeholder

        self.reAssign = function (response) { //handle putting results into the placeholder
                 // don't forget to handle error's in here!
                 self.aList = response.data;
            };

        // a function to enable refetching. it also uses the promise to (re)populate the aList array.
        self.reftech= function () {self.pList = $http.get('getList.html').then(self.reAssign);}

        // kick off first time loading!
        self.refetch();
        return self;
     });

This will always return the promise, and the complete list. But it will only fetch only once, after that, it will just return the resolved promise.
Doing this, you have the means to check if the list is fetched already (the promise will be resolved/rejected), and the list itself readily
Available. This is similar to what ngResource does.

With kind regards
Sander

Puritan Paul

unread,
Sep 13, 2014, 6:41:03 PM9/13/14
to ang...@googlegroups.com
Hi Sander, thanks for the suggestion.  I haven’t tried it yet as I’ve found my problem is something a bit different that I originally thought.  It seems the bottleneck on loading this page is the size of a one http return - it’s coming back with 100 or so items, all of which have a text component of a few sentences.  I wouldn’t think that a huge payload, but it’s definitely adding a few seconds to load time.  I tried returning it without the text portion of each element, and it’s STILL adding a few seconds - which I’m having a hard time understanding.

Should a payload of that size (100-200 elements, each with two fields that are just integers) really add seconds to the load time?  That isn’t really that large is it?

I think my original idea (the solution to which you’ve posted) wouldn’t really help if this truly is the problem, no?

Also.  This is a component of a Coldfusion site that I’m trying to update with more front-end functionality.  So, I figured I could just bring the payload down with the initial request and populate the Controllers from that using the ng-init function.  But that’s not working either.  Looks something like this:

<div ng-controller=“MyController” ng-init=“init(preLoadedPayload)”>
<div ng-repeat=“piece in payload”>stuff</div>
</div>

.contoller(‘MyController’),  ['$scope', function($scope){
        $scope.payload = [];
        $scope.settings = [];

        $scope.init = function(backendPayload) {
            $scope.payload = backendPayload;

            for (var i = 0; i < $scope.payload.length; i++) {
                $scope.settings[i] = 0;
            };
        }
}])

Which I though would work, but I’m getting a ‘$scope.payload not defined’ error in the init function.  I don’t understand.  

Does this seem like a reasonable approach?  I’m feeling pretty lost about how to move forward.

All suggestions welcomed and greatly appreciated.



--
You received this message because you are subscribed to a topic in the Google Groups "AngularJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/angular/r-TxMo1bj14/unsubscribe.
To unsubscribe from this group and all its topics, send an email to angular+u...@googlegroups.com.
To post to this group, send email to ang...@googlegroups.com.
Visit this group at http://groups.google.com/group/angular.
For more options, visit https://groups.google.com/d/optout.

Jonathan Price

unread,
Sep 13, 2014, 11:40:44 PM9/13/14
to ang...@googlegroups.com
Okay, I've isolated the problem a bit further.  Everywhere I turn, it's something other than my original suspicion.

It looks like it's a directive population that's the real time hog here, not the http or JSON loading as I thought.  I've got something along these lines:

<div my-directive ng-repeat="item in category" some-text="{{item.TEXTFIELD}}"></div>

And my directive has a very basic template that just outputs the some-text item.

Originally, my directive had an isolate scope, so the some-text field was being copied, I assume?  I switched that to have scope: false, and the load time has been cut in about half.  BUT, It still feels really long, and I'm worried because this page is going to have a LOT more of these.

Is there any way to expedite this process?  These directives aren't initially visible within the page, so it would be great if there were some way to keep their loading from preventing the user from using the page.

I'm a little relieved that I narrowed down the problem, but I'm worried that this is a bottleneck that I can't get around.  I could delegate a lot of this stuff back into Coldfusion, but I'd love to not have to do that.

Any suggestions?

steven smock

unread,
Sep 14, 2014, 8:37:25 AM9/14/14
to ang...@googlegroups.com
It's good to hear that you're getting closer to goal, but yes, that does sound slow.  My initial thoughts are that it could be due to: (1) burdensome compile/link code, (2) too many scopes, or (3) some unexpected interference from the server or server-generated client content. 

Have you tried running it in the isolation of a plunk, in order to rule out any environmental (i.e. ColdFusion/web server) weirdness?  (You will need to dump your payload to a .js file, of course, or just throw together a 200-item generating dummy service.)

If you do get it running in a plunk, and you are still seeing the long load time, would you mind sharing it with us?

Finally, which version of Angular are you using?  I know a lot of recent changes, especially on (unstable) 1.3.*, have been performance-related: https://github.com/angular/angular.js/blob/master/CHANGELOG.md.

Puritan Paul

unread,
Sep 14, 2014, 3:38:46 PM9/14/14
to ang...@googlegroups.com
Here’s a plunkr:


I’m new to this, so I’m sure it’s pretty sloppy.  All suggestions welcomed!

Within the html, you’ll see my directive shortcut-new and below it a few other lines commented out.  One’s an emptier version of the same directive (no controller, empty link) and one is a regular div that has most of the same functionality (the directive is pretty small).

Within my app, when I use the shortcut-new directive, it’s the slowest.  When I switch to the plain div, it’s over twice as fast.



Message has been deleted

Sander Elias

unread,
Sep 15, 2014, 10:03:50 AM9/15/14
to ang...@googlegroups.com

Hi Jonathan,

I went quickly over your plunk and found a number of small issues. Not that you did anything wrong, but often you opted
for the most expensive way (from a performance view). all those small things combined makes your solution feeling a bit sluggish.

compare those 2 functions, and then remember that those get called a lot!

    getShortcutIndex = function(id) {
        for (var i = 0; i < $scope.shortcut.length; i++) {
            if (id === $scope.shortcut[i].SHORTCUTID) {
                return i;
            }
        }
    }

    getShortcutIndex = function(id) {
        var i=0 , l =  $scope.shortcut.length;
        while (id !== $scope.shortcut[i].SHORTCUTID && ++i<l) {
            //just loop
        }
        //only return i if there is indeed a match.
        return id !== $scope.shortcut[i].SHORTCUTID ? i : null;
    };

The first one traverse the entire array every time!. Also you are generating a awful of DOM that is not needed.
I did put in a directive counter, and in your orginal version it counted 1122 shortcut-new directives being generated.
User filters and ngIf to only show the items you need on screen. In te atached updated plunk I putted in just a couple of ngIf in stead of ngShow
and the count dropped to 5!!!
There is still a lot to be won. while it still only fires 5 directives, your solution has to do the looping for all, on every change…
I would replace the second nested ngRepeat with a singe one looping over the shortcut array and use a filter to get only the ‘active’ ones.
that reduces the number of loops quite a lot!
Have a look for yourself.

here is the updated plunk: http://plnkr.co/edit/oBUCFkWndGem3PG3LHb2?p=preview

If you have additional questions, don’t hesitate to ask them!

Regards
Sander

Reply all
Reply to author
Forward
0 new messages