con buscador angularjs angular-ui ui-select

angularjs - buscador - ui-select multiselect es muy lento en mostrar las opciones



ui-select angularjs (4)

Me encontré con este problema, y ​​no sé cómo resolverlo. He utilizado un multiselección ui-select en mi página. Primero, se realiza una solicitud http.get a una URL que obtiene los datos, luego se completan las opciones de selección de ui. Los datos son grandes: la longitud de los datos es 2100. Estos datos se mostrarán como opciones. (Los datos se recuperan al principio durante la carga de la página y se almacenan en una matriz)

Pero el problema es que cada vez que hago clic en la selección múltiple para seleccionar una opción, se tarda 4-5 segundos en completar la lista y la página se vuelve muy lenta. ¿Qué hago para reducir este tiempo?

Los datos de las opciones se almacenan en una matriz, el tipo de datos es una matriz de cadenas.

<ui-select multiple ng-model="selectedFields.name" style="width: 100%;"> <ui-select-match placeholder="Select fields...">{{$item}}</ui-select-match> <ui-select-choices repeat="fields in availableFields | filter:$select.search"> {{fields}} </ui-select-choices> </ui-select>

en el controlador,

$scope.selectedFields = {}; $scope.selectedFields.name = []; $scope.init = function() { $http.get(url) .success( function(response, status, headers, config) { availableFields = response; }) .error( function(err) { }); }; $scope.init();

Si no es así, ¿hay alguna otra opción / opción con la que pueda trabajar que no demore en mostrar las opciones de selección?


Aquí está la solución completa que decora la directiva uiSelectChoices .

Los elementos se llenan progresivamente a medida que el usuario se desplaza.

También se encarga de las búsquedas en los pergaminos.

También funciona para todos los valores de position={auto, up, down}

Ejemplo

<ui-select-choices position="up" all-choices="ctrl.allTenThousandItems" refresh-delay="0" repeat="person in $select.pageOptions.people | propsFilter: {name: $select.search, age: $select.search} "> <div ng-bind-html="person.name | highlight: $select.search"></div> <small> email: {{person.email}} age: <span ng-bind-html="''''+person.age | highlight: $select.search"></span> </small> </ui-select-choices>

Plnkr de trabajo también con con v0.19.5

La directiva

app.directive(''uiSelectChoices'', [''$timeout'', ''$parse'', ''$compile'', ''$document'', ''$filter'', function($timeout, $parse, $compile, $document, $filter) { return function(scope, elm, attr) { var raw = elm[0]; var scrollCompleted = true; if (!attr.allChoices) { throw new Error(''ief:ui-select: Attribute all-choices is required in ui-select-choices so that we can handle pagination.''); } scope.pagingOptions = { allOptions: scope.$eval(attr.allChoices) }; attr.refresh = ''addMoreItems()''; var refreshCallBack = $parse(attr.refresh); elm.bind(''scroll'', function(event) { var remainingHeight = raw.offsetHeight - raw.scrollHeight; var scrollTop = raw.scrollTop; var percent = Math.abs((scrollTop / remainingHeight) * 100); if (percent >= 80) { if (scrollCompleted) { scrollCompleted = false; event.preventDefault(); event.stopPropagation(); var callback = function() { scope.addingMore = true; refreshCallBack(scope, { $event: event }); scrollCompleted = true; }; $timeout(callback, 100); } } }); var closeDestroyer = scope.$on(''uis:close'', function() { var pagingOptions = scope.$select.pagingOptions || {}; pagingOptions.filteredItems = undefined; pagingOptions.page = 0; }); scope.addMoreItems = function(doneCalBack) { console.log(''new addMoreItems''); var $select = scope.$select; var allItems = scope.pagingOptions.allOptions; var moreItems = []; var itemsThreshold = 100; var search = $select.search; var pagingOptions = $select.pagingOptions = $select.pagingOptions || { page: 0, pageSize: 20, items: $select.items }; if (pagingOptions.page === 0) { pagingOptions.items.length = 0; } if (!pagingOptions.originalAllItems) { pagingOptions.originalAllItems = scope.pagingOptions.allOptions; } console.log(''search term='' + search); console.log(''prev search term='' + pagingOptions.prevSearch); var searchDidNotChange = search && pagingOptions.prevSearch && search == pagingOptions.prevSearch; console.log(''isSearchChanged='' + searchDidNotChange); if (pagingOptions.filteredItems && searchDidNotChange) { allItems = pagingOptions.filteredItems; } pagingOptions.prevSearch = search; if (search && search.length > 0 && pagingOptions.items.length < allItems.length && !searchDidNotChange) { //search if (!pagingOptions.filteredItems) { //console.log(''previous '' + pagingOptions.filteredItems); } pagingOptions.filteredItems = undefined; moreItems = $filter(''filter'')(pagingOptions.originalAllItems, search); //if filtered items are too many scrolling should occur for filtered items if (moreItems.length > itemsThreshold) { if (!pagingOptions.filteredItems) { pagingOptions.page = 0; pagingOptions.items.length = 0; } else { } pagingOptions.page = 0; pagingOptions.items.length = 0; allItems = pagingOptions.filteredItems = moreItems; } else { allItems = moreItems; pagingOptions.items.length = 0; pagingOptions.filteredItems = undefined; } } else { console.log(''plain paging''); } pagingOptions.page++; if (pagingOptions.page * pagingOptions.pageSize < allItems.length) { moreItems = allItems.slice(pagingOptions.items.length, pagingOptions.page * pagingOptions.pageSize); } for (var k = 0; k < moreItems.length; k++) { pagingOptions.items.push(moreItems[k]); } scope.calculateDropdownPos(); scope.$broadcast(''uis:refresh''); if (doneCalBack) doneCalBack(); }; scope.$on(''$destroy'', function() { elm.off(''scroll''); closeDestroyer(); }); }; }]);


Como se indicó, ui-select está teniendo bastantes problemas de rendimiento, pero hay una solución para el problema del límite.

Si sigue el enfoque de akashrajkn, notará que en realidad eliminará partes importantes de datos porque solo generará 100 a la vez. Hay una solución que ha pasado las pruebas unitarias y se puede encontrar en el hilo aquí:

https://github.com/angular-ui/ui-select/pull/716

Básicamente, si está almacenando el archivo javascript localmente, entonces puede ajustar la versión no minada. Todo lo que necesita hacer es implementar los cambios que realizó en la solicitud de extracción y esto debería ser de gran ayuda. Para aplicar el factor limitante, eche un vistazo al siguiente ejemplo modificado:

<ui-select multiple ng-model="selectedFields.name" limit = "10" style="width: 100%;"> <ui-select-match placeholder="Select fields...">{{$item}}</ui-select-match> <ui-select-choices repeat="fields in availableFields | filter:$select.search | limitTo:$select.limit "> {{fields}} </ui-select-choices> </ui-select>

Lo anterior limitará sus datos en el menú desplegable y también mantendrá el nivel de consistencia necesario.


Debido a que no puedo dejar un comentario (no hay suficiente repetición), escribo esto como una respuesta y lamento que no haya respuesta para el problema.

@bhantol Cambié la siguiente línea de código a su solución que hasta ahora funciona perfectamente para mí

for (var k = 0; k < moreItems.length; k++) { pagingOptions.items.push(moreItems[k]); } for (var k = 0; k < moreItems.length; k++) { if (pagingOptions.items.indexOf(moreItems[k]) == -1){ pagingOptions.items.push(moreItems[k]); } }

Esto evita que se muestren elementos duplicados si el usuario comienza a escribir un filtro y luego lo elimina.

También me di cuenta de que si la lista es más pequeña que 20 elementos, no funcionará, así que cambié:

if (pagingOptions.page * pagingOptions.pageSize < allItems.length) { moreItems = allItems.slice(pagingOptions.items.length, pagingOptions.page * pagingOptions.pageSize); }

a:

if (pagingOptions.page * pagingOptions.pageSize < allItems.length) { moreItems = allItems.slice(pagingOptions.items.length, pagingOptions.page * pagingOptions.pageSize); } else{ moreItems = allItems;}

Tal vez esto te ayude de alguna manera y lo siento nuevamente por no responder la pregunta.


Este es un problema conocido en ui-select. He intentado las siguientes formas, tanto el trabajo

1) Hay una solución para esto - usar

| limitTo: 100

Esto limita la visualización de opciones a 100, pero se pueden seleccionar todas las opciones. Mira este hilo para más detalles.

2) Como parte del tiempo, es necesario mostrar la lista completa en las opciones, 1) no es una opción viable. Utilicé una biblioteca diferente - selectize.js . Aquí está una demostración plunker dada en la página