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

Need ability to postpone refresh function call until select is open #619

Closed
Envek opened this issue Jan 29, 2015 · 7 comments
Closed

Need ability to postpone refresh function call until select is open #619

Envek opened this issue Jan 29, 2015 · 7 comments

Comments

@Envek
Copy link

Envek commented Jan 29, 2015

Description

I have a lot (tens or thousands) selects on page that need to fetch choices for each select independently.

Each select allows to choose a user with a some rank that is free in some period of time. As only server knows that, I need to fetch data from it. But there is a lot of selects and data for all of them starting to load immediately after page load making browser to freeze. But at that time all of selects are hidden with ng-show directive of some parent node and most probably most of them wouldn't be used now.

Here is the code:

<div ng-show="crew.editing">
  <div ng-repeat="member in crew.members">
    <ui-select ng-model="member.user" theme="bootstrap">
      <ui-select-match>{{$select.selected.shortName()}}</ui-select-match>
      <ui-select-choices 
        repeat="user in users[member.slot.rank_id] | filter: {name: $select.search, lastname: $select.search, patronymic: $select.search}"
        refresh="loadUsers(crew.time_interval, member.slot.rank)"
      >
        <div ng-bind-html="user | highlight: $select.search"></div>
        <small>{{user.ranks | map:'name' | join:', '}}</div>
      </ui-select-choices>
    </ui-select>
  </div>
</div>

Required behaviour

Need ability to postpone function call in refresh attribute to time when select will be opened/clicked/focused/hovered/anything.

Workaround

Hide blocks containing selects with ng-if directive. It allows to load users in somewhat lesser batches, but problem still exists.

@sporkd
Copy link

sporkd commented Jan 30, 2015

You could probably define your own fetch method on the current scope and have it return empty options until you need the data. See https://github.com/angular-ui/ui-select/wiki/ui-select#examples-async

Trick will be detecting the event you want to trigger loading the options...

<ui-select ng-model="model.selected" ng-click="loadOptions()">
  <ui-select-choices repeat="option in options"
           refresh="refresh($select.search)">
</ui-select>
# Inside your directive
link: (scope, elem, attrs) ->
  scope.enabled = false
  scope.refresh = (query='') ->
    if scope.enabled
      OptionsService.fetch(query).then (data) ->
        scope.options = data
    else
      scope.options = []

  scope.loadOptions = ->
    scope.enabled = true
    scope.refresh()

Still, I agree it would be nice to delay the first call to fetch since it happens immediatley when the directive is rendered in a template. Another workaround is to delay the rendering the actual template it lives in using resolving routes...

.when '/selection-page',
  templateUrl:    'pages/select.html) %>'
  controller:     'SelectionController'
  resolve:
    fetchOptions: (OptionsFactory) ->
      OptionsFactory.fetchOptions()

See http://odetocode.com/blogs/scott/archive/2014/05/20/using-resolve-in-angularjs-routes.aspx for more complete example.

@sporkd
Copy link

sporkd commented Feb 2, 2015

Just realized the first solution I provided may delay loading like you want, but probably won't populate the dropdown until you actually start typing in box (since that's when fetch will next be called). Maybe you could render a dummy select ui and then swap it out with a real one when the user clicks? Ugly I know.

@Envek
Copy link
Author

Envek commented Feb 16, 2015

@sporkd thank you very much for a hint and sorry for the late response.

Currently I'm using workaround like this:

<ui-select ng-model="slot.user" theme="bootstrap" ng-click="allowLoadUsersFor(slot)">
  <ui-select-match>{{$select.selected.shortName()}}</ui-select-match>
  <ui-select-choices 
    repeat="user in users[slot.id] | filter: {name: $select.search, lastname: $select.search, patronymic: $select.search}"
    refresh="loadUsers(slot)"
  >
    <div ng-bind-html="user | highlight: $select.search"></div>
    <small>{{user.ranks | map:'name' | join:', '}}</div>
  </ui-select-choices>
</ui-select>
// in scope
this.allowedToLoadUsers = {}
this.allowLoadUsersFor = function(slot) {
  this.allowedToLoadUsers[slot.id] = true
}

this.loadUsers = function (slot) {
  if this.allowedToLoadUsers[slot.id] {
    // Do the real load
  } else {
    // Return an empty array or array with current user in a slot
  }
}

@abudel
Copy link

abudel commented Feb 27, 2015

Hi @Envek
i think this is what you want: #625.

@Envek Envek mentioned this issue Mar 2, 2015
@Envek
Copy link
Author

Envek commented Mar 2, 2015

Thanks a lot, this is exactly what I want!

@Jefiozie
Copy link
Contributor

As the PR #1845 is merged please verify if it fix your problem.

@Jefiozie
Copy link
Contributor

Jefiozie commented Feb 6, 2017

Closing it down due to comment above (believe this should fix it), if needed you can reopen it.
Thanks.

@Jefiozie Jefiozie closed this as completed Feb 6, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants