javascript - 数组更改时不调用 AngularJs Formatter

标签 javascript arrays angularjs angular-ngmodel formatter

在我的示例代码中,我有两种我无法真正理解的行为,我希望你们能够启发我发生了什么以及我做错了什么:

  1. 我在指令数组到字符串中有一个格式化程序,它只是 在初始化过程中被调用。当我更新 我的 Controller 中的数组带有推送功能,格式化程序不是 被调用。这是为什么?我能做些什么来克服这个问题?
  2. 在数组到字符串的格式化函数中,我将数组的值提取到单个字符串中。转换后我返回该字符串。现在为什么 mydir 的 ng-model 没有被更改为数组到字符串的格式化程序返回的值?这对我来说毫无意义,因为 mydir 的格式化程序获取数组到字符串格式化程序的结果(我在 mydir 指令中滥用了格式化程序来显示我认为发生了什么错误)

angular.module("app", []);

angular.module("app").directive("arrayToString", function() {
  return {
    restrict: "A",
    require: "?ngModel",
    link: function(scope, element, attrs, ngModelCtrl) {
      ngModelCtrl.$formatters.push(function(array) {
        console.log("formatter called");
        var text = "";
        angular.forEach(array, function(e) {
          text += e.label + ", ";
        });
        text = text.substring(0, text.length - 2);
        console.log(text);
        return text;
      });
    }
  };
});

angular.module("app").directive("mydir", function() {
  return {
    restrict: "E",
    scope: {
      ngModel: "="
    },
    require: "?ngModel",
    link: function(scope, element, attrs, ngModelCtrl) {
      ngModelCtrl.$formatters.push(function(alreadyFormattedValue) {
        scope.myString = alreadyFormattedValue;
      });
    },
    template: "<div>{{myString}}</div><div>{{ngModel}}</div>"
  }
});

angular.module("app").controller("Controller", function() {
  var _this = this;
  
  _this.myValues = [
    { label: "apple" },
    { label: "lemon" },
    { label: "pear" }
  ];
  
  _this.add = function() {
    _this.myValues.push({ label: "strawberry" });
  }
});
<!DOCTYPE html>
<html>

  <head>
    <script src="https://code.angularjs.org/1.4.8/angular.js" data-semver="1.4.8" data-require="angular.js@1.3.20"></script>
    <link href="style.css" rel="stylesheet" />
    <script src="script.js"></script>
  </head>

  <body ng-app="app" ng-controller="Controller as ctrl">
    <mydir ng-model="ctrl.myValues" array-to-string=""></mydir>
    <button type="button" ng-click="ctrl.add()">Add</button>
  </body>

</html>

最佳答案

如果深入了解 ngModel 指令的源代码,我们可以发现对于 watch 使用 custom function 。在此函数中存在 if 和下一个条件。

if (modelValue !== ctrl.$modelValue &&
       // checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator
       (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue)
    )

因此,modelValue 只是与 !== 进行比较,如果引用未更改,则 viewValue 既不会应用格式化程序,也不会应用验证程序。

最简单的方法 - 只需更改引用,即使用,例如 concat函数 push .

_this.myValues = _this.myValues.concat({ label: "strawberry" });

示例

angular.module("app", []);

angular.module("app").directive("arrayToString", function() {
  return {
    restrict: "A",
    require: "?ngModel",
    link: function(scope, element, attrs, ngModelCtrl) {
      ngModelCtrl.$formatters.push(function(array) {
        console.log("formatter called");
        var text = "";
        angular.forEach(array, function(e) {
          text += e.label + ", ";
        });
        text = text.substring(0, text.length - 2);
        console.log(text);
        return text;
      });
    }
  };
});

angular.module("app").directive("mydir", function() {
  return {
    restrict: "E",
    scope: {
      ngModel: "="
    },
    require: "?ngModel",
    link: function(scope, element, attrs, ngModelCtrl) {
      ngModelCtrl.$formatters.push(function(alreadyFormattedValue) {
        scope.myString = alreadyFormattedValue;
      });
    },
    template: "<div>{{myString}}</div><div>{{ngModel}}</div>"
  }
});

angular.module("app").controller("Controller", function() {
  var _this = this;
  
  _this.myValues = [
    { label: "apple" },
    { label: "lemon" },
    { label: "pear" }
  ];
  
  _this.add = function() {
    _this.myValues = _this.myValues.concat({ label: "strawberry" });
  }
});
<!DOCTYPE html>
<html>

  <head>
    <script src="https://code.angularjs.org/1.4.8/angular.js" data-semver="1.4.8" data-require="angular.js@1.3.20"></script>
    <link href="style.css" rel="stylesheet" />
    <script src="script.js"></script>
  </head>

  <body ng-app="app" ng-controller="Controller as ctrl">
    <mydir ng-model="ctrl.myValues" array-to-string=""></mydir>
    <button type="button" ng-click="ctrl.add()">Add</button>
  </body>

</html>

下一个变体:您可以添加自己的$watch并手动应用格式化程序

scope.$watchCollection(function() {
    return ngModelCtrl.$modelValue;
}, function(n) {
    var formatters = ngModelCtrl.$formatters,
        idx = formatters.length;

    var viewValue = n;
    while (idx--) {
        viewValue = formatters[idx](viewValue);
    }
    ngModelCtrl.$setViewValue(viewValue);
});

示例:

angular.module("app", []);

angular.module("app").directive("arrayToString", function() {
  return {
    restrict: "A",
    require: "?ngModel",
    link: function(scope, element, attrs, ngModelCtrl) {
      scope.$watchCollection(function() {
        return ngModelCtrl.$modelValue;
      }, function(n) {
        var formatters = ngModelCtrl.$formatters,
          idx = formatters.length;

        var viewValue = n;
        while (idx--) {
          viewValue = formatters[idx](viewValue);
        }
        ngModelCtrl.$setViewValue(viewValue);
      });
      ngModelCtrl.$formatters.push(function(array) {
        console.log("formatter called");
        var text = "";
        angular.forEach(array, function(e) {
          text += e.label + ", ";
        });
        text = text.substring(0, text.length - 2);
        console.log(text);
        return text;
      });
    }
  };
});

angular.module("app").directive("mydir", function() {
  return {
    restrict: "E",
    scope: {
      ngModel: "="
    },
    require: "?ngModel",
    link: function(scope, element, attrs, ngModelCtrl) {
      ngModelCtrl.$formatters.push(function(alreadyFormattedValue) {
        scope.myString = alreadyFormattedValue;
      });
    },
    template: "<div>{{myString}}</div><div>{{ngModel}}</div>"
  }
});

angular.module("app").controller("Controller", function() {
  var _this = this;

  _this.myValues = [{
    label: "apple"
  }, {
    label: "lemon"
  }, {
    label: "pear"
  }];

  _this.add = function() {
    _this.myValues.push({
      label: "strawberry"
    });
  }
});
<!DOCTYPE html>
<html>

<head>
  <script src="https://code.angularjs.org/1.4.8/angular.js" data-semver="1.4.8" data-require="angular.js@1.3.20"></script>
  <link href="style.css" rel="stylesheet" />
  <script src="script.js"></script>
</head>

<body ng-app="app" ng-controller="Controller as ctrl">
  <mydir ng-model="ctrl.myValues" array-to-string=""></mydir>
  <button type="button" ng-click="ctrl.add()">Add</button>
</body>

</html>

关于javascript - 数组更改时不调用 AngularJs Formatter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34963002/

相关文章:

单击p元素时的javascript触发事件

javascript - 如何在更改选择列表中的选项时停止所有 YouTube 视频

javascript - ServiceNow:从数组动态创建表

css - 在angularjs中实现模态内的过渡效果

javascript - Stripe连接传输: Insufficient funds

javascript - 针对代码中的特定导航 div

java - 二维数组

c++ - 比较两个数组的困难

javascript - 带有 Angular JS 解析列表的选项列表

javascript - 字符串匹配 angularjs/javascript 最多 2 个字符