Сложность с ng-моделью, ng-repeat и входами
Я пытаюсь разрешить пользователю редактировать список элементов с помощью ngRepeat
и ngModel
. (Посмотрите эту скрипту.) Однако оба подхода, которые я пробовал, приводят к странному поведению: один не обновляет модель, а другой размывает форма при каждом нажатии.
Я делаю что-то неправильно здесь? Это не поддерживаемый вариант использования?
Вот код из скрипки, скопированный для удобства:
<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
Это похоже на проблему с привязкой.
Совет не привязывается к примитивам.
Ваш 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/
Ответ 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>
Ответ 3
Вы попадаете в сложную ситуацию, когда необходимо понять, как области действия, ngRepeat и ngModel с NgModelController. Также попробуйте использовать версию 1.0.3. Ваш пример будет работать несколько иначе.
Вы можете просто использовать решение, предоставляемое jm -
Но если вы хотите глубже разобраться с ситуацией, вы должны понимать:
- как работает AngularJS;
Области
- имеют иерархическую структуру;
- ngRepeat создает новую область для каждого элемента;
- ngRepeat построить кеш элементов с дополнительной информацией (hashKey); на каждый вызов часов для каждого нового элемента (который не находится в кеше) ngRepeat создает новую область, элемент DOM и т.д. Более подробное описание.
- из 1.0.3 ngModelController входы rerenders с фактическими значениями модели.
Как ваш пример "привязка к каждому элементу напрямую" работает для AngularJS 1.0.3:
- вводите букву
'f'
на вход;
-
ngModelController
изменяет модель для области объекта (массив имен не изменяется) = > name == 'Samf'
, names == ['Sam', 'Harry', 'Sally']
;
Запустится цикл -
$digest
;
-
ngRepeat
заменяет значение модели из области приложения ('Samf'
) на значение из массива без изменений ('Sam'
);
-
ngModelController
введите rerenders с фактическим значением модели ('Sam'
).
Как работает ваш пример "Индексирование в массив":
- вводите букву
'f'
на вход;
-
ngModelController
изменяет элемент в именах array
= > `names == ['Samf', 'Harry', 'Sally'];
Запустится цикл - $digest;
-
ngRepeat
не может найти 'Samf'
в кеше;
-
ngRepeat
создает новую область, добавляет новый элемент div с новым вводом (поэтому поле ввода теряет фокус - старый div со старым входом заменяется новым div с новым вводом);
- отображаются новые значения для новых элементов DOM.
Кроме того, вы можете попытаться использовать AngularJS Batarang и посмотреть, как изменяется $id области действия div с введенным вами входом.
Ответ 4
Если вам не нужна модель для обновления с каждым нажатием клавиши, просто привяжите ее к name
, а затем обновите элемент массива при событии размытия:
<div ng-repeat="name in names">
Value: {{name}}
<input ng-model="name" ng-blur="names[$index] = name" />
</div>
Ответ 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">