2014-02-12 8 views
6

Ich versuche, den {{#each}} Helfer über ein Objekt zu iterieren, wie in Vanilla-Lenker. Leider, wenn ich auf einem Objekt verwenden #each Ember.js Version gibt mir diese Fehlermeldung:Wie kann ich Ember.js Lenker machen #ach jedem Objekt iterieren?

Assertion failed: The value that #each loops over must be an Array. You passed [object Object]

ich in Versuch, diese Helfer schrieb diese zu beheben:

Ember.Handlebars.helper('every', function (context, options) { 
    var oArray = []; 
    for (var k in context) { 
    oArray.push({ 
     key : k, 
     value : context[k] 
    }) 
    } 
    return Ember.Handlebars.helpers.each(oArray, options); 
}); 

Jetzt, wenn ich versuche, verwenden {{#every}}, erhalte ich folgende Fehlermeldung:

Assertion failed: registerBoundHelper-generated helpers do not support use with Handlebars blocks.

Dieses wie ein Grundzug scheint, und ich Ich weiß, dass ich etwas Offensichtliches vermisse. Kann jemand helfen?

bearbeiten:

Hier ist eine Geige:

Ember.Handlebars.registerHelper('every', function(context, options) { 
    var oArray = [], actualData = this.get(context); 

    for (var k in actualData) { 
    oArray.push({ 
     key: k, 
     value: actualData[k] 
    }) 
    } 

    this.set(context, oArray); 
    return Ember.Handlebars.helpers.each.apply(this, 
     Array.prototype.slice.call(arguments)); 
}); 

Ich weiß nicht: http://jsfiddle.net/CbV8X/

Antwort

2

Nachdem sie mit ihm für ein paar Stunden das Hantieren, ich mit diesem hacky Weg kam Welche Auswirkungen this.set hat, aber das scheint zu funktionieren!

Hier ist eine Geige: http://jsfiddle.net/CbV8X/1/

+1

Leider Sie gehen auf Probleme stoßen, wo es nicht sehen wird, oder zu aktualisieren ... http://jsfiddle.net/CbV8X/2/ – Kingpin2k

+0

Gibt es eine Möglichkeit, es richtig zu binden, @ Kingpin2k? – lxe

+1

Leider nein, es gibt keine integrierte Funktionalität, die besagt, dass alle Eigenschaften eines Objekts überwacht werden, was zur Implementierung dieser Art von Funktionalität erforderlich wäre – Kingpin2k

1

ich nach ähnlicher Funktionalität bin, und da wir unsere hacky Wege teilen, hier ist meine Geige für Ungeduldige: http://jsfiddle.net/L6axcob8/1/

Diese Geige auf dem einen basieren von @lxe bereitgestellt, mit Updates von @ Kingpin2k und dann von mir selbst.

Ember: 1.9.1, Lenker: 2.0.0, jQuery 2.1.3


Hier haben wir einen Helfer hinzufügen every genannt, die über Objekte und Arrays laufen kann.

Zum Beispiel dieses Modell:

model: function() { 
    return { 
     properties: { 
      foo: 'bar', 
      zoo: 'zar' 
     } 
    }; 
} 

kann mit dem folgenden Lenker Vorlage wiederholt werden:

<ul class="properties"> 
    {{#every p in properties}} 
    <li>{{p.key}} : {{p.value}}</li> 
    {{/every}} 
</ul> 

every Helfer funktioniert durch ein Array von den Objekten Schlüssel erstellen und dann die Koordination ändert sich in Ember über einen ArrayController. Ja, hacky. Dies erlaubt uns jedoch, Eigenschaften zu einem Objekt hinzuzufügen/davon zu entfernen, vorausgesetzt, dass das Objekt die Beobachtung der Eigenschaft [] unterstützt.

In meinem Anwendungsfall habe ich eine Ember.Object abgeleitete Klasse, die [] benachrichtigt, wenn Eigenschaften hinzugefügt/entfernt werden. Ich würde empfehlen, Ember.Set für diese Funktionalität zu betrachten, obwohl ich sehe, dass Set vor kurzem veraltet war. Da dies etwas außerhalb des Aufgabenbereichs liegt, überlasse ich es dem Leser als Übung.Hier ein Tipp: setUnknownProperty


Um von Eigenschaftsänderungen benachrichtigt werden wir nicht-Objektwerte wickeln, was ich ein DataValueObserver genannt haben, die einrichtet (zur Zeit eine Art und Weise) Bindungen. Diese Bindungen bieten eine Brücke zwischen den Werten, die von unserem internen ArrayController gehalten werden, und dem Objekt, das wir beobachten.

Beim Umgang mit Objekten; Wir verpacken diese in ObjectProxy, so dass wir ein "Schlüssel" -Mitglied einführen können, ohne das Objekt selbst modifizieren zu müssen. Warum ja, dies bedeutet, dass Sie # reversedly verwenden könnten. Eine weitere Übung für den Leser ;-)

Ich würde empfehlen, dass Ihr Modell auf Ember.Object basiert, um mit dem Rest von Ember konsistent zu sein, so dass Sie Ihr Modell über seine & Set-Handler manipulieren können. Wie in der Geige gezeigt, können Sie Em.Get/Em.set alternativ verwenden, um auf Modelle zuzugreifen, solange Sie dies konsistent tun. Wenn Sie Ihr Modell direkt berühren (no get/set), wird every nicht über Ihre Änderung benachrichtigt.

Em.set(model.properties, 'foo', 'asdfsdf'); 

Der Vollständigkeit halber hier ist mein every Helfer:

var DataValueObserver = Ember.Object.extend({ 
    init: function() { 
     this._super(); 
     // one way binding (for now) 
     Em.addObserver(this.parent, this.key, this, 'valueChanged'); 
    }, 
    value: function() { 
     return Em.get(this.parent, this.key); 
    }.property(), 
    valueChanged: function() { 
     this.notifyPropertyChange('value'); 
    } 
}); 

Handlebars.registerHelper("every", function() { 
    var args = [].slice.call(arguments); 
    var options = args.pop(); 
    var context = (options.contexts && options.contexts[0]) || this; 

    Ember.assert("Must be in the form #every foo in bar ", 3 == args.length && args[1] === "in"); 
    options.hash.keyword = args[0]; 
    var property = args[2]; 

    // if we're dealing with an array we can just forward onto the collection helper directly 
    var p = this.get(property); 
    if (Ember.Array.detect(p)) { 
     options.hash.dataSource = p; 
     return Ember.Handlebars.helpers.collection.call(this, Ember.Handlebars.EachView, options); 
    } 

    // create an array that we will manage with content 
    var array = Em.ArrayController.create(); 
    options.hash.dataSource = array; 
    Ember.Handlebars.helpers.collection.call(this, Ember.Handlebars.EachView, options); 

    // 
    var update_array = function(result) { 
     if (!result) { 
      array.clear(); 
      return; 
     } 

     // check for proxy object 
     var result = (result.isProxy && result.content) ? result.content : result; 
     var items = result; 

     var keys = Ember.keys(items).sort(); 

     // iterate through sorted array, inserting & removing any mismatches 
     var i = 0; 
     for (; i < keys.length; ++i) { 
      var key = keys[i]; 
      var value = items[key]; 
      while (true) { 
       var old_obj = array.objectAt(i); 
       if (old_obj) { 
        Ember.assert("Assume that all objects in our array have a key", undefined !== old_obj.key); 
        var c = key.localeCompare(old_obj.key); 
        if (0 === c) break; // already exists 
        if (c < 0) { 
         array.removeAt(i); // remove as no longer exists 
         continue; 
        } 
       } 

       // insert 
       if (typeof value === 'object') { 
        // wrap object so we can give it a key 
        value = Ember.ObjectProxy.create({ 
         content: value, 
         isProxy: true, 
         key: key 
        }); 
        array.insertAt(i, value); 
       } else { 
        // wrap raw value so we can give it a key and observe when it changes 
        value = DataValueObserver.create({ 
         parent: result, 
         key: key, 
        }); 
        array.insertAt(i, value); 
       } 
       break; 
      } 
     } 
     // remove any trailing items 
     while (array.objectAt(i)) array.removeAt(i); 
    }; 

    var should_display = function() { 
     return true; 
    }; 

    // use bind helper to call update_array if the contents of property changes 
    var child_properties = ["[]"]; 
    var preserve_context = true; 
    return Ember.Handlebars.bind.call(context, property, options, preserve_context, should_display, update_array, child_properties); 
}); 

Inspiriert von:

ist hier, dass Geige wieder, wenn Sie es verpasst haben:

8

Seit Ember v2.0.0-beta.1 Sie {{each-in}} Helfer verwenden können um über Objekteigenschaften in HTMLBars zu iterieren. Sie können es wie {{each}} Helfer verwenden.

Beispiel:

{{#each-in modelWhichIsObject as |key value|}} 
    `{{key}}`:`{{value}}` 
{{/each-in}} 

JS Bin demo.

Verwandte Themen