AngularJS从自定义指令更新模型值

时间:2015-03-10 16:46:46

标签: angularjs angularjs-directive

我想用自定义指令更新带有属性值的模型值。 让我们想象我有4个数字。我想做以下事情:

  • 求和前两个数字(1 + 2)
  • 求和后两位数(3 + 4)
  • 求和两个总和(sum1 + sum2) - 级联总和

公式以custom指令的属性值表示。 我在Angular中没那么有经验并且有一些部分工作的解决方案,但我认为我的方向错误,所以我会在没有自定义指令的情况下发布代码。

以下是我试图构建自定义指令的代码,编写该指令(公式)的最佳方法是什么?

编辑:带有公式指令的输入字段将是只读的,它们只有一个目的 - 根据公式重新计算其他字段的值。



<!DOCTYPE html>
<html ng-app>

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

<body>
  <h1>Cascade sum example</h1>
  <input ng-model="A1" type="number">
  <input ng-model="A2" type="number">
  <input ng-model="A3" type="number">
  <input ng-model="A4" type="number">
  <input ng-model="A5" type="number" formula="A1+A2" readonly>
  <input ng-model="A6" type="number" formula="A3+A4" readonly>
  <input ng-model="A7" type="number" formula="A5+A6" readonly>
</body>

</html>
&#13;
&#13;
&#13;

2 个答案:

答案 0 :(得分:2)

我认为你不需要编写自己的指令来解决这样的问题。 Angular允许您评估html页面内的表达式。例如,您可以使用您的ng模型值来内联评估您的公式, <input ng-model="A5" type="number" value={{A1+A2}}> angular将取此并将其替换为A1 + A2的值。

编辑: 见https://jsfiddle.net/v4b37wzm/3/

答案 1 :(得分:2)

(解决方案的工作人员 - http://plnkr.co/edit/nhlI4fSsK58mWS18RgUh?p=preview

这是一个简单的模板来说明用法:

<h1>Cascade sum example</h1>
<ul>
  <li ng-repeat="(key, input) in inputs">
    <input type="number" ng-model="input.value"
      formula="::input.formulaFn"/>
    <span>{{::key}}</span>
    <span ng-if="::input.formula">({{input.formula}})</span>
  </li>
</ul>

首先,我们从数据库中获取输入,并为每个输入创建一个公式函数。调用时,公式函数会为给定的公式生成一个值:

Inputs.getAll()
  .then(function(inputs) {
    $scope.inputs = inputs

    _.each($scope.inputs, function(input) {
      if (input.formula) {
        input.formulaFn = parseFormula(input.formula)
      }
    })
  })

  function parseFormula(expr) {
      var parsed = $parse(expr)
      return function apply() {
          return parsed($scope.values)
      }
  }

肉是parseFormula。它使用angular的$ parse将表达式(例如'A1 + A2')转换为函数(plus(a,b))。如果您使用包含属性parsedA1的对象调用A2,则会生成其值的总和 - 这是apply()正在执行的操作。

我们当前的对象$scope.inputs不能用于为我们的解析表达式提供所需的值(它需要看起来像'A1': 1,而不是'A1': { ... })。不幸的是,我们不能使用相同的对象来保存我们的值和我们的ng模型,因为角度ng-repeat具有绑定和基元的特性(你可以在这里阅读更多关于它的信息 - https://github.com/angular/angular.js/wiki/Understanding-Scopes#ng-repeat - 这也被非正式地称为“点规则”)。这就是为什么我们需要$scope.inputs(提供我们的可绑定模型)和同步$scope.values,我们将用于表达式。

$scope.values = {}
$scope.$watch('inputs', function(value) {
  $scope.values = _.mapValues($scope.inputs, function(input) {
    return input.value
  })
}, true)

该指令相当简单。如果元素上有一个公式(这实际上是我们之前创建的公式 functions ),它将会观察它(这意味着每个摘要都会调用该函数)。一旦公式产生一个新值(例如'A1 + A2',A1或A2被更改),那么我们只需将ngModel与它同步。

.directive('formula', function() {
  return {
    scope: {
      formula: '=',
    },
    require: 'ngModel',
    link: function(scope, element, attrs, ngModelCtrl) {
      if (!scope.formula) return
      element.attr('readonly', true)
      scope.$watch(scope.formula, function(value) {
        ngModelCtrl.$setViewValue(value)
        ngModelCtrl.$render()
      })
    }
  }
})