Ошибка связывания с Dropdown

У меня возникает проблема при привязке моего значения выпадающего списка с ассоциативным массивом.

Проблема связана с треком, так что, когда я не добавляю трек к моему выпадающему списку, тогда у меня есть привязка к раскрывающемуся списку, и когда я добавляю трек, тогда O не удается автоматически выбрать значение выпадающего списка.

Я хочу использовать track by с ng-options, чтобы angular js не добавлял $$ hashKey и эффективность производительности, связанная с отслеживанием.

Я не понимаю, почему это происходит.

Примечание. Я хочу привязать название вариантов как Пицца или гамбургер для каждого из моих $scope.items, а не для всего объекта.

Обновление: Как я понимаю и с такой большой попыткой с текущей структурой данных моих $scope.items он не работает с ng-options, и я хочу использовать ng-options с треком на избегать генерации хеш-ключа angular js. Я также попробовал ng-change, как предложил @MarcinMalinowski, но я получаю ключ как undefined.

Итак, какова должна быть моя структура данных $scope.items, так что, когда мне нужно получить доступ к любому элементу из моих $scope.items? Я могу получить к нему доступ, не делая цикл (например, мы обращаемся к элементам из ассоциативного массива), например, как теперь я могу получить правильную структуру данных и использовать ngoptions только с отслеживанием.

var app = angular.module("myApp", []);
app.controller("MyController", function($scope) {
  $scope.items = [
  {
    "title": "1",
    "myChoice" :"",
      "choices": {
        "pizza": {
          "type": 1,
          "arg": "abc",
          "$$hashKey": "object:417"
        },
        "burger": {
          "type": 1,
          "arg": "pqr",
          "$$hashKey": "object:418"
        }
      }
   },
   {
    "title": "2",
     "myChoice" :"",
      "choices": {
        "pizza": {
          "type": 1,
          "arg": "abc",
          "$$hashKey": "object:417"
        },
        "burger": {
          "type": 1,
          "arg": "pqr",
          "$$hashKey": "object:418"
        }
      }
   }
  ];
   
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<ul ng-app="myApp" ng-controller="MyController">
   <div ng-repeat="data in items">
       <div>{{data.title}}
       </div>
     <select ng-model="data.myChoice" 
     ng-options="key as key for (key , value) in data.choices track by $index"><option value="">Select Connection</option></select>
   </div>
   
   </ul>

Ответы

Ответ 1

Проблемы в вашем коде:

1) track by $index не поддерживается ngOptions, это приведет к тому, что значение option будет undefined (в вашем случае это будет $index of ngRepeat);

2) track by не работает с объектными данными-источниками (предполагается, что они используются с источниками данных массива), из документов:

trackexpr: используется при работе с массивом объектов. Результат это выражение будет использоваться для идентификации объектов в массиве.

Конечно, вы можете использовать ngRepeat для генерации элементов option, но лично я бы предпочел использовать ngOptions без track by из-за преимуществ, которые он имеет над ngRepeat.

UPDATE: Вот код, который иллюстрирует, как вы можете изменить исходный источник данных и использовать track by, чтобы предварительно выбрать параметр, если модель является объектом. Но даже в первом примере console.log() показывает, что $$hashKey не был добавлен в объект choices.

var app = angular.module("myApp", []);
app.controller("MyController", ['$scope', '$timeout', function($scope, $timeout) {
  $scope.items = [
  {
    "title": "1",
    "myChoice" :"burger",
      "choices": {
        "pizza": {
          "type": 1,
          "arg": "abc"
        },
        "burger": {
          "type": 1,
          "arg": "pqr"
        }
      }
   },
   {
    "title": "2",
     "myChoice" :"",
      "choices": {
        "pizza": {
          "type": 1,
          "arg": "abc"
        },
        "burger": {
          "type": 1,
          "arg": "pqr"
        }
      }
   }
  ];
  
  $scope.itemsTransformed = angular.copy($scope.items).map(function(item){
    delete item.myChoice;
    item.choices = Object.keys(item.choices).map(function(choice){
        item.choices[choice].name = choice;
        return item.choices[choice];
    });
    return item;
  });
  
  //select an option like an object, not a string
  $scope.itemsTransformed[1].myChoice = $scope.itemsTransformed[1].choices[0];
  
  $timeout(function() {
    //changes a prop in opts array - options are not-re-rendered in the DOM
    //the same option is still selected
    $scope.itemsTransformed[1].choices[0].arg = "xyz";
  }, 3000);
  
  $scope.selectionChanged =function(key, items){
    console.log(items); //as we can see $$hashKey wasn't added to choices props
  };
   
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<ul ng-app="myApp" ng-controller="MyController">
   <p>Without track by:</p>
   <div ng-repeat="data in items track by data.title">
     <div>{{data.title}} - {{data.myChoice}}</div>
       
     <select ng-model="data.myChoice" 
             ng-options="key as key for (key , value) in data.choices"
             ng-change="selectionChanged(key, items)">
       <option value="">Select Connection</option>
     </select>
     
   </div>
   <hr/>
    <p>Using track by name to pre-select an option:</p>
    <div ng-repeat="data in itemsTransformed track by data.title">
     <div>{{data.title}} - {{data.myChoice}}</div>
       
     <select ng-model="data.myChoice" 
             ng-options="choice as choice.name for choice in data.choices track by choice.name"
             ng-change="selectionChanged(key, itemsTransformed)">
       <option value="">Select Connection</option>
     </select>
     
   </div>
</ul>

Ответ 2

ngOptions не создает новую область действия, например, директиву ngRepeat для каждого элемента, поэтому вам не нужно заботиться о том, чтобы избавиться от $$hashKey

Я бы использовал ng-repeat для итерации на <option> (предположим, что вы не создаете длинные списки):

<select ng-model="data.myChoice">    
    <option value="">Select Connection</option>
    <option ng-repeat="(key , value) in data.choices track by key" ng-value="key" title="{{key}}"
    >{{key}}</option>
</select>

Рабочая демонстрационная скрипта


Посмотрите на эту проблему: github.com/angular/angular.js/issues/6564 - ng-options отслеживают и выбирают как несовместимые

Я считаю, что этот вопрос все еще существует, поэтому предложите использовать ngRepeat с track by. Для небольшого списка нет штрафа за производительность

Ответ 3

Вам нужно добавить ng-change и передать/использовать ваше значение ng-model, чтобы получить любое свойство, которое вы хотите.

Ответ 4

Атрибут

ngOptions может использоваться для динамического создания списка элементов для элемента с использованием массива или объекта

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

1.Если вы устанавливаете модель на объект, который равен объекту в вашей коллекции, ngOptions не смогут установить выделение, потому что объекты не идентичны. Поэтому по умолчанию вы всегда должны ссылаться на элемент в своей коллекции для выбора, например: $scope.selected = $scope.collection [3]

  1. ngOptions будет отслеживать идентификатор элемента не по ссылке, а по результату дорожки по выражению. Например, если ваши элементы коллекции имеют свойство id, вы будете отслеживать по элементу item.id.

Пример:

 $scope.items = [
  {
    "title": "1",
    "myChoice" :"",
      "choices": {
        "pizza": {
          "type": 1,
          "arg": "abc"
        },
        "burger": {
          "type": 1,
          "arg": "pqr"
        }
      }
   },
   {
    "title": "2",
     "myChoice" :"",
      "choices": {
        "pizza": {
          "type": 1,
          "arg": "abc"
        },
        "burger": {
          "type": 1,
          "arg": "pqr"
        }
      }
   }
  ];

Из вышеприведенной 2-й точки отслеживайте личность элемента не по ссылке.

Добавить keyName ключа в объекте и дорожке с помощью keyName или track by arg, введите.

Трек по аргументу или типу:

 <select ng-model="data.myChoice" 
                 ng-options="choice as choice.arg for choice in data.choices track by choice.arg">
           <option value="">Select Connection</option>
         </select>

Или добавить ключевое имя внутри объекта выбора

 $scope.items = $scope.items.filter(function(item){
    delete item.myChoice;
    item.choices = Object.keys(item.choices).map(function(choice){
        item.choices[choice].keyName = choice;
        return item.choices[choice];
    });
    return item;
  });

Код HTML:

<div ng-controller="MyCtrl">
   <ul>
   <div ng-repeat="data in items">
     <select ng-model="data.selected" 
             ng-options="choice as choice.keyName for choice in data.choices track by choice.keyName"
             ng-change="selection(data.selected)">
       <option value="">Select</option>
     </select>

   </div>
   </ul>
</div>

Демо-ссылка Пример

Ответ 5

<select class="form-control pickupaddress ng-pristine ng-valid ng-touched m-r-sm m-t-n-xs" ng-model="item.pickup_address" tabindex="0" aria-invalid="false" ng-options="add._id as add.nick_name for add in addPerFood[item.food._id] | unique:'nick_name'" ng-change="dropDownSelect(item.pickup_address,allCarts,item,$index)">