2017-09-09 1 views
2

J'ai la mise en œuvre suivante d'un matériel-dropdown-select et il fonctionne magnifiquement.Comment avoir la détection de changement avec matériel-dropdown-sélectionnez si vous utilisez un SelectionOptions

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

Mes données proviennent de cette propriété:

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

La bonne chose à ce sujet est que les éléments sont mis à jour automatiquement une fois que le back-end (firebase) ajoute de nouveaux éléments à la liste.

Maintenant, je veux le changer pour utiliser la liste déroulante interrogeable. Pour cela, je dois convertir les données en SelectionOptions et avec cela j'ai des problèmes. Tout fonctionne bien mais je n'ai plus la détection de changement. Ce n'est pas vraiment surprenant puisque je dois maintenant créer une instance de SelectionOptions statique et c'est la seule chose que je transmets au composant de vue.

<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> 

et voilà comment je crée les filteredSailingClubs

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

et accéder à la propriété Nom

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

Je n'ai pas encore utilisé Firebase et je ne sais pas quel type de valeur il renvoie. Je pense que vous devez écouter les mises à jour, puis faire quelque chose comme 'filteredSailingClubs.optionGroups = [new OptionGroup (_store.state.sailingClubs.values)])' –

+0

Deux questions rapides: Est-ce que votre objet magasin a un moyen d'écouter changements à cela? Quelque chose comme classe magasin { flux get onStoreChanged => ... } Et est la propriété 'sailingClubs' de l'état d'une carte, Liste, ou autre chose? –

+0

Quelle stratégie de détection de changement utilisez-vous? Cela fonctionne-t-il si vous le changez? –

Répondre

0

Ok, voici ma solution finale. Ce n'est pas vraiment génial à mon avis car il faut encore du code mais au moins ça marche très bien. La raison principale de la quantité de code est que la liste map.values ​​elle-même n'est pas stable. Ainsi, chaque nouvelle comparaison de map.values ​​avec les anciennes valeurs retournera true. Même si la carte est inchangée. Par conséquent, nous devons enregistrer la carte originale.

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; 
} 
1

écoutez-vous à votre base de données Firebase des changements?

Je ne sais pas exactement ce que _store ou l'une de ses propriétés sont, mais à partir d'une base de données Firebase DatabaseRef, vous pouvez écouter les changements et mettre à jour vos options de sélection. La détection de changement devrait alors détecter que les options de sélection ont changé.

sailingClubsRef.onValue((value) { 
    filteredSailingClubs = new StringSelectionOptions(
    value.snapshot.val(), 
    toFilterableString: displayNameRenderer, 
); 
}); 
+0

J'ai maintenant ajouté une réponse pour montrer mon approche actuelle. Mon magasin lui-même est un magasin Redux qui n'a aucune connaissance de l'interface graphique. Et le callback Firebase ne sait rien sur le gui et par ex. StringSelection. Il crée juste un nouvel événement en envoyant un changement au magasin. Cela fonctionne très bien pour tous les composants graphiques, y compris la liste déroulante, sauf si je dois utiliser l'API de recherche. – Fabian

1

Voici ma position actuelle, approche. L'afficher comme une réponse pour une meilleure lisibilité.

J'ai d'abord dû ajouter de nouvelles variables pour les valeurs calculées et garder une trace des changements manuellement.

StringSelectionOptions<SailingClub> filteredSailingClubs; 
SelectionModel<SailingClub> singleSelectModel; 
Map<String, SailingClub> oldSailingClubs; 
SailingClub oldOrganizer; 

Ensuite, dans le constructeur de mon composant, je peux créer le filterSailingClubs. Mais cette StringSelection sera vide car à ce moment toutes les options ne sont pas chargées à partir de Firebase.

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

et pour pouvoir enfin mettre à jour le FilterSailingClubs que j'ai dû ajouter.

void ngDoCheck() { 
    if (oldSailingClubs != _store.state.sailingClubs) { 
    oldSailingClubs = _store.state.sailingClubs; 
    filteredSailingClubs = 
     new StringSelectionOptions(_store.state.sailingClubs.values, toFilterableString: displayNameRenderer); 
    } 
    if (oldOrganizer != organizer) { 
    oldOrganizer = organizer; 
    singleSelectModel = new SelectionModel<SailingClub>.withList(selectedValues: [organizer]); 
    singleSelectModel.selectionChanges.listen(update); 
    } 
} 

et est encore un rappel ici qui me permet de mettre à jour une valeur lorsque la sélection a changé dans l'IUG

void update(List<SelectionChangeRecord> record) { 
    if (record.isNotEmpty && record.first.added.isNotEmpty) { 
    onOrganizerChanged(record.first.added.first); 
    } 
} 

Malheureusement, c'est beaucoup de code de plaque de la chaudière juste pour faire la liste des recherches. Avant toute la détection de changement a été traitée par Angular et complètement caché. Par conséquent, je me demande si je le fais mal.

Je ne veux pas non plus changer la structure de mon magasin. Il s'agit essentiellement d'un magasin de modèles redux (utilisant greencat) et est immuable. Je ne veux pas non plus que mon magasin sache quoi que ce soit à propos de l'interface graphique ou par exemple. un modèle de sélection, etc.

Ma prochaine étape serait de dériver de la liste déroulante matérielle-sélectionner elle-même et voir si je peux cacher la complexité là-bas.

+0

Pourquoi avez-vous besoin d'une instruction try et pourquoi ne consignez-vous pas ce qu'elle saisit? L'avez-vous omis ici pour la brièveté? Vous devez annuler les abonnements précédents à selectionChanges avant de créer un nouveau modèle et un nouvel abonnement, cela pourrait être l'un des problèmes de votre code. –

+0

Merci pour l'indice avec l'annulation des abonnements précédents, je vais mettre en œuvre cela. La raison de l'essai est que l'organisateur peut être nul, donc j'ai besoin de meilleurs contrôles pour cette condition, je viens d'ajouter la prise d'essai pour une preuve de concept rapide. Mais ce n'est pas le problème avec mon code. Le problème est de savoir comment rendre la liste déroulante des matériaux sensible aux changements. Ma solution fonctionne mais c'est tellement le code de plaque de chaudière :-( – Fabian