Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angularjs/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Angularjs 如何实现自定义指令的ng更改_Angularjs_Angularjs Directive_Angularjs Ng Change - Fatal编程技术网

Angularjs 如何实现自定义指令的ng更改

Angularjs 如何实现自定义指令的ng更改,angularjs,angularjs-directive,angularjs-ng-change,Angularjs,Angularjs Directive,Angularjs Ng Change,我有一个指令,模板如下 <div> <div ng-repeat="item in items" ng-click="updateModel(item)"> <div> 我希望在单击某个项目并且foo的值已经更改时调用ng change 也就是说,如果我的指令按照以下方式实施: <my-directive items=items ng-model="foo" ng-change="bar(foo)"></my-directive&g

我有一个指令,模板如下

<div>
    <div ng-repeat="item in items" ng-click="updateModel(item)">
<div>
我希望在单击某个项目并且
foo
的值已经更改时调用
ng change

也就是说,如果我的指令按照以下方式实施:

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

我希望在更新
foo
的值时调用
bar

对于上面给出的代码,
ngChange
被成功调用,但调用时使用的是
foo
的旧值,而不是新的更新值

解决此问题的一种方法是在超时内调用
ngChange
,以便在将来某个时间点执行它,此时
foo
的值已经更改。但是这个解决方案让我对事情的执行顺序失去了控制,我认为应该有一个更优雅的解决方案

我也可以在父作用域中的
foo
上使用一个观察者,但是这个解决方案并没有真正提供一个要实现的
ngChange
方法,而且我被告知观察者是伟大的内存消费者

有没有一种方法可以使
ngChange
在没有超时或监视程序的情况下同步执行


示例:

这里的基本问题是,在
scope.updateModel
完成执行之后发生的摘要周期之前,基础模型不会得到更新。如果
ngChange
功能需要正在进行的更新的详细信息,则可以将这些详细信息明确提供给
ngChange
,而不是依赖先前应用的模型更新

这可以通过在调用
ngChange
时提供局部变量名到值的映射来实现。在此场景中,您可以将模型的新值映射到可在
ng change
表达式中引用的名称

例如:

scope.updateModel=函数(项)
{
scope.ngModel=项目;
ngChange({newValue:item});
}
在HTML中:

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


请参阅:

经过一些研究,似乎最好的方法是使用
$timeout(callback,0)

在执行回调后,它会自动启动一个
$digest
循环

因此,在我的例子中,解决方案是使用

$timeout(scope.ngChange, 0);
这样,回调的签名是什么并不重要,它将按照您在父范围中定义的方式执行


以下是带有此类更改的plunkr:

如果您需要
ngModel
,您只需在
ngModelController
上调用
$setViewValue
,即可隐式计算
ng change
。链接函数的第四个参数应该是ngModelCtrl。以下代码将使
ng change
适用于您的指令

link : function(scope, element, attrs, ngModelCtrl){
    scope.updateModel = function(item) {
        ngModelCtrl.$setViewValue(item);
    }
}
为了使您的解决方案能够工作,请将ngChange和ngModel从myDirective的隔离范围中删除

这里有一个提示:

tl;dr

根据我的经验,你只需要从中继承。使用方法
ngModelCtrl.$setViewValue

angular.module("myApp").directive("myDirective", function(){
  return {
    require:"^ngModel", // this is important, 
    scope:{
      ... // put the variables you need here but DO NOT have a variable named ngModel or ngChange 
    }, 
    link: function(scope, elt, attrs, ctrl){ // ctrl here is the ngModelCtrl
      scope.setValue = function(value){
        ctrl.$setViewValue(value); // this line will automatically eval your ng-change
      };
    }
  };
});
更准确地说

如果ngModel的对象引用已更改,则在ngModelCtrl.$commitViewValue()过程中评估
ng change
。如果未使用触发器参数或未对任何参数进行求值,则方法
$commitViewValue()
将由
$setViewValue(value,trigger)
自动调用

我指定如果
$viewValue
的引用发生更改,则
ng更改将自动触发。当您的
ngModel
字符串
int
时,您不必担心它。如果您的
ngModel
是一个对象,并且您只是更改了它的一些属性,那么
$setViewValue
将不会评估
ngChange

如果我们从这篇文章开始的代码示例

scope.setValue = function(value){
    ctrl.$setViewValue(value); // this line will automatically evalyour ng-change
};
scope.updateValue = function(prop1Value){
    var vv = ctrl.$viewValue;
    vv.prop1 = prop1Value;
    ctrl.$setViewValue(vv); // this line won't eval the ng-change expression
};

Samuli Ulmanen和lucienBertin的答案很好地说明了这一点,尽管AngularJS文档中的进一步阅读提供了关于如何处理这一问题的进一步建议(请参阅)

特别是在将对象传递给$setViewValue(myObj)的情况下。AngularJS文件说明:

当与标准输入一起使用时,视图值将始终是字符串(在某些情况下解析为另一种类型,例如输入[Date]的日期对象)。但是,自定义控件也可能将对象传递给此方法。在这种情况下,我们应该在将对象传递给$setViewValue之前复制该对象。这是因为ngModel不执行对象的深度监视,它只寻找身份的变化。如果只更改对象的属性,那么ngModel将不会意识到对象已更改,也不会调用$parser和$validators管道。因此,在将副本传递给$setViewValue后,不应更改副本的属性。否则,可能会导致范围上的模型值发生错误更改

对于我的特定情况,我的模型是一个时刻日期对象,因此我必须先克隆该对象,然后再调用setViewValue。我在这里很幸运,因为矩提供了一个简单的克隆方法:
var b=矩(a)


你能添加一个提琴或弹拨器吗?给你男:如果我执行一个作用域。$parent。$apply();值已更新,但现在抛出异常:真正的ng更改永远不应该知道参数是什么。对于这种特殊情况,您提出的是一种解决方案,但是如果我尝试使用带有两个或多个参数的回调条(a、b、c,…),会发生什么情况?在调用
scope.ngChange
时,应该指定指令想要公开的任何值,以便能够在
ng change
表达式中使用。例如:
scope.ngChange({newValue:item,
scope.setValue = function(value){
    ctrl.$setViewValue(value); // this line will automatically evalyour ng-change
};
scope.updateValue = function(prop1Value){
    var vv = ctrl.$viewValue;
    vv.prop1 = prop1Value;
    ctrl.$setViewValue(vv); // this line won't eval the ng-change expression
};
link : function(scope, elements, attrs, ctrl) {
    scope.updateModel = function (value) {
        if (ctrl.$viewValue == value) {
            var copyOfObject = moment(value);
            ctrl.$setViewValue(copyOfObject);
        }
        else
        {
            ctrl.$setViewValue(value);
        }
    };
}