Ошибка связывания с раскрывающимся списком с отслеживанием по

16

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

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

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

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

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

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

Итак, какова должна быть моя структура данных $ 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>
    
задан Learning-Overthinker-Confused 07.09.2017 в 17:32
источник
  • Почему бы не отслеживать по $ index –  Maxim Shoustin 07.09.2017 в 17:40
  • @MaximShoustin Добавление индекса trackby $ всегда является автоматическим выбором последнего элемента. Посмотрите мое обновление, я добавил индекс $ index, и теперь я не могу выбрать какие-либо другие элементы –  Learning-Overthinker-Confused 07.09.2017 в 17:42
  • При обращении к себе («Я») всегда используйте заглавную букву. Это позволит некоторым редакторам-добровольцам работать над улучшением ваших сообщений (предположительно, все 278 из них имеют одинаковые ошибки). Спасибо! –  halfer 14.09.2017 в 22:37

5 ответов

9

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

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

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

  

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

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

ОБНОВЛЕНИЕ: Вот код, который иллюстрирует, как вы можете изменить исходный источник данных и использовать 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: Простой пример, который показывает нам, что свойство $$hashKey не добавляется к объектам при использовании ngOptions без track by :

var app = angular.module("myApp", []);
app.controller("MyController", ['$scope', '$timeout', function ($scope, $timeout) {
    $scope.items = {
        "pizza": {
          "type": 1,
          "arg": "abc"
        },
        "burger": {
          "type": 1,
          "arg": "pqr"
        }
      };

    $scope.selectionChanged = function (key, items) {
        console.log($scope.items);
    };

}]);
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyController">
    <hr/>
    <p>Example without track by:</p>

    <select ng-model="myChoice"
            ng-options="key as key for (key , value) in items"
            ng-change="selectionChanged(myChoice, items)">
        <option value="">Select Connection</option>
    </select> 
    <hr/>
    {{myChoice}}
</div>

ОБНОВЛЕНИЕ 3: Конечный результат ниже (работа с версиями angularjs и 1.4 для 1.4+ я бы рекомендовал изменить структуру данных как $scope.itemsTransformed в первом фрагменте кода):

angular.module("myApp", [])
.controller("MyController", ['$scope', function ($scope) {
    $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"
                }
            }
        }
    ];
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyController">
    <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">
            <option value="">Select Connection</option>
        </select>

    </div>
</div>
    
ответ дан Stanislav Kvitash 07.09.2017 в 19:24
источник
  • Упомянуто для ваших добрых усилий по оказанию мне помощи, но делает ng-опционы без отслеживания, благодаря преимуществам производительности по сравнению с ng-repeat ?? –  Learning-Overthinker-Confused 07.09.2017 в 20:22
  • Проблема с ng-параметрами без трека генерирует хеш, с помощью которого я заявил в своем вопросе, и я этого не хочу. Вот почему я хочу использовать трек, так что угловой не генерирует хеш для отслеживания изменений –  Learning-Overthinker-Confused 07.09.2017 в 20:24
  • @Learning, попытался удалить трек из ngOptions, и я не вижу $$ hashKey, который создается (добавит код для иллюстрации.). отслеживать с помощью ngRepeat имеет смысл с точки зрения производительности, но я не уверен, что он играет ту же роль в директиве ngOptions - поскольку из документов он используется для сохранения выбора при повторном создании параметров. –  Stanislav Kvitash 07.09.2017 в 20:41
  • @Learning Добавлен фрагмент кода, пожалуйста, проверьте. Как указано в директиве docs, ngOptions обладает преимуществами производительности по сравнению с ngRepeat (нет ничего о том, как использовать дорожку для улучшения ее производительности, и я тоже не вижу что-то связанное в источниках). Откуда вы получили эту информацию, которая отслеживает влияние производительности ngOptions? Btw в фрагменте, который вы используете angularjs v1.2, я рекомендую обновить его, если вы заботитесь о производительности в целом :) –  Stanislav Kvitash 07.09.2017 в 21:16
  • WIthout трек добавляет hashkey в ваш первый пример. Я не понимаю, почему вы использовали тайм-аут в своем коде второго примера –  Learning-Overthinker-Confused 09.09.2017 в 13:12
Показать остальные комментарии
6

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 . Для небольшого списка нет штрафа за производительность

    
ответ дан Maxim Shoustin 07.09.2017 в 18:10
источник
  • Упомянуто о ваших добрых усилиях по оказанию помощи, но вы можете объяснить мне немного об этом, как о том, в чем проблема в моем коде и почему не ng-options ?? –  Learning-Overthinker-Confused 07.09.2017 в 18:34
  • @Участие в вашем коде не проблема, а сложная структура. Поэтому я заменил директиву ngOptions базовым ng-repeat –  Maxim Shoustin 07.09.2017 в 18:40
  • @Learning Взгляните на эту проблему: github.com/angular/angular.js/issues/6564 - ng-options отслеживать и выбирать как несовместимые –  Maxim Shoustin 07.09.2017 в 18:50
  • Большое вам спасибо за ваши добрые усилия по оказанию помощи и, пожалуйста, продолжайте помогать подобным образом. Оцените :) –  Learning-Overthinker-Confused 16.09.2017 в 16:46
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>

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

    
ответ дан ankesh jain 11.09.2017 в 11:54
источник
  • Большое вам спасибо за ваши добрые усилия по оказанию помощи и, пожалуйста, продолжайте помогать подобным образом. Оцените :) –  Learning-Overthinker-Confused 16.09.2017 в 16:46
3

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

    
ответ дан Marcin Malinowski 07.09.2017 в 17:45
источник
  • Упомянуто о ваших добрых усилиях по оказанию мне помощи, но я немного запутался здесь. Если я установил значение моей ng-модели, то какая должна быть моя ng-модель в select. Можете ли вы добавить какой-нибудь простой код того, что вы говорите, пожалуйста? –  Learning-Overthinker-Confused 07.09.2017 в 18:33
  • ng-change="youFuncHere (ключ)" –  Marcin Malinowski 07.09.2017 в 20:46
  • Но когда я не добавляю ng-model в своем раскрывающемся списке, я получаю сообщение об ошибке: Контроллер 'ngModel', требуемый директивой 'ngOptions', не может быть найден! Так вы говорите, что я указываю ng-model, но все же установить мою модель в метод youFuncHere? –  Learning-Overthinker-Confused 09.09.2017 в 13:05
  • Не уверен, что этот ответ каким-то образом связан с использованием ngOptions. –  Stanislav Kvitash 11.09.2017 в 12:06
2
<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)">
    
ответ дан Ravi Teja 13.09.2017 в 07:27
источник
  • , пожалуйста, попробуйте объяснить больше. –  Shaminder S Aujla 13.09.2017 в 07:32
  • Большое вам спасибо за ваши добрые усилия по оказанию помощи и, пожалуйста, продолжайте помогать подобным образом. Оцените :) –  Learning-Overthinker-Confused 16.09.2017 в 16:46