Fabian Fabian - 1 year ago 181
Dart Question

How to have change detection with material-dropdown-select if using a SelectionOptions

I have the following implementation of a material-dropdown-select and it works beautifully.

<material-dropdown-select [buttonText]="organizer?.name">
<material-select-item *ngFor="let sailingClub of sailingClubs"
{{sailingClub.name}}
</material-select-item>
</material-dropdown-select>


My data is coming from this property:

Iterable<SailingClub> get sailingClubs => _store.state.sailingClubs.values;


The nice thing about it is that the items automatically update once the backend (firebase) adds new items to the list.

Now I want to change it to use the searchable dropdown.
For this I have to convert the data into SelectionOptions and with that I have problems. Everything works fine but I no longer get the change detection.
It is not really surprising since I now have to create a static SelectionOptions instance and that is the only thing I am handing to the view component.

<material-dropdown-select [buttonText]="organizer?.name"
[options]="filteredSailingClubs"
[itemRenderer]="displayNameRenderer">
<div header>
<material-select-searchbox
label="Search..."
[filterable]="filteredSailingClubs">
</material-select-searchbox>
</div>
</material-dropdown-select>


and this is how I create the filteredSailingClubs

filteredSailingClubs = new StringSelectionOptions(_store.state.sailingClubs.values, toFilterableString: displayNameRenderer);


and access the name property

ItemRenderer<SailingClub> displayNameRenderer = (SailingClub item) => item.name;

Answer Source

Ok here is my final solution. It is not really great in my opinion since it still requires quite some code but at least it works very well. The main reason for the amount of code is that the map.values list itself is not stable. So each new comparison of map.values with the old values would return true. Even if the map is unchanged. Therefore we have to save the original map.

StringSelectionOptions<SailingClub> _filteredSailingClubs;
Map<String, SailingClub> _oldSailingClubs;
SelectionModel<SailingClub> _singleSelectModel;
SailingClub _oldOrganizer;
StreamSubscription _selectionListener;

StringSelectionOptions<SailingClub> get filteredSailingClubs {
  // We have to save the old state since the Iterable itself is unstable and would change all the time
  if (_oldSailingClubs != _store.state.sailingClubs) {
    _oldSailingClubs = _store.state.sailingClubs;
    _filteredSailingClubs =
      new StringSelectionOptions(_store.state.sailingClubs.values, toFilterableString: displayNameRenderer);
  }
  return _filteredSailingClubs;
}

SelectionModel<SailingClub> get singleSelectModel {
  // We have to update the selection model on organizer change
  if (_singleSelectModel == null || _oldOrganizer != organizer) {
    _oldOrganizer = organizer;
    _singleSelectModel = new SelectionModel<SailingClub>.withList(selectedValues: [organizer]);
    _selectionListener?.cancel();
    _selectionListener = _singleSelectModel.selectionChanges.listen(update);
  }
  return _singleSelectModel;
}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download