How do I $watch the Angular-ui's new ui-select (former ui-select2) search string changes?
Asked Answered
P

5

10

I noticed that the Angular-UI have discontinued their UI-Select2 directive in favor of the new UI-Select (with multiple themes - select2, bootstrap, selectize).

It looks like this:

<ui-select multiple ng-model="multipleDemo.colors" theme="select2" ng-disabled="disabled" style="width: 300px;">
    <ui-select-match placeholder="Select colors...">{{$item}}</ui-select-match>
    <ui-select-choices repeat="color in availableColors | filter:$select.search">
        {{color}}
    </ui-select-choices>
</ui-select>

<p>Selected: {{multipleDemo.colors}}</p>

Initially my selectbox is supposed to be empty but ready to take typed characters, that is a string of at least 4 characters and then make an API call to retrieve a list of suggested values which are to populate the box. One value will then be chosen, and searching should be repeated as needed.

First I tried $watching the ng-model which in this case is multipleDemo.colors (using this example from the demos). The API call never occurred and then I realized why. The actual model is not changed at all because it only changes when a selection is made (my selectbox is empty so nothing can be selected).

My conclusion is that I should (be able to) $watch what's been added as filter, namely filter: $select.search.

Does anyone know how am I supposed to use that one in my controller?

This:

$scope.$watch('$select.search', function(newVal){
    alert(newVal);
});

doesn't work.

EDIT: For anyone's reference, see this short discussion: Is it possible to add support for custom query function like the select2?

EDIT 2:

I solved this by using $emit from within the directive so the value is available in my controller now. But now I'd like to know how can I override this part of the directive so the directive itself can be left intact so it doesn't break in future updates?

Period answered 29/9, 2014 at 9:40 Comment(0)
P
-1

I solved it by creating an event in the right spot within the directive and then $emitting it - eventually I am able to listen to the event in my controller and use the value.

The downside to this is that I've put this directly in the 3rd-party's directive so it can't be safely updated. I need to find a way to override the directive. If you have any ideas, please let me know.

Period answered 3/10, 2014 at 20:35 Comment(1)
Next time you run "bower update ui-select" come here and unmark this as the answer. btw, have you checked Chris Bond answer?Bridge
H
16

Use the refresh attribute on the <ui-select-choices> element to call a function on your scope with $select.search as the parameter:

<ui-select-choices repeat="color in multipleDemo.availableColors | filter:$select.search"
                   refresh="refreshColors($select.search)"
                   refresh-delay="0">
    {{color}}
</ui-select-choices>

Then use the function (refreshColors() in this snippet) to update multipleDemo.availableColors accordingly.

You may also use the refresh-delay attribute to specify how many milliseconds to debounce the function so it is not called too many times in quick succession.

I have also put availableColors on multipleDemo like you have done for multipleDemo.colors, as is recommended.

Reference: ui-select directive wiki under section Examples: Async.

Hannie answered 6/11, 2014 at 3:43 Comment(5)
It works as long as you don't need it inside ng-repeat.Bridge
Are you repeating the <ui-select>? In that case you could pass a second parameter to refresh function to identify the instance.Hannie
mmmm yes...but does that feels alright? see github.com/angular-ui/ui-select/issues/…Bridge
I assume you have something like <div ng-repeat="item in list"><ui-select>...</ui-select></div>... to make the refresh function aware of the context, pass it in like refresh="refreshColors(item, $select.search)". Then you can access all useful properties of each item (like IDs) to do whatever differentiation you need.Hannie
Added this then used a function. Worked well for me. <ui-select-choices refresh='refresh($select)' refresh-delay='0' ... >Tramroad
V
11

There seems to be an on-select attribute, see Github example:

<ui-select ng-model="person.selected" on-select="someFunction($item, $model)" [...]>
  [...]
</ui-select>
Veron answered 23/10, 2014 at 22:50 Comment(1)
I believe this is executed after an option is selected. What I needed was to trigger an action when character (or a threshold thereof is reached) are input.Period
T
1

Use ngInit to get the value,

<div ui-select ng-init="mySelect = $select"></div>
<button ng-click="search(mySelect.search)">Search</button>

You can alse watch 'mySelect' instead

$scope.$watch('mySelect.search', function(newVal){
    alert(newVal);
});
Tridentum answered 26/11, 2015 at 8:17 Comment(0)
E
1

Bear with me, this is my first answer on SO.

So the current top answer does not work for me. Just want to provide another option. The refresh property on the ui-select-choices does not trigger the named function in my scope.

I followed the info in their docs for accessing the UI select for custom features. Create a custom directive in which you watch $select.search like

myModule.directive('myUiSelect', function() {
  return {
    require: 'uiSelect',
    link: function(scope, element, attrs, $select) {
      scope.$watch('$select.search', function (search) {
        if (search) {
          ...
        }
      });
    }
  };
});

and then include the directive on your <ui-select my-ui-select> tag.

Elanorelapid answered 23/8, 2016 at 21:5 Comment(0)
P
-1

I solved it by creating an event in the right spot within the directive and then $emitting it - eventually I am able to listen to the event in my controller and use the value.

The downside to this is that I've put this directly in the 3rd-party's directive so it can't be safely updated. I need to find a way to override the directive. If you have any ideas, please let me know.

Period answered 3/10, 2014 at 20:35 Comment(1)
Next time you run "bower update ui-select" come here and unmark this as the answer. btw, have you checked Chris Bond answer?Bridge

© 2022 - 2024 — McMap. All rights reserved.