0

I'm trying to pass some simple, numeric parameters into a custom directive. (I keep getting connection timeouts from Plunker, so please bear with me.)

HTML

  <body ng-controller="MainCtrl">
    <custom-page-selector
        record-count="recordCount"
        page-size="pageSize"
        page-number="pageNumber"
    ></custom-page-selector>
  </body>

JS

// AngularJS v1.2.16

app.controller('MainCtrl', function($scope) {
  $scope.pageSize = 20;
  $scope.recordCount = 53;
  $scope.pageNumber = 1;
});

app.directive("customPageSelector", [
  function () {
    function calcPages (recordCount, pageSize) {
      console.log("dividing " + recordCount + " by " + pageSize);
      return Math.ceil(recordCount / pageSize);
    }

    return {
      template: "<pre>\
                <p>recordCount = {{recordCount}}</p>\
                <p>pageSize    = {{pageSize}}</p>\
                <p>pageNumber  = {{pageNumber}}</p>\
            </pre>",
      replace: true,
      restrict: "E",
      scope: {
        recordCount: "=",
        pageSize:    "=",
        pageNumber:  "="
      },
      link: function(scope, element, attrs) {
        console.log("LINK: scope", scope);
        console.log("LINK: scope.recordCount", scope.recordCount); // logs "0"
        console.log("LINK: scope.pageSize", scope.pageSize);       // logs "20"

        attrs.$observe("recordCount", function(recCt) {
          console.log("OBSERVER: recCt", recCt);
          scope.totalPages = calcPages(recCt, scope.pageSize);
        });
      }
    };
  }
]);

Now, I know there are a couple of red flags. My simple numbers should probably be passed-in already interpolated (e.g., record-count="{{recordCount}}") and bound as strings (e.g., recordCount: "@"). I have tried that, and that's why you'll see the $observe function. I spent long enough trying to figure that out before finding this great answer.

Regardless, in the above example, why does scope correctly get the value of pageSize, but gets 0 for recordCount? Both are declared, passed, bound and reported the same way. I have danced around this every way I know how. Only using "@" and $observe have I been able to get the correct value for recordCount, but pageSize works as-is.

Community
  • 1
  • 1
nshew13
  • 3,052
  • 5
  • 25
  • 39
  • `&` is absolutely **not** the way to go ! It is for _"executing an expression in the context of the parent scope"_. – gkalpak May 13 '14 at 20:43
  • Oh, sorry. Not "&", "@". I'll correct. – nshew13 May 13 '14 at 20:44
  • What browser are you trying it on ? – gkalpak May 13 '14 at 20:46
  • You are missing a `;` after `$scope.pageSize = 20`, but is still seems to be working fine: http://jsfiddle.net/ExpertSystem/9Lh3E/ (I tested it on Chrome, Firefox and Safari) – gkalpak May 13 '14 at 20:49
  • I am using FF29. The template works (as `@` is resolved by then). It's the log functions and, more importantly, the `calcPages()` function that are getting the 0. – nshew13 May 13 '14 at 21:12
  • Did you try my demo above ? Like I said it works fine for me (in latest Chrome, Firefox (29) and Safari (5.17)). – gkalpak May 13 '14 at 21:17

1 Answers1

1

Something else must be going on outside of the code you provided that is causing scope.recordCount to be 0. Your code looks fine and I'm almost positive recordCount will be 53 if you throw it in a fiddle. However, there is an issue here with your totalPages calculation. attrs.$observe will return the raw value inside of the attribute, which is the string 'recordCount'. You want the $evaluated value instead. You can $evaluate it manually with scope.$eval...

attrs.$observe("recordCount", function(recCt) {
    console.log("OBSERVER: recCt", scope.$eval(recCt));
    scope.totalPages = calcPages(scope.$eval(recCt), scope.pageSize);
});

Although I would instead use scope.$watch...

scope.$watch("recordCount", function(recCt) {
    console.log("OBSERVER: recCt", recCt);
    scope.totalPages = calcPages(recCt, scope.pageSize);
});
Charlie Martin
  • 8,208
  • 3
  • 35
  • 41
  • Yep, I think I figured it out. The controller actually initializes `recordCount` to 0. That must be what `link` gets. By the time both the main view template and directive template display `recordCount`, it has been set by the expected means to 53. – nshew13 May 14 '14 at 13:51