以编程方式在Angular.js中设置模型值

时间:2021-08-07 12:28:27

I'm an author of angular-input-modified directive.

我是angular- in- modified directive的作者。

This directive is used to track model's value and allows to check whether the value was modified and also provides reset() function to change value back to the initial state.

此指令用于跟踪模型的值,并允许检查值是否被修改,并提供reset()函数将值更改为初始状态。

Right now, model's initial value is stored in the ngModelController.masterValue property and ngModelController.reset() function is provided. Please see the implementation.

现在,模型的初始值存储在ngModelController中。提供了masterValue属性和ngModelController.reset()函数。请参考实现。

I'm using the following statement: eval('$scope.' + modelPath + ' = modelCtrl.masterValue;'); in order to revert value back to it's initial state. modelPath here is actually a value of ng-model attribute. This was developed a way back and I don't like this approach, cause ng-model value can be a complex one and also nested scopes will break this functionality.

我使用了以下语句:eval('$scope)。' + modelPath + ' = modelCtrl.masterValue;');为了将值恢复到初始状态。这里的modelPath实际上是一个ng模型属性的值。这是一种开发方法,我不喜欢这种方法,因为ng-model值可能很复杂,而且嵌套作用域也会破坏这种功能。

What is the best way to refactor this statement? How do I update model's value directly through the ngModel controller's interface?

重构这个命题的最佳方法是什么?如何通过ngModel控制器的接口直接更新模型的值?

2 个解决方案

#1


2  

The best solution I've found so far is to use the $parse service in order to parse the Angular's expression in the ng-model attribute and retrieve the setter function for it. Then we can change the model's value by calling this setter function with a new value.

到目前为止,我发现的最佳解决方案是使用$parse服务来解析ng-model属性中的角的表达式,并为其检索setter函数。然后我们可以用一个新的值调用这个setter函数来更改模型的值。

Example:

function reset () {
  var modelValueSetter = $parse(attrs.ngModel).assign;
  modelValueSetter($scope, 'Some new value');
}

This works much more reliably than eval().

这比eval()更可靠。


If you have a better idea please provide another answer or just comment this one. Thank you!

如果您有更好的想法,请提供另一个答案或只是评论这个。谢谢你!

#2


0  

[previous answer]

(之前的回答)

I had trouble with this issue today, and I solved it by triggering and sort of hijacking the $parsers pipeline using a closure.

我今天遇到了这个问题,我通过使用闭包触发并劫持了$parsers管道来解决这个问题。

const hijack = {trigger: false; model: null};
modelCtrl.$parsers.push( val => {
   if (hijack.trigger){
        hijack.trigger = false;
        return hijack.model;
   }
   else { 
      // .. do something else ...
   })

Then for resetting the model you need to trigger the pipeline by changing the $viewValue with modelCtrl.$setViewValue('newViewValue').

然后,为了重新设置模型,您需要使用modelCtrl.$setViewValue('newViewValue')更改$viewValue来触发管道。

const $setModelValue = function(model){
    // trigger the hijack and pass along your new model
    hijack.trigger = true;
    hijack.model = model; 
    // assuming you have some logic in getViewValue to output a viewValue string
    modelCtrl.$setViewValue( getViewValue(model) ); 
    }

By using $setViewValue(), you will trigger the $parsers pipeline. The function I wrote in the first code block will then be executed with val = getViewValue(model), at which point it would try to parse it into something to use for your $modelValue according the logic in there. But at this point, the variable in the closure hijacks the parser and uses it to completely overwrite the current $modelValue.

通过使用$setViewValue(),您将触发$parsers管道。然后,我在第一个代码块中编写的函数将使用val = getViewValue(model)执行,这时它将尝试根据其中的逻辑将其解析为用于$modelValue的内容。但是此时,闭包中的变量会劫持解析器并使用它来完全覆盖当前的$modelValue。

At this point, val is not used in the $parser, but it will still be the actual value that is displayed in the DOM, so pick a nice one.

此时,在$解析器中不使用val,但它仍然是在DOM中显示的实际值,因此选择一个合适的值。

Let me know if this approach works for you.

如果这个方法对你有效,请告诉我。

[edit]

(编辑)

It seems that ngModel.$commitViewValue should trigger the $parsers pipeline as well, I tried quickly but couldn't get it to work.

看来ngModel。$commitViewValue也应该触发$parsers管道,我快速地尝试了一下,但是不能让它工作。

#1


2  

The best solution I've found so far is to use the $parse service in order to parse the Angular's expression in the ng-model attribute and retrieve the setter function for it. Then we can change the model's value by calling this setter function with a new value.

到目前为止,我发现的最佳解决方案是使用$parse服务来解析ng-model属性中的角的表达式,并为其检索setter函数。然后我们可以用一个新的值调用这个setter函数来更改模型的值。

Example:

function reset () {
  var modelValueSetter = $parse(attrs.ngModel).assign;
  modelValueSetter($scope, 'Some new value');
}

This works much more reliably than eval().

这比eval()更可靠。


If you have a better idea please provide another answer or just comment this one. Thank you!

如果您有更好的想法,请提供另一个答案或只是评论这个。谢谢你!

#2


0  

[previous answer]

(之前的回答)

I had trouble with this issue today, and I solved it by triggering and sort of hijacking the $parsers pipeline using a closure.

我今天遇到了这个问题,我通过使用闭包触发并劫持了$parsers管道来解决这个问题。

const hijack = {trigger: false; model: null};
modelCtrl.$parsers.push( val => {
   if (hijack.trigger){
        hijack.trigger = false;
        return hijack.model;
   }
   else { 
      // .. do something else ...
   })

Then for resetting the model you need to trigger the pipeline by changing the $viewValue with modelCtrl.$setViewValue('newViewValue').

然后,为了重新设置模型,您需要使用modelCtrl.$setViewValue('newViewValue')更改$viewValue来触发管道。

const $setModelValue = function(model){
    // trigger the hijack and pass along your new model
    hijack.trigger = true;
    hijack.model = model; 
    // assuming you have some logic in getViewValue to output a viewValue string
    modelCtrl.$setViewValue( getViewValue(model) ); 
    }

By using $setViewValue(), you will trigger the $parsers pipeline. The function I wrote in the first code block will then be executed with val = getViewValue(model), at which point it would try to parse it into something to use for your $modelValue according the logic in there. But at this point, the variable in the closure hijacks the parser and uses it to completely overwrite the current $modelValue.

通过使用$setViewValue(),您将触发$parsers管道。然后,我在第一个代码块中编写的函数将使用val = getViewValue(model)执行,这时它将尝试根据其中的逻辑将其解析为用于$modelValue的内容。但是此时,闭包中的变量会劫持解析器并使用它来完全覆盖当前的$modelValue。

At this point, val is not used in the $parser, but it will still be the actual value that is displayed in the DOM, so pick a nice one.

此时,在$解析器中不使用val,但它仍然是在DOM中显示的实际值,因此选择一个合适的值。

Let me know if this approach works for you.

如果这个方法对你有效,请告诉我。

[edit]

(编辑)

It seems that ngModel.$commitViewValue should trigger the $parsers pipeline as well, I tried quickly but couldn't get it to work.

看来ngModel。$commitViewValue也应该触发$parsers管道,我快速地尝试了一下,但是不能让它工作。