【问题标题】:Difficulty with ng-model, ng-repeat, and inputsng-model、ng-repeat 和输入的难度
【发布时间】:2012-11-22 18:51:56
【问题描述】:

我试图允许用户使用ngRepeatngModel 编辑项目列表。 (See this fiddle.) 但是,我尝试过的两种方法都会导致奇怪的行为:一种不会更新模型,另一种会在每次按键时模糊表单。

我在这里做错了吗?这不是受支持的用例吗?

这是小提琴中的代码,为方便起见复制:

<html ng-app>
    <head>
        <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.2.1/css/bootstrap-combined.min.css" rel="stylesheet">
    </head>
    <body ng-init="names = ['Sam', 'Harry', 'Sally']">
        <h1>Fun with Fields and ngModel</h1>
        <p>names: {{names}}</p>
        <h3>Binding to each element directly:</h3>
        <div ng-repeat="name in names">
            Value: {{name}}
            <input ng-model="name">                         
        </div>
        <p class="muted">The binding does not appear to be working: the value in the model is not changed.</p>
        <h3>Indexing into the array:</h3>
        <div ng-repeat="name in names">
            Value: {{names[$index]}}
            <input ng-model="names[$index]">                         
        </div>
        <p class="muted">Type one character, and the input field loses focus. However, the binding appears to be working correctly.</p>
    </body>
</html>

【问题讨论】:

  • 这与stackoverflow.com/questions/12977894/… 非常相似,但是这里的第二种方法是新的,所以它并不完全是重复的。我在那里提供了一个详细的答案(类似于 Artem 的),解释了 ng-repeat 子作用域的工作原理。
  • 由于在最终找到此线程之前花费了我合理的谷歌搜索量,我可以将其重命名为:“未从 ngRepeat 输入更新父模型”或“使用 ngRepeat 时未更新模型”或“ ngRepeat 输入未绑定到(父)模型”?也许您对标题有更好的想法?

标签: angularjs angularjs-ng-repeat angularjs-ng-model


【解决方案1】:

这似乎是一个绑定问题。

建议是don't bind to primitives

您的ngRepeat 正在迭代集合内的字符串,而它应该迭代对象。解决您的问题

<body ng-init="models = [{name:'Sam'},{name:'Harry'},{name:'Sally'}]">
    <h1>Fun with Fields and ngModel</h1>
    <p>names: {{models}}</p>
    <h3>Binding to each element directly:</h3>
    <div ng-repeat="model in models">
        Value: {{model.name}}
        <input ng-model="model.name">                         
    </div>

jsfiddle:http://jsfiddle.net/jaimem/rnw3u/5/

【讨论】:

  • 感谢第一个超链接,因为它解释了模糊/失去焦点/闪烁问题。我一直想知道为什么会这样。
  • 谢谢你,帮了大忙。尽管如此,绑定到原语应该在那里...
  • 旧帖子,但是 thnx,我花了一些时间才发现“不更改 ngRepeat 中的模型”问题,建议不要绑定到原语
  • 另外:不要在打字时修改整个列表 - 我掉进了一个陷阱。我正在观察集合的变化,并用相同的副本替换它 - 所以即使我没有绑定到基元,元素也会被重新创建。
【解决方案2】:

使用 Angular 最新版本 (1.2.1) 并通过 $index 跟踪。此问题已修复

http://jsfiddle.net/rnw3u/53/

<div ng-repeat="(i, name) in names track by $index">
    Value: {{name}}
    <input ng-model="names[i]">                         
</div>

【讨论】:

  • 完成了这项工作;不再有参考损失
  • 我确实搜索了很久……太容易了……太隐蔽了。把这个作为答案!
  • oooooh,所以在 ng-repeat 中添加“track by $index”也可以解决“闪烁”问题
【解决方案3】:

当有必要了解 scopesngRepeatngModelNgModelController 的工作原理时,您会陷入困境。也尝试使用 1.0.3 版本。您的示例会有所不同。

您可以简单地使用jm提供的解决方案-

但如果你想更深入地处理这种情况,你必须了解:

  • how AngularJS works;
  • 范围具有层次结构;
  • ngRepeat 为每个元素创建新范围;
  • ngRepeat 使用附加信息 (hashKey) 构建项目缓存;在每次监视调用每个新项目(不在缓存中)时,ngRepeat 构造新范围、DOM 元素等。More detailed description
  • 从 1.0.3 开始,ngModelController 使用实际模型值重新呈现输入。

您的示例“直接绑定到每个元素”如何适用于 AngularJS 1.0.3:

  • 您在输入框中输入字母'f'
  • ngModelController 更改项目范围的模型(名称数组未更改)=> name == 'Samf', names == ['Sam', 'Harry', 'Sally'];
  • $digest 循环开始;
  • ngRepeat 将项目范围 ('Samf') 中的模型值替换为未更改名称数组 ('Sam') 中的值;
  • ngModelController 使用实际模型值 ('Sam') 重新呈现输入。

您的示例“索引到数组”的工作原理:

  • 您在输入框中输入字母'f'
  • ngModelController 更改名称中的项目array => `names == ['Samf', 'Harry', 'Sally'];
  • $digest 循环开始;
  • ngRepeat 在缓存中找不到 'Samf'
  • ngRepeat 创建新范围,使用新输入添加新 div 元素(这就是输入字段失去焦点的原因 - 具有旧输入的旧 div 被具有新输入的新 div 替换);
  • 呈现新 DOM 元素的新值。

另外,你可以尝试使用AngularJS Batarang,看看你输入的div的作用域的$id是如何变化的。

【讨论】:

  • 感谢 1.0.3 的解释。有趣的是,在 1.0.3 中,“直接绑定”的情况下,输入字段似乎被破坏了,因为它似乎不接受任何更改/键入的输入(至少在 Chrome 中)。我相信在不久的将来我们会看到很多关于此的 SO 帖子 :) 我认为这种新方法更好,因为它会更明显地表明某些地方是错误的。
【解决方案4】:

如果您不需要每次击键都更新模型,只需绑定到name,然后在模糊事件上更新数组项:

<div ng-repeat="name in names">
    Value: {{name}}
    <input ng-model="name" ng-blur="names[$index] = name" />
</div>

【讨论】:

  • 为什么不使用ng-model="names[$index]" ...我知道这是一种解决方法,但它有效;-)
【解决方案5】:

我刚刚将 AngularJs 更新到 1.1.2 并且没有问题。我想这个错误已经修复了。

http://ci.angularjs.org/job/angular.js-pete/57/artifact/build/angular.js

【讨论】:

    【解决方案6】:

    问题似乎在于ng-model 如何与input 一起工作并覆盖name 对象,使其丢失ng-repeat

    作为一种解决方法,可以使用以下代码:

    <div ng-repeat="name in names">
        Value: {{name}}
        <input ng-model="names[$index]">                         
    </div>
    

    希望对你有帮助

    【讨论】:

      【解决方案7】:

      我尝试了上面的解决方案来解决我的问题,它就像一个魅力。谢谢!

      http://jsfiddle.net/leighboone/wn9Ym/7/

      这是我的版本:

      var myApp = angular.module('myApp', []);
      function MyCtrl($scope) {
          $scope.models = [{
              name: 'Device1',
              checked: true
          }, {
              name: 'Device1',
              checked: true
          }, {
              name: 'Device1',
              checked: true
          }];
      
      }
      

      和我的 HTML

      <div ng-app="myApp">
          <div ng-controller="MyCtrl">
               <h1>Fun with Fields and ngModel</h1>
              <p>names: {{models}}</p>
              <table class="table table-striped">
                  <thead>
                      <tr>
                          <th></th>
                          <th>Feature 1</td>
                          <th>Feature 2</th>
                          <th>Feature 3</th>
                      </tr>
                  </thead>
                  <tbody>
                      <tr>
                          <td>Device</td>
                         <td ng-repeat="modelCheck in models" class=""> <span>
                                          {{modelCheck.checked}}
                                      </span>
      
                          </td>
                      </tr>
                      <tr>
                          <td>
                              <label class="control-label">Which devices?</label>
                          </td>
                          <td ng-repeat="model in models">{{model.name}}
                              <input type="checkbox" class="checkbox inline" ng-model="model.checked" />
                          </td>
                      </tr>
                  </tbody>
              </table>
          </div>
      </div>
      

      【讨论】:

        【解决方案8】:

        怎么做:

        <select ng-model="myModel($index+1)">
        

        在我的检查器元素中是:

        <select ng-model="myModel1">
        ...
        <select ng-model="myModel2">
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-08-13
          • 2017-11-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多