Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
747 views
in Technique[技术] by (71.8m points)

angularjs - How to implement an ng-change for a custom directive

I have a directive with a template like

<div>
    <div ng-repeat="item in items" ng-click="updateModel(item)">
<div>

My directive is declared as:

return {
    templateUrl: '...',
    restrict: 'E',
    require: '^ngModel',
    scope: {
        items: '=',
        ngModel: '=',
        ngChange: '&'
    },
    link: function postLink(scope, element, attrs) 
    {
        scope.updateModel = function(item)
        {
             scope.ngModel = item;
             scope.ngChange();
        }
    }
}

I would like to have ng-change called when an item is clicked and the value of foo has been changed already.

That is, if my directive is implemented as:

<my-directive items=items ng-model="foo" ng-change="bar(foo)"></my-directive>

I would expect to call bar when the value of foo has been updated.

With code given above, ngChange is successfully called, but it is called with the old value of foo instead of the new updated value.

One way to solve the problem is to call ngChange inside a timeout to execute it at some point in the future, when the value of foo has been already changed. But this solution make me loose control over the order in which things are supposed to be executed and I assume that there should be a more elegant solution.

I could also use a watcher over foo in the parent scope, but this solution doesn't really give an ngChange method to be implmented and I have been told that watchers are great memory consumers.

Is there a way to make ngChange be executed synchronously without a timeout or a watcher?

Example: http://plnkr.co/edit/8H6QDO8OYiOyOx8efhyJ?p=preview

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If you require ngModel you can just call $setViewValue on the ngModelController, which implicitly evaluates ng-change. The fourth parameter to the linking function should be the ngModelCtrl. The following code will make ng-change work for your directive.

link : function(scope, element, attrs, ngModelCtrl){
    scope.updateModel = function(item) {
        ngModelCtrl.$setViewValue(item);
    }
}

In order for your solution to work, please remove ngChange and ngModel from isolate scope of myDirective.

Here's a plunk: http://plnkr.co/edit/UefUzOo88MwOMkpgeX07?p=preview


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...