2012-04-06 15 views
1

Ich habe folgendes Modell:Bindung an ein verschachteltes Modell in Ember.js

App.Checklist = DS.Model.extend({ 
    name: DS.attr('string'), 
    checkitems: DS.hasMany('App.Checkitem', { embedded: true }), 

    remainingItemsCount: function() { 
    var checkitemsToCount = this.get('checkitems'); 
    return checkitemsToCount.filterProperty('isDone', false).get('length'); 
    }.property() 

}); 

ich will, um eine Liste von Checklisten zur Anzeige mit einer Zählung der aktuellen checkitems für jede Liste offen bleibt.

Wenn ich folgendes in eine Vorlage fallen, erhalte ich die richtige Ausgabe:

{{#each checklists}} 
    {{this.name}} 
    {{this.remainingItemsCount}} 
{{/each}} 

Wenn jedoch eine neue CheckItem zu einer Checkliste hinzugefügt wird, wird die Zählung nicht steigen.

ABER, wenn ich die berechnete remainingItemsCount Eigenschaft in dem Checklist-Modell ändern, so dass es auf [email protected] abhängt, dann wird die Zählung erhöht, wenn neue Checkitems hinzugefügt werden.

Das Problem ist, dass, sobald diese Abhängigkeit hinzugefügt wird, die Sammlung von untergeordneten checkitems falsch ist - es wiederholt das erste checkitem für die Anzahl der gesamten checkitems (dh wenn es fünf Elemente gibt, für die isDone falsch ist und vier, für die 'isDone' wahr ist, dann erscheint die Liste als 9, und das erste checkitem wird 9 mal wiederholt).

Was mache ich falsch?

UPDATE:

Es stellt sich heraus, dass die Abhängigkeit der remainingItemsCount Eigenschaft Hinzufügen verursacht glut-Daten einen neuen Aufruf an den Server zu machen.

Ohne die Abhängigkeit, werden die folgenden XHR-Anforderungen auf Seite Last gemacht:

GET http://localhost:3000/checklists 

Mit der Abhängigkeit werden auf Seite laden folgende XHR Anfragen:

GET http://localhost:3000/checklists 
GET http://localhost:3000/checkitems 

Die letzte Anfrage kommt mit den folgenden Parametern, die eine Darstellung des ersten Check-Items zu sein scheinen, eingewickelt in einem "IDs" -Hash:

Ich frage mich, ob dies daran liegt, dass das Modell checkitem mit einem Attribut "answerTo" definiert ist?

App.Checkitem = DS.Model.extend({ 
    title: DS.attr('string'), 
    isDone: DS.attr('boolean'), 
    checklist: DS.belongsTo('App.Checklist') 
}); 

UPDATE 2

Ich bin noch nicht sicher, warum, aber es ist klar, dass auf die Eigenschaft, die die Abhängigkeit Zugabe wie folgt ...

remainingItemsCount: function() { 
    var checkitemsToCount = this.get('checkitems'); 
    return checkitemsToCount.filterProperty('isDone', false).length; 
}.property('[email protected]').cacheable() 

... verursacht ember -datas eingebauter DS.RESTAdapter zum Aufruf von findMany. Die Anfrage findMany sollte ein Array von IDs verwenden, stattdessen wird ein Array mit einem gesamten checkitem-Objekt, das in einem Hash mit dem Schlüssel 0 verschachtelt ist, an dieses übergeben.

SOLUTION

Am Ende habe ich verfolgt das Problem auf den folgenden Beobachter tief in glut-Daten:

dataDidChange: Ember.observer(function() { 
    var associations = get(this.constructor, 'associationsByName'), 
     data = get(this, 'data'), store = get(this, 'store'), 
     idToClientId = store.idToClientId, 
     cachedValue; 

    associations.forEach(function(name, association) { 
     if (association.kind === 'hasMany') { 
     cachedValue = this.cacheFor(name); 

     if (cachedValue) { 
      var ids = data.get(name) || []; 
      var clientIds = Ember.ArrayUtils.map(ids, function(id) { 
      return store.clientIdForId(association.type, id); 
      }); 

      set(cachedValue, 'content', Ember.A(clientIds)); 
      cachedValue.fetch(); 
     } 
     } 
    }, this); 
    }, 'data') 

Zu der Zeit, dass Beobachter an der Linie return store.clientIdForId(association.type, id) bekam, das Array ids war ein Array von checkitem-Objekten, kein Array von id-Integern. Das Update war ziemlich einfach: return store.clientIdForId(association.type, id.id) gibt ein Array von ID-Ganzzahlen zurück.

Antwort

2

Ich erstellte eine JSFiddle aus Ihrer Beschreibung und konnte Ihr Problem nicht reproduzieren. Ich verwende Ember.js 0.9.6 und die neueste Version von Ember-Daten siehe http://jsfiddle.net/pangratz666/dGjyR/

Lenker:

<script type="text/x-handlebars" data-template-name="checklist" > 
    {{#each checklists}} 
     {{this.name}} 
     remaining: {{this.remainingItemsCount}} 
     {{#each checkitems}} 
     {{view Ember.Checkbox valueBinding="isDone"}} 
     {{/each}} 
     <a {{action "addCheckitem"}} class="clickable">add item</a> 
     <hr/> 
    {{/each}} 

</script>​ 

JavaScript:

App = Ember.Application.create({}); 

App.Checkitem = DS.Model.extend({ 
    isDone: DS.attr('boolean') 
}); 

App.Checklist = DS.Model.extend({ 
    name: DS.attr('string'), 

    checkitems: DS.hasMany('App.Checkitem', { 
     embedded: true 
    }), 

    remainingItemsCount: function() { 
     var checkitemsToCount = this.get('checkitems'); 
     return checkitemsToCount.filterProperty('isDone', false).get('length'); 
    }.property('[email protected]').cacheable() 
}); 

App.store = DS.Store.create({ 
    revision: 4 
}); 

App.checklistsController = Ember.ArrayProxy.create({ 
    content: App.store.find(App.Checklist) 
}); 

Ember.View.create({ 
    templateName: 'checklist', 
    checklistsBinding: 'App.checklistsController', 
    addCheckitem: function(evt) { 
     var checklist = evt.context; 
     checklist.get('checkitems').addObject(App.Checkitem.createRecord({ 
      isDone: false 
     })); 
    } 
}).append(); 


var checklist = App.Checklist.createRecord({ 
    name: 'firstChecklist' 
}); 

App.Checklist.createRecord({ 
    name: 'secondChecklist' 
}); 

checklist.get('checkitems').addObject(App.Checkitem.createRecord({ 
    isDone: false 
})); 
checklist.get('checkitems').addObject(App.Checkitem.createRecord({ 
    isDone: true 
})); 
checklist.get('checkitems').addObject(App.Checkitem.createRecord({ 
    isDone: true 
}));​ 
+0

Das hat mir sehr geholfen! Vielen Dank. Es stellt sich heraus, dass das Hinzufügen der Abhängigkeit dazu führt, dass die ember-Daten die URL des "/ checkitems" des Servers mit einem Hash aufrufen, der eines der checkitems darstellt. Ich habe keine Ahnung warum, aber das ist mit ziemlicher Sicherheit der Grund, warum der ArrayProxy von Checkitems falsch auftaucht. – sirvine

+0

Ich frage mich, ob dies daran liegt, dass das Checkitem-Modell ein 'checklist: DS.belongsTo ('App.Checklist') 'Attribut hat. Ich kann nicht herausfinden, warum der Server angerufen werden würde. Ich habe nie eine URL für das Checkitem DS.Model gesetzt. – sirvine

+0

Aber Sie verwenden einen 'DS.RESTAdapter'? Da diese Ihre URL automatisch abbildet. Vielleicht bekommst du deswegen einen Anruf auf deinen Server. – pangratz

Verwandte Themen