I ran into this problem, and I don't know how to solve it. I have used a ui-select multiselect in my page. First, a http.get request is made to a url which gets the data, then the ui-select choices are populated. The data is big - the length of the data is 2100. This data is to be shown as choices. (The data is fetched at the beginning during the loading of the page and is stored in an array)
But the problem is each time I click on the multiselect to select a choice, it takes 4-5 seconds to populate the list and the page becomes very slow. What do I do to reduce this time?
The choices data is stored in an array, the datatype is array of strings.
<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>
in the controller,
$scope.selectedFields = {};
$scope.selectedFields.name = [];
$scope.init = function() {
$http.get(url)
.success( function(response, status, headers, config) {
availableFields = response;
})
.error( function(err) {
});
};
$scope.init();
If not this way, is there any other options/choice I can work with which doesn't delay showing the select-choices?
This is a known issue in ui-select. I tried the following ways, both work
1) There is a workaround for this - use
| limitTo: 100
This limits the choice display to 100 but all the choices can be selected. Look at this thread for more details.
2) Since some of the time, there is a need to display the entire list in the choices, 1) is not a viable option. I used a different library - selectize.js. Here's a plunker demo given in the page
Here is complete solution that decorates uiSelectChoices
directive.
Items are populated progressively as the user scrolls.
Also takes care of searches in the scrolls.
Also works for all values of position={auto, up, down}
Example
<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>
Working Plnkr Also with With v0.19.5
The directive
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();
});
};
}]);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With