【问题标题】:What is the angularjs way to databind many inputs?angularjs 数据绑定许多输入的方法是什么?
【发布时间】:2012-10-19 15:49:19
【问题描述】:

我正在学习 angularjs,我希望能够让用户输入许多输入。当输入这些输入时,list 数组元素应相应更改。我想尝试使用 ngRepeat 指令,但我读到了,因为它创建了一个新范围,我无法进行数据绑定:

<div ng-repeat="item in list">
    <label>Input {{$index+1}}:</label>
    <input ng-model="item" type="text"/>
</div>

我想知道是否应该使用自定义指令来执行此操作或以不同的方式处理它。

【问题讨论】:

  • 如果一个输入框可以工作,每个项目都由一些分隔符分隔,请参阅 ngList。 docs.angularjs.org/api/ng.directive:ngList
  • 虽然它对我目前正在开发的东西并不直观,但很高兴知道 Angular 有这个功能作为我将来可能使用的指令。谢谢!

标签: javascript angularjs


【解决方案1】:

数据绑定到原始“项目”不起作用的原因是 ng-repeat 为每个项目创建子范围的方式。对于每个项目,ng-repeat 都有新的子范围原型继承自父范围(见下图中的虚线),然后它将项目的值分配给子范围上的新属性(下图中的红色项目)。新属性的名称是循环变量的名称。来自ng-repeat source code

childScope = scope.$new();
...
childScope[valueIdent] = value;

如果 item 是原语,则新的子范围属性本质上被分配了原语值的副本。此子范围属性对父范围不可见,您对输入字段所做的更改存储在此子范围属性中。例如,假设我们在父范围内

$scope.list = [ 'value 1', 'value 2', 'value 3' ];

在 HTML 中:

<div ng-repeat="item in list">

然后,第一个子作用域将具有以下 item 属性和原始值 (value 1):

item: "value 1"

由于 ng-model 数据绑定,您对表单输入字段所做的更改存储在该子范围属性中。

您可以通过将子范围记录到控制台来验证这一点。在 ng-repeat 中添加到您的 HTML:

<a ng-click="showScope($event)">show scope</a>

添加到您的控制器:

$scope.showScope = function(e) {
    console.log(angular.element(e.srcElement).scope());
}


使用@Gloopy 的方法,每个子作用域仍然获得一个新的“item”属性,但是因为 list 现在是一个对象数组,childScope[valueIdent] = value; 导致 item 属性的值被设置为对数组对象之一的引用(而不是复制)。

使用 showScope() 技术,您将看到子作用域 item 属性的值引用了数组对象之一——它不再是原始值。

另请参阅don't bind to primitives in ng-repeat child scopes
What are the nuances of scope prototypal / prototypical inheritance in AngularJS?(其中包含使用 ng-repeat 时作用域的图片)。

【讨论】:

  • 嘿伙计,你用什么软件来渲染上面的图表?
  • @abbood, graphviz.
【解决方案2】:

如果您的 list 是一个对象数组(而不是一个基元数组),那么您的运气会更好。即使使用ng-repeat 创建了一个新范围,这也能正常工作:

<div ng-repeat="item in list">
    <label>Input {{$index+1}}:</label>
    <input ng-model="item.value" type="text"/>
</div>

使用以下控制器:

function TestController($scope) {
    $scope.list = [ { value: 'value 1' }, { value: 'value 2' }, { value: 'value 3' } ];
}​

this fiddle 为例。

另一方面,如果您尝试绑定到字符串数组,则新范围将导致问题,因为您正在修改的值不会绑定到原始数​​组字符串原语(如this fiddle 示例)。

【讨论】:

    【解决方案3】:

    我发现了一种有趣的方法,它允许我处理一组原语。

    我正在使用 AngularJS 1.2.1,这是我可以使用的唯一版本。

    HTML:

    <div ng-repeat="item in list">
        <label>Input {{$index+1}}:</label>
        <input ng-model="item" type="text" ng-blur="editItem($index, item)"/>
    </div>
    

    JavaScript:

    $scope.editItem = function(idx, eItem) {
        $scope.list[idx] = eItem;
    };
    

    链接: http://jsfiddle.net/bxD2P/10/(感谢 Gloopy 提供的初学者 Fiddle)

    我确信有一些简单的方法可以在它的工作原理上找到漏洞,我很想听听他们的意见。它可以让我支持我的代码。

    【讨论】:

      【解决方案4】:

      这是一种方法。我使用了 textareas 和与我的转发器不同的结构,但主要概念是:

      • 根据索引显示一个简单的值。 (未绑定)
      • 关于模糊更新模型
      • 关于模型更新重新渲染

      本质上是伪造绑定。

      工作小提琴 - http://jsfiddle.net/VvnWY/4/

      html:

        <script type="text/ng-template" id="textareas.html">
          <textarea ng-if="strings" ng-repeat="str in strings" ng-blur="blur( $event, $index )">{{strings[$index]}}</textarea>
        </script>
      
      <div ng-controller="MyCtrl">
          Here's a few strings: <br />
          <div ng-repeat="str in strings">{{strings[$index]}}</div>
      
          Here's the strings as editable (twice so that you can see the updates from a model change): <br />
          <form-textareas strings="strings"></form-textareas>
          <form-textareas strings="strings"></form-textareas>
      
      </div>
      

      JS:

      var myApp = angular.module('myApp',[]);
      angular.module('myApp', [])
        .controller('MyCtrl', ['$scope', function($scope) {
          $scope.strings = [ "foo", "bar", "cow" ];
         }])
        .directive('formTextareas', function() {
          return {
              restrict: "E",
              scope: {
                  strings: '='
              },
              templateUrl: "textareas.html",
              link: function( $scope ){
                  $scope.blur = function( $event, $index ){
                      $scope.strings[ $index ] = $event.currentTarget.value;
                  };
              }
          };
        })
      ;
      

      【讨论】:

        【解决方案5】:

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-07-03
          • 1970-01-01
          • 2010-09-06
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多