diplosaurus
diplosaurus

Reputation: 2588

Directive needs data updated after element is rendered

Having trouble getting a directive to display properly with data that is updated via promise. The first directive updates perfectly, but the second and third do not.

Plunk

First, the data:

app.controller('MainCtrl', function($scope, $timeout) {
  $scope.data = {};

  $timeout(function() {
      angular.copy({totalItems: 100, pageSize: 10, currentPage: 1 }, $scope.data);
  }, 3000);
});

Then the directives:

var template1 = '{{(data.pageSize * (data.currentPage - 1)) + 1}} - {{data.pageSize * data.currentPage}} of {{data.totalItems}}';
var template2 = '{{lower}} - {{upper}} of {{total}}';
var dir = {
  restrict: 'C',
  template: template1,
  scope: false
};

app.directive('pagination', function() {
    return dir;    
});

app.directive('pagination2', function() {
  dir.template = template2;
  dir.link = function(scope, element, attrs) {
    scope.lower = (attrs.size * (attrs.currentPage - 1)) + 1;
    scope.upper = (attrs.size * attrs.currentPage);
    scope.total = attrs.total;
  };

  return dir;
});

app.directive('pagination3', function() {
  dir.template = template2;
  dir.link = function(scope, element, attrs) {
    scope.lower = (scope.data.pageSize * (scope.data.currentPage - 1)) + 1;
    scope.upper = (scope.data.pageSize * scope.data.currentPage);
    scope.total = scope.data.totalItems;
  };

  return dir;
});

And lastly the markup:

<div class="pagination"></div>
<div class="pagination2" total="{{data.totalItems}}" size="{{data.pageSize}}" current-page="{{data.currentPage}}"></div>
<div class="pagination3"></div>

I understand why the first one works. The $timeout finishes, my $scope is updated, dirty check ensues, everything is recalculated, and all is well.

In the second one I think I understand why it doesn't update - because the data is not there when I pass values to the element attributes, meaning the entire directive is built using undefined values. I would like to somehow correct this and have the directive update when $scope.data updates.

I figured I'd solve the problem I was having with the second directive with the third directive but am quite confused why this one doesn't work. I thought I had direct access to the $scope because my directive is using scope: false, but apparently not.

Upvotes: 0

Views: 37

Answers (1)

Rebornix
Rebornix

Reputation: 5270

app.directive('pagination3', function() {
  dir.template = template2;
  dir.link = function(scope, element, attrs) {
    scope.lower = (scope.data.pageSize * (scope.data.currentPage - 1)) + 1;
    scope.upper = (scope.data.pageSize * scope.data.currentPage);
    scope.total = scope.data.totalItems;
};

return dir;
});

Per your code, you are assigning scope.data.totalItems at directive's linking phase but at that time scope.data is just an empty object {}, it has no property called totalItems or pageSize or currentPage. lower, upper and total will be undefined after the assignment.

If you really don't want to put the calculation in your view template, you can monitor scope.data's change as below

app.directive('pagination3', function() {
  dir.template = template2;
  dir.link = function(scope, element, attrs) {
    scope.$watch('data', function(newVal, oldVal) {
      scope.lower = (newVal.pageSize * (newVal.currentPage - 1)) + 1;
      scope.upper = (newVal.pageSize * newVal.currentPage);
      scope.total = newVal.totalItems;
    }, true);
  };
  return dir;
};

Upvotes: 1

Related Questions