2015-09-16 11 views
6

Ember 2.0 ha fatto di tutto per rendere tutto un componente. Con componenti routable in arrivo, anche i controller saranno gradualmente eliminati.Dove memorizzare lo stato dell'interfaccia utente transitoria in Ember 2.0

Contesto

Tuttavia, v'è un problema ricorrente mi trovo di fronte quando si costruisce interfaccia utente, che non ho un modello soddisfacente per finora: stato di interfaccia utente.

Cosa sto prendendo in giro?

  • stato selezione
  • fuoco attuale
  • piegato/foglio spiegato in qualche visualizzazione albero

Fondamentalmente, qualsiasi Stato che non fa parte dei dati effettivi, tuttavia deve essere monitorato su un base oggetto per oggetto. In passato, ciò avveniva con Controllers, che fungeva da proxy per i modelli. Questo approccio è ormai obsoleto. Il nuovo approccio è Components ovunque, per il meglio. Componente esegue la contabilità, tiene traccia dello stato transitorio e ripristina le azioni.

Un modello tipico che ho, però, è con stato condiviso, come una lista con voci selezionabili.

La questione

Costruire un componente di lista, con i seguenti requisiti:

  • Ogni voce può essere selezionata.
  • Lo stato di selezione modifica il DOM (alcuni collegamenti di classi).
  • L'utente può disegnare un rettangolo nel componente elenco per selezionare diversi elementi contemporaneamente.
  • Idealmente, l'intero comportamento può essere estratto come un mixin.

Domanda: dove si trova la bandiera di selezione?

Tentativi

1) Tutto è un componente.

Faccio a ciascun elemento un sottocomponente, diciamo {{my-list-item}}. Il componente tiene traccia dello stato di selezione. Problema: come può il componente dell'elenco aggiornare lo stato di selezione?

2) Spostare lo stato fuori dai componenti secondari.

Inserirlo nel componente dell'elenco. All'interno di un array di stati separato accanto all'elenco degli elementi. Pro: la lista ha tutto lo stato di cui ha bisogno. Contro: è un incubo mantenerlo sincronizzato quando gli oggetti vengono aggiunti o rimossi dalla lista. E significa che il sottocomponente non ha accesso allo stato. O forse potrei passarlo a loro come valore vincolato?

3) Reintroduzione di proxy.

Venendo a pensarci, c'è un modo per condividere qualche stato: mettilo sui modelli.Bene, non sui modelli attuali per non inquinarli con lo stato locale, ma impostando un ArrayProxy che restituirà un po 'di ObjectProxy per ogni oggetto, per mantenere lo stato.

Pro: questa è l'unica soluzione che sono riuscito a implementare completamente. Contro: incapsulamento e decapsulazione di oggetti è una seccatura. Inoltre, dopo aver passato alcuni strati, get e set devono passare attraverso 4 o 5 proxy, che temo rappresentino un problema con le prestazioni.

Inoltre, non funziona bene per i mix. Se voglio astrarre alcuni mix HasSelection e un mix HasFoldableItems e un mix Sortable, tutti hanno bisogno di un certo stato.

Torna al tavolo da disegno

C'è qualche motivo meglio non ho trovato?

ho trovato le seguenti domande pertinenti, ma che mi ha portato da nessuna parte:

+1

Toran è sulla buona strada, quando lo stato diventa troppo complesso per i singoli componenti da gestire, estrae lo stato dall'interfaccia utente e lo attacca su un servizio. Ho scritto un commento a questo proposito qui: http://www.samselikoff.com/blog/comment-on-data-flow-in-ember-apps/ –

risposta

7

Ottima domanda: in realtà sono andato da uno dei membri del team ember di base per scoprire e la risposta al momento è servizi. Poiché il componente è il migliore a sinistra stateless (per la maggior parte) è possibile sfruttare un servizio per mantenere questo stato che non si adatta a un modello persistente del server.

Ecco un grande esempio che Stef Penner messo insieme mostrando come si potrebbe salvare una "bozza di e-mail" nel brace app (che back-end non viene mantenuto) componente

https://github.com/stefanpenner/ember-state-services

Esempio di riferimento (dal progetto github in alto)

export default Ember.Component.extend({ 
    tagName: 'form', 
    editEmailService: Ember.inject.service('email-edit'), 
    state: Ember.computed('email', function() { 
    return this.editEmailService.stateFor(this.get('email')); 
    }).readOnly(), 

    actions: { 
    save() { 
     this.get('state').applyChanges(); 
     this.sendAction('on-save', this.get('email')); 
    }, 

    cancel() { 
     this.get('state').discardChanges(); 
     this.sendAction('on-cancel', this.get('email')); 
    } 
    } 
}); 
+0

Leggendo la situazione dei servizi statali in questo momento. Questo approccio sembra molto buono, fondamentalmente i componenti condivideranno lo stato quando usano lo stesso 'stateName'. Tuttavia, sembra che lo stato Nome debba essere predefinito, il che significa che tutte le istanze dello stesso componente condivideranno lo stesso stato. Ma vedo come sarebbe possibile aggiungere un livello di riferimento indiretto (avere solo un servizio, che può creare al volo nuovi nomi di stato). Questo approccio è migliore di tutti i 3 che ho avuto nella mia domanda. Tuttavia, vorrei lasciare aperta la domanda per un po 'per vedere se altri sorgono. – spectras

+0

OK. Il modulo appuntito ha un ottimo concetto. Questo dovrebbe davvero andare da qualche parte sul tutorial ember.js. Non si adattava perfettamente al caso d'uso in quanto è mirato allo stato dell'interfaccia utente a lungo termine che non richiede alcuna gestione del ciclo di vita, ma potrei basarmi sull'idea: ho fatto allo store di stato un oggetto, che il componente genitore inietta (attraverso un attr) nei sottocomponenti. ** Contro **: non è più un singleton, quindi forse rompe un po 'l'idea. ** Pro **: Posso accoppiare la durata del componente e dello stato, il che ha senso qui. – spectras

+0

@spectras Qualche possibilità potresti fornire una risposta separata con la tua soluzione? – Jon