javascript angularjs

javascript - Tema de enlace desplegable con seguimiento por



angularjs (5)

El atributo ngOptions se puede usar para generar dinámicamente una lista de elementos para el elemento utilizando la matriz o el objeto

ngModel observa el modelo por referencia, no por valor. Es importante saber esto cuando se vincula la selección a un modelo que es un objeto o una colección.

1.Si establece el modelo en un objeto que es igual a un objeto en su colección, ngOptions no podrá establecer la selección, porque los objetos no son idénticos. Entonces, de forma predeterminada, siempre debe hacer referencia al elemento en su colección para las preselecciones, por ejemplo: $ scope.selected = $ scope.collection [3]

  1. ngOptions rastreará la identidad del artículo no por referencia, sino por el resultado de la pista por expresión. Por ejemplo, si los elementos de su colección tienen una propiedad de identificación, debe realizar un seguimiento por item.id.

Por ejemplo :

$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" } } } ];

Desde el segundo punto anterior, haga un seguimiento de la identidad del artículo, no por referencia.

Agregue keyName de la clave en el objeto y rastree por keyName o rastree por arg, escriba.

Seguimiento por arg o tipo:

<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>

O agregue keyName dentro del objeto de elección

$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; });

Código 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>

Example enlace de demostración

Estoy teniendo problemas al vincular mi valor desplegable con una matriz asociativa.

El problema está en la pista por, por ejemplo, cuando no agrego la pista a mi menú desplegable, tengo mi enlace con la lista desplegable y cuando agrego la pista por entonces O no puedo seleccionar automáticamente el valor del menú desplegable.

Quiero usar track by con ng-options para que js angular no agregue $$ hashKey y aproveche el beneficio de rendimiento asociado con track por.

No entiendo por qué está ocurriendo este comportamiento.

Nota: solo quiero unir el nombre de opciones como Pizza o hamburguesa para cada uno de mis $ scope.items y no todo el objeto .

Actualización: Como entiendo y con tanto intentar con la estructura de datos actual de mi $ scope.items, no funciona con ng-options y quiero usar ng-options con track para evitar generar la clave hash con Angular js. También probé ng-change según lo sugerido por @MarcinMalinowski, pero estoy recibiendo la clave como indefinida.

Entonces, ¿cuál debería ser mi estructura de datos de $ scope.items para que cuando tenga que acceder a cualquier elemento desde mi $ scope.items? Puedo acceder a él sin hacer un bucle (como nosotros accedemos a elementos de una matriz asociativa), como cómo puedo acceder ahora con la estructura de datos correcta y usar ngoptions solo con seguimiento por.

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>


Los problemas en su código son:

1) el track by $index no es compatible con ngOptions , dará como resultado que el valor de la option undefined esté undefined (en su caso será un $index de ngRepeat );

2) el track by no funciona bien con las fuentes de datos de objetos (se supone que se debe usar con fuentes de datos de matriz), desde los documentos :

trackexpr: se utiliza cuando se trabaja con una matriz de objetos. El resultado de esta expresión se utilizará para identificar los objetos en la matriz.

Por supuesto, puede usar ngRepeat para generar elementos de option , pero personalmente, preferiría usar ngOptions sin track by debido a los beneficios que tiene sobre ngRepeat .

ACTUALIZACIÓN: Aquí está el código que ilustra cómo puede cambiar su origen de datos inicial y usar la track by para preseleccionar una opción en caso de que el modelo sea un objeto. Pero incluso en el primer ejemplo console.log() muestra que $$hashKey no se agregó al objeto de 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>

ACTUALIZACIÓN 2: Un ejemplo simple que nos muestra el hecho de que la propiedad $$hashKey no se agrega a los objetos cuando se usan ngOptions sin 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>

ACTUALIZACIÓN 3: Resultado final a continuación (que funciona con las versiones de angularjs <1.4, para 1.4+ recomendaría cambiar la estructura de datos como $scope.itemsTransformed en el primer fragmento de código):

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>


ng-change agregar ng-change y pasar / usar su valor ng-model allí para obtener la propiedad que desee.


ngOptions no crea un nuevo ámbito, como la directiva ngRepeat por elemento, por lo que no necesita tener cuidado para deshacerse de $$hashKey

ng-repeat para iterar en <option> (suponga que no crea listas largas):

<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>

Demostración de trabajo Fiddle

Observe este problema: github.com/angular/angular.js/issues/6564 - ng-options rastrea y seleccione que no son compatibles

Creo que este problema sigue existiendo, así que sugiero que use ngRepeat con track by . Para la lista pequeña no hay penalización de rendimiento


<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)">