ng模型,ng重复和输入的难度


116

我正在尝试允许用户使用ngRepeat和编辑项目列表ngModel。(请参阅此小提琴。)但是,我尝试过的两种方法都导致了奇怪的行为:一种方法没有更新模型,另一种方法使每个keydown的表单模糊。

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

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

<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>


1
这与stackoverflow.com/questions/12977894/…非常相似,但是第二种方法在这里是新的,因此并不是完全相同。我在那里提供了详细的答案(类似于Artem的答案),解释了ng-repeat子作用域如何工作。
Mark Rajcok

由于在最终找到此线程之前花了合理的时间进行谷歌搜索,因此我可以将其重命名为:“父模型未从ngRepeat输入更新”或“模型未在使用ngRepeat时更新”或“ ngRepeat输入未绑定到(父)”模型”?也许您对标题有更好的主意?
vucalur

Answers:


120

这似乎是一个具有约束力的问题。

建议是不要绑定到基元

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/


3
感谢您使用第一个超链接,因为它解释了焦点/闪烁问题的模糊/丢失。我一直想知道为什么会这样。
Mark Rajcok

2
谢谢你的帮助。尽管如此,绑定到基元应该在那里...
Daniel Gruszczyk

1
旧帖子,但thnx,花了我一些时间来查找“在ngRepeat中不更改模型”问题,这是您的建议,不要绑定到基元
Stefanos Chrs 2014年

另外:键入时不要修改整个列表 -我掉进了陷阱。我正在观察集合中的更改,并用相同的副本替换它-因此,即使我没有绑定到基元,也正在重新创建元素。
z0r

71

使用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>

做这份工作;没有更多参考损失
Dan Ochiana

我确实搜索了这么长时间....是如此简单...只是那么隐蔽。将此作为答案!
安德里亚(Andrea)

哦,所以在ng-repeat中添加“ track by $ index”也可以解决“闪烁”问题
boi_echos

43

当需要了解scopesngRepeatngModel以及NgModelController的工作方式时,您将陷入困境。也请尝试使用1.0.3版本。您的示例将有所不同。

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

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

  • AngularJS的工作方式 ;
  • 范围具有层次结构;
  • ngRepeat为每个元素创建新范围;
  • ngRepeat建立带有附加信息的项目缓存(hashKey); 在每个监视项目的每个监视项目(不在缓存中)上,ngRepeat都会构造新的作用域,DOM元素等。更详细的描述
  • 从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=>`名称== ['Samf','Harry','Sally'];
  • $ digest循环开始;
  • ngRepeat'Samf'在缓存中找不到;
  • ngRepeat 创建新的作用域,使用新的输入添加新的div元素(这就是输入字段失去焦点的原因-具有旧输入的旧div被具有新输入的新div替换);
  • 呈现新DOM元素的新值。

另外,您可以尝试使用AngularJS Batarang来查看div范围的$ id如何随着您输入的输入而变化。


感谢1.0.3的解释。有趣的是,在1.0.3中,“直接绑定”情况下,输入字段似乎已损坏,这意味着它似乎不接受任何更改/键入的输入(至少在Chrome中是这样)。我敢肯定,在不久的将来,我们会看到很多这样的SO帖子:)我想这种新方法会更好,因为很明显出现了问题。
Mark Rajcok

6

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

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

为什么不使用ng-model="names[$index]"...我知道这是一个解决办法,但它工作;-)
Draško科基奇


2

问题似乎出在如何ng-model处理input和覆盖name对象的方式上,使它丢失了ng-repeat

解决方法是,可以使用以下代码:

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

希望能帮助到你


1

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

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>

-5

怎么做的:

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

在我的检查器元素中是:

<select ng-model="myModel1">
...
<select ng-model="myModel2">
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.