Manually trigger Angular data binding for an input

2019-06-16 04:00发布

I'm writing some tests for an Angular directive and I need to simulate user input into an input field. I tried to do this:

element.find('input').val('some value').trigger('input');

but it didn't work. Triggering change didn't work either. I know I can access the element scope directly with element.scope() and change it, but it seems more natural to change the input's value and let Angular do the data binding.

For what it's worth, I've checked out input(name).enter(value) from Angular ngScenario, and it seems to do the same as I did:

...
input.val(value);
input.trigger(event || (supportInputEvent ? 'input' : 'change'));
...

What am I missing? Is there a better way to test user input in this case?

(I made a jsFiddler script to illustrate the question)

UPDATE

I think some clarification is needed. I'm not trying to change the DOM nor the scope outside Angular realm per se. I have a directive that renders an input box bound to a property of the directive's scope. I'm writing automated tests to ensure the directive does what it's supposed to do, and what one test should do is to simulate some input so that the directive scope gets updated and I can assert that some behavior is performed on that input. As I mentioned earlier, I can change the directive's scope from the test code by using element.scope(), but I'd rather change the input's value and let Angular do its thing.

2条回答
唯我独甜
2楼-- · 2019-06-16 04:31

This is not right approach to do this in angular. You should do like this.

Working DEMO

Create function inside the $scope and change your variable value so that angular itself will update your input field as well as at all places where you have used(bind) this variable.

Angular Function

$scope.changeInput = function() {
    $scope.value="barfoo";
}
查看更多
时光不老,我们不散
3楼-- · 2019-06-16 04:42

After spending some more time researching and testing, I've figured out what was wrong: jqLite registers event handlers using addEventHandler and they don't get triggered by jQuery trigger function. My jsFiddle script wasn't working because Angular's script was being loaded before jQuery's (and therefore was using jqLite). I updated the script to load everything in the correct order so that Angular uses jQuery on function to register event handlers, and now it simulates changes on the input box and tells Angular to do the data binding.

My test code wasn't working for the very same reason. I fixed it by changing the scripts order as well. If I didn't happen to be using jQuery, I would have to trigger the event by calling dispatchEvent instead of trigger.

查看更多
登录 后发表回答