2012-01-11 17 views
5

Sto utilizzando Ember, Dati di bordo e Manubri per visualizzare una sequenza temporale con un numero di tipi diversi di modelli. La mia attuale implementazione, benché funzioni correttamente, sembra che potrebbe essere drasticamente migliorata con una convenzione e un aiuto. Tuttavia, non riesco a capire come utilizzare i modelli già definiti.Scegliere dinamicamente una vista in fase di esecuzione con Ember + Handlebars

Questo è quello che ho:

{{#view App.AccountSelectedView contentBinding="App.selectedAccountController.everythingSorted"}} 
    {{#with content}} 
    <ol class="timeline"> 
     {{#each this}} 
     {{#is constructor="App.Design"}} 
     ... stuff about the design 
     {{/is}} 
     {{#is constructor="App.Order"}} 
     ... stuff about the order 
     {{/is}} 
     {{#is constructor="App.Message"}} 
     ... stuff about the message 
     {{/is}} 
     {{/each}} 
    </ol> 
    {{/with}} 
{{/view}} 

... insieme a un aiutante ...

Handlebars.registerHelper('is', function(options) { 
    if (this.constructor == options.hash["constructor"]) { 
    return options.fn(this); 
    } 
}); 

avrei preferito fare affidamento su qualche convenzione per capire cosa vista per il rendering. Ad esempio:

<script type="text/x-handlebars-template" data-model="App.Design" id="design-view"> 
... stuff about the design 
</script> 

<script type="text/x-handlebars-template" data-model="App.Order" id="order-view"> 
... stuff about the order 
</script> 

Forse l'attributo del modello di dati potrebbe essere utilizzato per determinare come viene eseguito il rendering di un oggetto.

{{#view App.SelectedAccountView contentBinding="App.selectedAccountController.everythingSorted"}} 
    {{#with content}} 
    <ol class="timeline"> 
     {{#each this}} 
     {{viewish this}} 
     {{/each}} 
    </ol> 
    {{/with}} 
{{/view}} 

Purtroppo, non riesco a capire come accedere ai modelli da un helper.

Handlebars.registerHelper('viewish', function(options) { 
    // Were I able to access the templates this question 
    // would be unnecessary. 
    // Handlebars.TEMPLATES is undefined... 
}); 

Inoltre, è qualcosa che dovrei voler fare con Handlebars?

risposta

1

Questo è appena fuori dalla mia testa: vorrei creare un modello/vista separata per ogni tipo di modello. Per esempio. ci sarebbe un DesignView, OrderView, ecc Ognuno di questi sarebbe specificare il modello da utilizzare con templateName (tutto il codice CoffeeScript):

App.DesignView = Em.View.extend 
    templateName: 'design' 

App.OrderView = Em.View.extend 
    templateName: 'order' 

Tutto il rendering personalizzato per ogni tipo sarebbe stato fatto all'interno della vista/template .

A questo punto è necessario disporre di alcuni modelli logici per decidere quale vista mostrare per ciascun elemento. La cosa più semplice da fare sarebbe quella di memorizzare viewType sul modello.

App.Design = Em.Model.extend 
    viewType: App.DesignView 

App.Order = Em.Model.extend 
    viewType: App.OrderView 

Poi il modello potrebbe apparire come:

{{#collection contentBinding="App.selectedAccountController.everythingSorted"}} 
    {{view content.viewType contentBinding="content"}} 
{{/collection}} 

Questo non è l'ideale, però, dal momento che non vogliamo il modello da sapere sul livello della vista. Invece, potremmo creare una logica di fabbrica per creare una vista per un modello. Allora potremmo creare una proprietà calcolata sul controller, che contiene una serie di modelli e il loro parere corrispondenti:

App.selectedAccountController = Em.ArrayController.create 
    .. 
    viewForModel: (model) -> 
    # if model is instance of Design return DesignView, Order return OrderView etc. 
    everythingSortedWithViews: (-> 
    everythingSorted.map (model) -> 
     {model: model, viewType: @viewForModel(model)} 
).property('everythingSorted') 

Il modello sarebbe quindi simile a questa:

{{#collection contentBinding="App.selectedAccountController.everythingSortedWithView"}} 
    {{view content.viewType contentBinding="content.model"}} 
{{/collection}} 

Ci sono modi probabilmente meglio Fai questo. Mi piacerebbe sentire qualcuno che è più vicino al nucleo di Ember dare una soluzione.

4

Ho risolto questo stabilendo la mia convenzione con un mixin. Un modello corrisponde a una vista con un nome simile. Ad esempio, un'app.L'istanza del modello di progettazione corrisponde alla vista App.DesignView.

App.ViewTypeConvention = Ember.Mixin.create({ 
    viewType: function() { 
    return Em.getPath(this.get('constructor') + 'View'); 
    }.property().cacheable() 
}); 

Mescolo questo nei miei modelli ...

App.Design.reopen(App.ViewTypeConvention); 
App.Order.reopen(App.ViewTypeConvention); 

... e iterare su una collezione mista come questo:

{{#each content}} 
    {{view item.viewType tagName="li" contentBinding="this"}} 
{{/each}} 

In questo modo, evito di definire la convenzione esplicitamente nei miei modelli. Grazie a Gordon, mi sono reso conto che la vista poteva essere specificata usando una proprietà su un oggetto. Mi piacerebbe davvero sentire parlare del modo "giusto" per risolvere questo problema.

1

Questo è quello che ho usato per uno scenario simile.

Modello 'pagina' haMolte 'attività'.

// App.PageModel 
export default DS.Model.extend({ 
    index  : DS.attr('number'), 
    activity : DS.hasMany('activity', { async: true }) 
}); 

Model 'attività' ha proprietà 'tipo' che i riferimenti che modello da utilizzare per il contenuto in un'altra proprietà 'configurazione'.

// App.ActivityModel 
export default DS.Model.extend({ 
    activityId : DS.attr('string'), 
    type   : DS.attr('string'), 
    page   : DS.belongsTo('page', { async: true }), 
    configuration : DS.attr() 
}); 

Nota la mancanza di tipo di attributo per la configurazione. Questo offre i mezzi per archiviare una collezione di oggetti strutturati casualmente. Per oggetti strutturati in modo coerente, suggerisco di utilizzare Ember-Data.Model-Fragments.

template Main:

{{! page.hbs }} 
{{#with activity}} 
    {{#each}} 
     {{partial type}} 
    {{/each}} 
{{/with}} 

Per il tipo: 'statica', utilizza il {{{3 opzione baffi}}} per rendere una stringa HTML.

{{! static.hbs }} 
{{{configuration.content}}} 

Le altre opzioni sono molto più complesse, ma ancora semplificate utilizzando un "con". vale a dire: per il tipo: 'scelta multipla',

{{! multiplechoice.hbs }} 
{{#with configuration}} 
    {{#each options}} 
    <label {{bind-attr class=":label selected:checked:unchecked"}}> 
     {{view Ember.Checkbox checkedBinding="selected" }} 
     {{#if text.content}} 
      {{{text.content}}} 
     {{else}} 
      {{text}} 
     {{/if}} 
    </label> 
    {{/each}} 
    {{ ...etc... }} 
{{/with}} 

Con i parziali, ricordarsi di considerare nomenclatura e/o struttura di cartelle a seconda dell'ambiente, vale a dire '_partialname.hbs' o 'ViewName/partialname.hbs'

Problemi correlati