9

My situation is as follows:

directive

scope: { foo:'=' },
template: '<input type="checkbox" ng-model="foo"/>'

parent controller

$scope.foo = false;

jasmine test

var cb = iElement.find('input');

$timeout(function() {  // using $timeout to ensure $digest() isn't the issue.
    cb.prop('checked',!cb.prop('checked'))
},0);

expect(cb.prop('checked')).toBe(true); // passes

expect($scope.foo).toBe(true); // doesn't pass

My question: why doesn't $scope.foo get updated when I issue the prop('checked') even though the DOM does (as I've verified after inspecting it).

Here is a jsbin that roughly demonstrates the problem http://jsbin.com/kapifezi/2/edit

1
  • 1
    Asked a different way - what is the correct way to test a checkbox (that lives in a directive) who's ng-model is linked to a variable in its parent controller? Commented Apr 2, 2014 at 19:51

4 Answers 4

9

So the complete answer would be: You need to change 'checked' property, and then trigger click event.

var input = element.find('input');
input.prop('checked',!input.prop('checked'));
// input.triggerHandler('click');
input.triggerHandler('change');

Thanks Kevin, that helped me a lot!

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

Comments

4

After further investigation - it looks like angular will add a click listener when you add an ng-model to something like a checkbox.

So it would seem that the correct method of testing this would be to issue a click event on the DOM object from within the jasmine test.

2 Comments

Actually - I recently ran into an issue (possibly related to using click here) where Firefox fails to pickup the click event (or perhaps the change didn't enact a $digest loop - regardless of my explicit call to $digest() directly after the click -- although tests pass in both Chrome and PhantomJS. Not sure what's going on...
Thanks @Kevin your comments saved my day In my test el.prop('checked', true) did not work but once changed to el.click() the model was correctly updated
0

try

expect($scope.$parent.foo).toBe(true);

updating answer:

$timeout(function() {  // using $timeout to ensure $digest() isn't the issue.
      //cb.prop('checked',!cb.prop('checked'));  
      $scope.val = !cb.prop('checked');

},0);

you want to keep all updates on the scope level and let angular manage the cycles by itself. if updated the property you're off angular's radar.

5 Comments

I'm guessing you mean $scope.$parent. In any case, foo does not exist there. If I understand correctly, in order to access the isolated scope created by the directive, I need to use the scope that is returned by, for example: ele = angular.element('<directive></directive>'); $compile(ele)($rootScope) isolated_scope = ele.scope();
sorry about the typo. fixed the answer. the new input in the template has its own scope. you pass the value, but should be able to access the parent value.
Maybe my question is unclear - in this jsbin example: link why doesn't my scope variable $scope.val get updated?
if i got it right, you want by clicking the button to update both checkbox and labels. to do that, replace the line 'cb.prop('checked',!cb.prop('checked'));' with '$scope.val = !cb.prop('checked');' - works on my end.
Ya you're right - that does work - but not in the way that I need/want it to. If you notice, $scope.val is tied to the ng-model of the checkbox directive, so in my mind, it would make sense that if the checkbox were to change from checked to unchecked, ng-model should pick up on this change. Or maybe my understanding of how MVC is interacting is skewed. In either case, I suppose I can do something as you suggested above for now. Thanks.
0

@egoproxy answer helped me in the end, but I had issues with using a raw dom element. To get around this I used angular.element(domElement) which: wraps a raw DOM element or HTML string as a jQuery element.

var checkbox = angular.element(checkboxElement));

// Click to check it, then Change to propate to ngModel 
checkbox.trigger('click');
checkbox.trigger('change');

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.