Почему AngularJS не может инициализировать опцию выбора (раскрывающийся список), когда ngmodel используется с вложенным объектом?

У меня есть сложный объект, который содержит несколько вложенных массивов объектов. Внутри одного из этих внутренних объектов находится значение, которое является идентификатором элемента в другом списке. Список представляет собой просто поиск кодов и описаний и выглядит следующим образом:

[
  { "id": 0, "value": "Basic"},
  { "id": 1, "value": "End of Month (EOM)"},
  { "id": 2, "value": "Fixed Date"},
  { "id": 3, "value": "Mixed"},
  { "id": 4, "value": "Extra"}
]

Однако я несу значение только во вложенном объекте. В списке Select Option (раскрывающийся список) будут отображаться все значения из предыдущего списка, чтобы пользователь мог сделать свой выбор.

Привязка через ng-модель

Затем я привязываю значение, возвращаемое из Select / Option, непосредственно к вложенному объекту. Таким образом, когда пользователь делает выбор, мой объект должен быть обновлен, чтобы я мог просто сохранить (опубликовать) весь объект обратно на сервер.

Инициализация - это проблема

Выбор действительно работает нормально, и я вижу, что все значения правильно обновляются в моем вложенном объекте, когда пользователь выбирает. Однако мне не удалось инициализировать пользовательский интерфейс (select / option) правильным значением, когда я получил (вложенный) объект с сервера.

Текст типа ввода был привязан правильно Моим следующим шагом было добавить текстовое поле в форму, привязать его к той же ng-модели и посмотреть, инициализировано ли оно. Это было так.

Это большой проект, над которым я работал, поэтому я создал plnkr.co и решил проблему. Вы можете увидеть мой plnkr в действии по адресу: http://plnkr.co/edit/vyySAmr6OhCbzNnXiq4a?p=preview

Мой плункер выглядит так:

образцы плунжера

Не инициализировано

Я воссоздал точный объект из моего проекта в образце 1, и, как вы можете видеть, выпадающий список не выбран должным образом при инициализации, так как значение (id) на самом деле равно 3, но в раскрывающемся списке не отображается выбранное значение.

Имейте в виду: они связаны, и выбор одного из них обновляет значения

Если вы попробуете плункер, вы увидите, что значения привязаны к списку выбора / опций, потому что даже в образцах, которые не инициализируются должным образом, когда вы выбираете элемент, другие связанные элементы мгновенно обновляются.

Получилось: взломайте!

Я работал с ним долгое время и постоянно создавал поддельные объекты, чтобы увидеть, какие из них работают, а какие нет. Это работает только после того, как я изменил объект значения на тот, который выглядит следующим образом:

$scope.x = {};
$scope.x.y = 3;

Теперь я могу привязать x.y (ng-model="x.y") к select / option, и он инициализирует список select / option, как и следовало ожидать. См. Образец 2 в плункере, и вы увидите, что "смешанный" (значение id 3) выбран, как и ожидалось.

Еще одна работа

Я также узнал, что следующее будет работать:

$scope.lastObj = {};
$scope.lastObj.inner = [];
$scope.lastObj.inner.push(3);

Больше вложенности

В этом случае я могу привязать lastObj.inner к списку select / option, и снова вы можете увидеть в примере 3, что он все еще работает. Это объект, который содержит массив, содержащий значение.

Минимальное вложение, которое не удается

Однако Образец 4 в плункере отображает окончательную степень вложенности, которая не работает с привязкой AngularJS.

$scope.thing = {};
$scope.thing.list=[];
$scope.thing.list.push({"item":"3"});

Это объект, который содержит массив, содержащий объект со значением. Он не может правильно привязаться к выбору / параметру, но не к текстовому полю.

Может ли кто-нибудь объяснить это, или это ошибка, или и то, и другое?

Может ли кто-нибудь объяснить, почему в этом случае не удается правильно привязать / инициализировать параметр select / option?

Последнее замечание

Также будьте сильны и не пытайтесь объяснять, почему вы думаете, что вложение моих объектов должно быть другим. Здесь это не обсуждается, если только вы не скажете мне, что сам JavaScript не поддерживает такое поведение.

Однако, если вы можете объяснить, что Angular не может справиться с такой глубиной вложенности и почему, то это совершенно верный ответ.

Спасибо за любой вклад.


person raddevus    schedule 01.05.2014    source источник


Ответы (2)


Вы напортачили с примитивными типами. Это означает, что вы должны вставить

$scope.vm.currentDocument.fieldSets[0].fields.push({"value":3});

вместо того

$scope.vm.currentDocument.fieldSets[0].fields.push({"value":"3"});

Обратите внимание на разницу {"value":3} и {"value":"3"}

Первый определяет объект со свойством «значение» с типом Integer, а второй определяет объект со свойством «значение» с типом String. Поскольку Angular проверяет соответствие типа, становится, что ("3" === 3) оценивается как false, поэтому angular не может найти выбранную опцию. Вот как это должно работать.

person Armen    schedule 01.05.2014
comment
Это абсолютно, до боли круто. Спасибо за помощь. Это невероятно смешно, что я этого не заметил, но в этом смысле это большая загадка. :) Спасибо, что прочитали и ответили. - person raddevus; 02.05.2014

Также обратите внимание, что, как указывает Армен, объекты передаются по ссылке, в отличие от примитивов, которые передаются по значению.

Из-за этого, обычно инициализируя поле выбора через ngModel из JSON (скажем, из записи $ resource) , вам нужно будет установить значение модели для определенного свойства элемента / объекта массива, которое внутренне проверяется на равенство < / strong> от Angular к элементам в ngOptions (или повторяющимся элементам параметров с ng-значениями, присвоенными одним и тем же объектам записи). Никакие два разных объекта в JS не считаются равными, даже если они имеют одинаковые имена / значения свойств.

У Angular есть один способ обойти это: используйте предложение track by в атрибуте ngOptions. Если у вас есть гарантированно уникальное значение (например, индекс записи из базы данных), Angular будет проверять значение свойства между значением модели и записями в ngOptions.

См. https://docs.angularjs.org/api/ng/directive/select для получения дополнительной информации.

person thynctank    schedule 18.11.2014
comment
Спасибо! Это сводило меня с ума. - person Nick Tiberi; 28.03.2017