Load directive after AJAX call
Asked Answered
S

3

10

I have build a directive for pagination that takes two arguments; the current page and the total number of pages.

<pagination page="page" number-of-pages="numberOfPages"></pagination>

The issue is that I will only know the value of numberOfPages after an AJAX call (through ng-resource). But my directive is already rendered before that the AJAX call is done.

app.controller('MyController', function ($scope, $routeParams) {
    $scope.page = +$routeParams.page || 1,
    $scope.numberOfPages = 23; // This will work just fine

    MyResource.query({
        "page": $scope.page,
        "per_page": 100
    }, function (response) {
        //This won't work since the directive is already rendered
        $scope.numberOfPages = response.meta.number_of_pages;
    });
});

I prefer to wait with the rendering of my controllers template until the AJAX call is finished.

Plan B would be to append the template with the directives template when the AJAX call is done.

I'm stuck working out both scenarios.

Scruple answered 7/2, 2015 at 22:55 Comment(0)
W
11

You have to wait for the value using a $watch function like:

<div before-today="old" watch-me="numberOfPages" >{{exampleDate}}</div>

Directive

angular.module('myApp').directive('myPagingDirective', [
  function () {
    return {
        restrict: 'A',   
      link: function (scope, element, attr) {


        scope.$watch(attr.watchMe,function(newValue,oldValue){
                //check new value to be what you expect.
             if (newValue){           
                  // your code goes here
             }
        });
      } 
    };
  }
]);

Imporant: Your directive may use an isolated scope but even so the same principle stands.

Waring answered 7/2, 2015 at 22:57 Comment(3)
Thanks. I didn't knew about link (instead of controller). I think can hide the directive with ng-hide and show it when the value changes. But isn't it possible to just prevent the rendering until all is done?Scruple
Also; I got the watch function working. But how can I re-render the directive once the new change is detected?Scruple
can you give examples how to deal with isolated scope?Hefty
S
14

But isn't it possible to just prevent the rendering until all is done

  • I think ng-if would do that, contrary to ng-show/ng-hide which just alter the actual display
Shieh answered 7/2, 2015 at 23:37 Comment(4)
This also worked :). But i prefer to keep the delayed rendering logic inside the directive's JS code (instead of the HTML).Scruple
ng-if is a better solution since it should be the owner of directive (i.e. html) to decide whether to load itHefty
Another heads-up, it's easier to use ng-if on your html element than adding a scope.$watch function. I had the same problem of a large dataset being loaded from ajax and needed it before rendering my directive. Thanks for the tip!Foothold
This answer was what I was looking for. Great!Ambur
W
11

You have to wait for the value using a $watch function like:

<div before-today="old" watch-me="numberOfPages" >{{exampleDate}}</div>

Directive

angular.module('myApp').directive('myPagingDirective', [
  function () {
    return {
        restrict: 'A',   
      link: function (scope, element, attr) {


        scope.$watch(attr.watchMe,function(newValue,oldValue){
                //check new value to be what you expect.
             if (newValue){           
                  // your code goes here
             }
        });
      } 
    };
  }
]);

Imporant: Your directive may use an isolated scope but even so the same principle stands.

Waring answered 7/2, 2015 at 22:57 Comment(3)
Thanks. I didn't knew about link (instead of controller). I think can hide the directive with ng-hide and show it when the value changes. But isn't it possible to just prevent the rendering until all is done?Scruple
Also; I got the watch function working. But how can I re-render the directive once the new change is detected?Scruple
can you give examples how to deal with isolated scope?Hefty
E
0

If you use resolve from ui-router, you can have meta or meta.number_of_pages injected in your controller BEFORE it's view gets rendered.

//routes.js
angular.module('app')
  .state('some_route', {
    url: '/some_route',
    controller: 'MyController',
    resolve: {
      meta: ['MyResource', function (MyResource) {
        return MyResource.query({
          "page": $scope.page,
          "per_page": 100
        }, function (response) {
          return response.meta;
        });
      }]
    }
  });

//controllers.js
app.controller('MyController', function ($scope, $routeParams, meta) {
  $scope.page = +$routeParams.page || 1,
    $scope.numberOfPages = meta.number_of_pages;
});
Envisage answered 7/2, 2015 at 23:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.