Angularjs: выберите обновление без обновления ng-модели
Я создал следующий пример, чтобы вы могли точно видеть, что происходит: http://jsfiddle.net/8t2Ln/101/
То же самое происходит, если я использую ng-options. У меня есть другая причина для этого, но для упрощения примера эта часть вышла.
Как вы видите, по умолчанию у него есть два варианта. Я показываю выбранное значение ng-модели рядом с select, чтобы вы могли видеть, что это такое. Когда вы используете верхнюю часть для добавления третьей опции, она устанавливает значение в значение этой новой опции, о чем свидетельствует отображаемое значение ng-модели рядом с выбором, но сам выбор не изменяется, чтобы показать правильное значение выбран.
Ниже приведен пример кода по ссылке:
var testApp = angular.module('testApp', ['ngRoute']);
testApp.controller('Ctrl', function ($scope) {
$scope.newInput = '';
$scope.inputDevice = [
{
value: '1',
label: 'input1'
},
{
value: '2',
label: 'input2'
}
];
$scope.selectedDevice = '';
$scope.addType = function () {
var newElem = {
label: $scope.newInput,
value: '3'
};
$scope.inputDevice.push(newElem);
$scope.selectedDevice = newElem.value;
};
});
И вот html:
<div ng-app="testApp">
<div ng-controller="Ctrl">
<p>
<input type="text" ng-model="newInput" />
<br />
<button ng-click="addType()">Add Type</button>
</p>
<select ng-model="selectedDevice">
<option></option>
<option ng-repeat="i in inputDevice" value="{{ i.value }}">{{ i.label }} - {{ i.value }}</option>
</select>
{{ selectedDevice }}</div>
</div>
Ответы
Ответ 1
Именно поэтому вы не должны использовать ngRepeat
для выбора опций выбора. Вместо этого следует использовать ngOptions
:
<select ng-model="selectedDevice"
ng-options="i.value as (i.label + '-' + i.value) for i in inputDevice">
<option></option>
</select>
В общем, избегайте использования ngRepeat для выбора вариантов выбора. Есть по крайней мере две веские причины. ngRepeat
создает отдельную дочернюю область для каждой итерации, которая не нужна в случае тега опции. Еще одно важное предостережение заключается в том, что при ngRepeat
вы можете привязывать только select к примитивам, таким как строки, но вы не сможете записать объект в ngModel с ним.
Ниже приведена демонстрация.
angular.module('demo', []).controller('DemoController', function($scope) {
$scope.newInput = '';
$scope.inputDevice = [
{value: '1', label: 'input1'},
{value: '2', label: 'input2'}
];
$scope.selectedDevice = '';
$scope.addType = function() {
var newElem = {
label: $scope.newInput,
value: Number($scope.inputDevice[$scope.inputDevice.length - 1].value) + 1
};
$scope.inputDevice.push(newElem);
$scope.selectedDevice = newElem.value;
$scope.newInput = '';
};
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.min.js"></script>
<div ng-app="demo" ng-controller="DemoController">
<form ng-submit="addType()">
<input type="text" ng-model="newInput" />
<button type="submit">Add Type</button>
</form>
<select ng-model="selectedDevice" ng-options="i.value as (i.label + ' - ' + i.value) for i in inputDevice">
<option>Select</option>
</select>
{{ selectedDevice }}
</div>
Ответ 2
Проблема заключается в том, что, поскольку вы не используете ng-options
, браузер не закончил рендеринг в тот момент, когда вы устанавливаете новый selectedDevice
. Если вы используете ng-options
, вы можете использовать это обходное решение. Используйте $timeout
, чтобы обернуть ваш $scope.selectedDevice = newElem.value;
, чтобы убедиться, что он запускается после завершения браузером изменений с помощью ng-repeat
.
Я также добавил код для увеличения следующего значения для последовательных добавлений, потому что его жесткое кодирование до "3" означало, что третий параметр будет постоянно выбираться, даже когда добавлено больше.
var testApp = angular.module('testApp', ['ngRoute']);
testApp.controller('Ctrl', function($scope, $timeout) {
$scope.newInput = '';
$scope.inputDevice = [{
value: '1',
label: 'input1'
}, {
value: '2',
label: 'input2'
}];
$scope.selectedDevice = '';
$scope.addType = function() {
var last = Number($scope.inputDevice[$scope.inputDevice.length - 1].value) + 1;
var newElem = {
label: $scope.newInput,
value: last.toString()
};
$scope.inputDevice.push(newElem);
$timeout(function() {
$scope.selectedDevice = newElem.value;
}, 0);
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular-route.js"></script>
<div ng-app="testApp">
<div ng-controller="Ctrl">
<p>
<input type="text" ng-model="newInput" />
<br />
<button ng-click="addType()">Add Type</button>
</p>
<select ng-model="selectedDevice">
<option></option>
<option ng-repeat="i in inputDevice" value="{{ i.value }}" ng-selelected="{{ selectedDevice == i.value }}">{{ i.label }} - {{ i.value }}</option>
</select>
{{ selectedDevice }}
</div>
</div>
Ответ 3
У меня была аналогичная проблема, и причина в том, что мой ключ был числом, но при попытке установить другое значение я отправлял строку. Обходной путь в этом случае состоит в том, чтобы заставить установить значение модели того же типа, что и ключ.
например:
<select ng-model="model" ng-options="option.{{ key }} as option.{{ label }} for option in options">
<option value="">{{ emptyLabel }}</option>
</select>
if (scope.options.length > 0) {
scope.keyType = typeof(scope.options[0][scope.key]);
}
...
if (scope.keyType == 'number') {
scope.model = parseInt(newVal, 10);
} else {
scope.model = newVal;
}
Ответ 4
У меня была та же проблема. Для меня это решило преобразование числа в строку. Пример:
$scope.selectedDevice = "" + newElem.value;
Ответ 5
У меня была та же проблема, что и select, не обновляемый при обновлении ng-модели. Я извлекал значение для ng-модели из функции, которая извлекала объект из массива на основе пары ключей, значений.
При этом возвращаемый объект имел свойство hashkey $$hashKey: "object:115"
Проблема возникла, когда я создал копию объекта с помощью angular.copy, которая удалила это свойство hashkey и, следовательно, не будет выбрана.
После того, как я реорганизовал код, чтобы получить значение ng-model после angular.copy, проблема была решена.
ConstructorReviewers: function (oItem) {
this.PERSON_ID = oItem.PERSON_ID;
this.CHAIR_PERSON = oItem.CHAIR_PERSON;
/* // Commented this part and added it to EditItem function
this.oDepartment = CommonFactory.FindItemInArray(vm.oCommittee.arrDepartments, 'NAME', this.DEPARTMENT, 'item');
*/
this.EditItem = function () {
vm.EditItemOriginal = this;
angular.copy(this, vm.EditItem); // After this update the ng-model into vm.EditItem.oTitle object
vm.EditItem.oTitle = CommonFactory.FindItemInArray(vm.oCommittee.arrTitles, 'TITLE', vm.EditItem.TITLE, 'item');
vm.Popup.ShowPopup(true, 'new_edit', Constants.Mentoring.Popup.Edit);
}
}