1

I have a controller with following code snippet,

...
$scope.selected_contents = [];
$scope.$watch('selected_contents', function (sel_contents) {
  console.log(sel_contents, 'selected contents');
}, true);
...

a directive,

commonDirectives.directive('chkbox', function() {
  return {
    restrict: 'A',
    require: '?ngModel',
    scope : {
        item : '=item',
        selection_pool: '=selectionPool'
    },
    link: function(scope, elem, attrs, ngModel) {
      console.log('selected contents are', scope.selection_pool);
      // watch selection_pool
      scope.$watch('selection_pool', function (pool) {
        console.log(pool, scope.selection_pool, 'pool updated');
        if (_.contains(pool, scope.item)) {
          elem.prop('checked', true);
        }
        else {
          elem.prop('checked', false);
        }
      });
      // toggle the selection of this component
      var toggle_selection = function () {
        if(_.indexOf(scope.selection_pool, scope.item) != -1) {
          scope.selection_pool = _.without(scope.selection_pool , scope.item);
        }
        else {
          scope.selection_pool.push(scope.item);
        }
      };
      elem.on('click', toggle_selection);
    }
  };
});

and a template which uses the directive,

<tr ng-repeat="content in contents">
      <td><input type="checkbox" selection_pool="selected_contents" item="content" chkbox></td>
</tr>

The problem is, changes in selection_pool in the directive is not reflected to selected_contents in the controller. What am i missing?

Update 1:

Following the suggestion from @mohamedrias I wrapped the changes in scope with scope.$apply. Doing so updates selected_contents in controller only while adding the content but not while removing it.

  ...
  // toggle the selection of this component
  var toggle_selection = function () {
    if(_.indexOf(scope.selection_pool, scope.item) != -1) {
      scope.$apply(function () {
        scope.selection_pool = _.without(scope.selection_pool , scope.item);
      });
    }
    else {
      scope.$apply(function () {
        scope.selection_pool.push(scope.item);
      });
    }
  };
  ...
2
  • You must use scope.$apply() inside the click handler in directive Commented Apr 9, 2015 at 9:27
  • @mohamedrias could you explain it lil more? I wish to know why it is required. Commented Apr 9, 2015 at 9:28

2 Answers 2

2

Angular uses name-with-dashes for attribute names and camelCase for the corresponding directive name

From here.

The variable should be changed from this selection_pool:

<input type="checkbox" selection_pool="selected_contents" item="content" chkbox>

to selection-pool:

<input type="checkbox" selection-pool="selected_contents" item="content" chkbox>

And this selectionPool into the directive:

scope : {
    item : '=item',
    selectionPool: '=selectionPool'
}

EDIT: Because the selectionPool is an array, you should use $watchCollection:

scope.$watchCollection('selectionPool', function (pool) 

And when you add/remove values from the array in toggle_selection function, should be wrapped within the $timeout function:

$timeout(function () {
            if (_.indexOf(scope.selectionPool, scope.item) != -1) {
                scope.selectionPool = _.without(scope.selectionPool, scope.item);
             } else {
                 scope.selectionPool.push(scope.item);
             }
});

This is to assure that a digest cycle is going to be applied afterwards.

Here's the code working on a jsfiddle: http://jsfiddle.net/0rvcguz0/3/

Sign up to request clarification or add additional context in comments.

3 Comments

sorry still the same problem, the removal of content is still not reflected in the controller's selected_contents.
Sorry I understood something different , now I think I answered the question
$scope.$watchCollection did it for me. I was testing the behavior with $scope.$watch and it did not reflect the changes on the object
0

After researching for entire day, I ended up here. If someone is having any trouble with Angularjs scope, I highly encourage to read it.

The proper solution in my case was to wrap selected_contents by an object. e.g.

$scope.selected = {};
$scope.selected.contents = [];

Then in the template replace selcted_contents with selected.contents.

But still what I don't understand is, [] or an Array is also an object. My earlier code should have worked according to the information I found in the wiki. If anyone could explain me why I would really appreciate it :).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.