2012-09-26 19 views
10

Sto scrivendo un'app con EmberJS v1.0.pre. Ho uno ArrayController che contiene un elenco di tutte le persone. Ci sono un sacco di viste nidificate che mostrano la persona, i loro animali domestici e le note per ogni animale domestico.EmberJS Nested Views and Controllers

|----------------------------------------| 
| John         | <- Person 
|----------------------------------------| 
| Quincy (Dog)       | <- Pet 
|  - Super ornery      | <- Note 
|  - Likes XYZ Dog food    | 
|  - Will eat your socks    | 
|          | 
| Tom (Cat)       | 
| - Always (not) catching mice  | 
|          | 
|----------------------------------------| 
| Roger         | 
|----------------------------------------| 
| V (Dog)        | 
| - Likes XYZ Dog food    | 
| - Sneezes, but it's ok    | 
|          | 
|----------------------------------------| 
| ...         | 

Dal punto di vista MVC puro ci si sente come ci dovrebbe essere un controller per ogni bambino, ma non riesco a capire come ottenere che nel Ember. C'è il controller di array superiore e quindi tutte le singole visualizzazioni. Se voglio cancellare una nota, o modificarla, sembra che ho bisogno di passare il contesto della vista fino al controller.

// in the view 
click: function() { 
    this.get('controller').updateNote(this.get('content')) 
} 

Questo mi fa davvero male, la Vista non dovrebbe essere la fonte autorevole per i dati. La mia ipotesi è che un controller Array istanzia un itemControlerClass insieme allo itemViewClass.

UPDATE: Ho creato un fiddle per illustrare meglio il mio problema. La funzionalità è intenzionalmente incompleta, lo scopo è terminare la funzionalità aumentando il contenuto quando si fa clic su un elemento nell'elenco.

UPDATE: Mi dispiace, ho cancellato il violino in caso di incidente! Sto lavorando su una soluzione finale, quindi cercherò di creare un nuovo violino con la soluzione.

+0

Passare attraverso questo http://emberjs.com/guides/outlets/ –

+0

Non ci sono informazioni reali sulla guida in merito al mio problema. L'ho letto prima, e continuerò a riferirmi ad esso, ma non ho ancora trovato nulla. – noazark

+0

Dai un'occhiata a http://stackoverflow.com/questions/12595496/how-can-i-build-a-recursive-view-in-ember/12602743#comment17008361_12602743 –

risposta

12

"Dal punto di vista puro MVC ci si sente come ci dovrebbe essere un controller per ogni bambino"

Non avete bisogno di un controller per ogni articolo, ma invece un ArrayController per ogni collezione di oggetti (Persone, Animali domestici, Note). A proposito, qualsiasi azione sugli oggetti figlio (cani, note) non deve essere passata a App.PersonsController. Ciò spezzerebbe il principio Separation of Concerns.

I documenti Ember.Router coprono il caso in cui si desidera nidificare le viste in un singolo oggetto (ad esempio /:people_id). Ma vuoi nidificare le viste per una serie di oggetti. Non riesco a immaginare un modo per nidificare le viste {{outlet}}, ma è possibile effettuare le seguenti operazioni:

Caricare gli oggetti Persone, Animali domestici, Note in 3 controller di array e delegare le azioni sugli oggetti figlio al relativo controller di array Array corrispondente.

App.Router = Ember.Router.extend({ 
    root: Ember.Route.extend({ 
    route: '/', 
    persons: Ember.Route.extend({ 
     connectOutlets: function(router) { 

      router.get('applicationController').connectOutlet('persons'); 
      // App.Note.find() fetches all Notes, 
      // If you are not using ember-data, make sure the notes are loaded into notesController 
      router.set('notesController.content', App.Note.find()); 
      router.set('petsController.content', App.Pet.find()); 
     } 
    }) 
    }) 
}); 

E poi il modello people dovrebbe essere simile:

{{#each person in people}} 
    <h1>My name is {{person.name}}</h1> 

    {{#each pet in person.pets}} 
    I have a pet with name {{pet.name}} 
    <a {{action delete pet target="App.router.petsController">Delete pet</a> 
    {{/each}}  

    {{view Ember.TextField valueBinding="myNewPetName" type="text"}} 
    <a {{action create myNewPetName person target="controller"}}> 
    Add a new pet for this person 
    </a> 


    {{#each note in person.notes}} 
    <!-- delete, create, edit ... --> 
    {{/each}} 

Come si può vedere, le azioni sugli oggetti figlio sono delegate al suo controllore (pet -> petsController), passando l'oggetto come il contesto. Nel caso dell'azione create, il controllore deve sapere a quale persona l'animale domestico belongsTo. Quindi passiamo in 2 contesti: la persona e le proprietà dell'animale domestico (per semplicità ho assunto solo un nome per l'animale domestico).

Nei tuoi App.petsControllers si dovrebbe avere azioni lungo le linee:

App.PetsController = Ember.ArrayController.extend({ 
    delete: function(e) { 
    var context = e.context; 
    this.get('content').removeObject(context); 
    // Also, if you use ember-data, 
    // App.Pet.deleteRecord(context); 
    }, 

    create: function(e) { 
    var petName = e.contexts[0] 
    var person = e.contexts[1]; 
    this.get('content').pushObject({name: petName, person: person}); 
    // with ember-data: 
    // App.Pet.createRecord({name: petName, person: person}); 
    } 
}); 
+1

Questo è facilmente l'esempio più completo che ho visto del mio problema, grazie! Prenderò questa risposta e correrò con essa. Ci sono alcuni problemi che ho ancora bisogno di affrontare però. Passare il contesto dalla vista è il mio reclamo originale a questo problema, ma sembra inevitabile. Inoltre, i controllori non possono essere semplicemente impostati su tutte le note, poiché sono figli di animali (letteralmente incorporati) e uguali a quelli di animali domestici e persone. Per me, questo non sembra un problema architettonico. Dovrò prima impostare il contesto genitore, suppongo. Aggiornerò la mia domanda con qualsiasi altra cosa scopro. Grazie ancora. – noazark

1

Dovresti utilizzare le prese. Sono piccoli "segnaposto" nelle viste d'argento che possono essere gestiti con diversi controller.

C'è una spiegazione chiara su di loro sul link sopra, dove hai già controllato e non trovato nulla. Ma prima di tornare a quello, leggere prima questo: http://trek.github.com/

Se uno di questi ancora non ti aiuta, fallo sapere e io metterò insieme un esempio per te.

+0

Ho letto entrambi gli articoli, anche prima del mio post. Sto anche utilizzando i punti vendita, tuttavia gli outlet non delegano la responsabilità del contenuto a un controller separato. Grazie per la vostra offerta di mettere insieme un esempio, mi piacerebbe vederne uno. Sbatterò anche qualcosa su jsfiddle per spiegare meglio il mio problema. – noazark

+0

Ho aggiornato la mia domanda con un [violino] (http://jsfiddle.net/noazark/HmHK3/). Grazie per il tuo aiuto continuo. – noazark

1

Penso che this sia quello che stai cercando, dai un'occhiata, è piuttosto semplice, puoi anche controllare l'esempio this. Fondamentalmente puoi ottenere ciò che vuoi con punti vendita, router e azioni per connettere tutti i tuoi punti vendita.

+0

Prenderò un'altra pugnalata. Anche questo articolo, https://gist.github.com/3002177, è stato di grande aiuto. Penso che il mio problema abbia usato l'ArrayController. Quando dovrebbe essere solo un controller con prese? Ha senso? – noazark

+0

Qualche possibilità di fornire un esempio diverso, più pertinente? Quello che hai fornito non ha alcun parallelo alla mia domanda. Nello specifico, il mio problema non riguarda il routing, ma la delega del controllo alle risorse nidificate. Gli outlet sono interessanti, ma anche con tutti i suggerimenti per usarli, non c'è ancora un esempio utile di come risolvono il mio problema. – noazark

0

Sono nuovo di Ember e sono state cercando un modo per fare qualcosa di simile. Nel ArrayController di livello superiore, ho solo usato la proprietà itemController e ha funzionato grande:

App.PeopleController = Ember.ArrayController.extend({ 
    itemController: "Person" 
}); 

App.PersonController = Ember.ObjectController.extend //... 

La mia soluzione completa è in this js fiddle. Sfortunatamente, il modo in cui riesco a far funzionare le istanze PetController mi sembra intrusivo.

+0

Gli aggiornamenti da v1.0pre sono stati super utili e ho avuto molta più fortuna. Scaverò ulteriormente in quello che hai fatto e vedremo come va! – noazark