Skip to content
This repository has been archived by the owner on Oct 2, 2019. It is now read-only.

Async refresh ui-select: selected options appears in the list again after type in input #580

Closed
Astray-git opened this issue Jan 13, 2015 · 9 comments

Comments

@Astray-git
Copy link

I have a select with a refresh method,
If I select one item in the list, it will be removed from the options list.
but after I type in the input, the list get refreshed, selected options appears again in the list.

How to avoid this?

@MikeABentley
Copy link

I've hit this issue as well. It's because the filter code is using the Array.indexOf() proto function. This doesn't work so well when you have an array of objects. I was able to get it to work using the Array.map() proto function and then calling indexOf on the returned array object.

I'm using the id property of the objects in my various collections. Obviously this doesn't work since you never know what properties are going to exist. I tried using the $$hashKey property, but that property doesn't exist on the items that are returned by my remote data call. I didn't add code to verify that I'm working with an array of classical objects since this is just a working example.

// See https://github.com/angular/angular.js/blob/v1.2.15/src/ng/directive/ngRepeat.js#L259
      $scope.$watchCollection(ctrl.parserResult.source, function(items) {

        if (items === undefined || items === null) {
          // If the user specifies undefined or null => reset the collection
          // Special case: items can be undefined if the user did not initialized the collection on the scope
          // i.e $scope.addresses = [] is missing
          ctrl.items = [];
        } else {
          if (!angular.isArray(items)) {
            throw uiSelectMinErr('items', "Expected an array but got '{0}'.", items);
          } else {
            if (ctrl.multiple){
              //Remove already selected items (ex: while searching)
                var filteredItems = items.filter(function (i) {
                    return ctrl.selected.map(function (e) { return e.id; }).indexOf(i.id) < 0;
                });
              setItemsFn(filteredItems);
            }else{
              setItemsFn(items);
            }
            ctrl.ngModel.$modelValue = null; //Force scope model value and ngModel value to be out of sync to re-run formatters

          }
        }

      });

@MikeABentley
Copy link

Quick follow-up to this. For now I'm just filtering my results when I get the data back from the ajax call.

I pass in the select control to the refresh function and grab the selected values from there.

<ui-select-choices repeat="solicitor in locals.solicitorSearchResults | filter: $select.search" refresh="locals.solicitorSearch($select.search, $select)" refresh-delay="100">

Then I filter the results based on what's currently selected.

.....
.....
var results = result.data.results,
    filteredItems,
    selected = locals.solicitorSearchControl.selected;

filteredItems = results.filter(function (i) {
    return selected.map(function (e) { return e.id; }).indexOf(i.id) < 0;
});

$scope.locals.solicitorSearchResults = filteredItems;
.....
.....

@nmarshall23
Copy link

@MBentley1976 could you go into more detail. That I have to write a filter for this, seems odd.

This feels like a bug in ui-select.

@MikeABentley
Copy link

Hey Marshall, the issue is the IndexOf() function on the array to look for existing items. That doesn't work well when trying to compare objects which is what I'm populating my items array with. To get around it I'm using the Map() function to do the comparison and filtering my remotely sourced array myself. I took code I had in my local controller and wrapped it up in a custom angular service, so it's pretty portable throughout my application.

@H320
Copy link

H320 commented Sep 24, 2015

very simple! just keep reference of selected items and exchange it by duplicate received items

if (ctrl.multiple && ctrl.selected) {
    var selectedindexes = ctrl.selected.map(function (e) { return e.id; }), i, t;
    angular.forEach(items, function(v, k) { 
        if ((i = selectedindexes.indexOf(v.id)) >= 0) {
            t = items[k] = select.selected[i];
            angular.forEach(v, function(n, p) { t[p] = v[p]; });
        }
    });
}

@wesleycho
Copy link
Contributor

Going to close as a usage issue - this is a problem that should be solved on the user's side.

@MattiJarvinen
Copy link
Contributor

@wesleycho seems to be odd that it should be solved on the user's side instead of UI-select, especially this isn't documented.

@user378230
Copy link
Contributor

@MattiJarvinen-BA This has actually been resolved in #1473 from what I can see (Ref: src/uiSelectController.js#L242)

@MattiJarvinen
Copy link
Contributor

@user378230 oh, seems so. So nevermind then. ;)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants