Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterating through an Ember Object

Tags:

ember.js

I have Ember.Object which is being used as a basic key/value dictionary. The names of the keys are dynamic and what I'd like to be able do is iterate over these properties. Seems like this should be easy but google searches and my collective head scratching doesn't seem to point to the obvious answer I was expecting.

For the following psuedo code:

App.MyObject = Ember.Object.extend({
    randomComputedProperty: function() {
        return "foobar";
    }     
}
$object = new MyObject.create(someBigAndUnpredictableNameValueHash);

My ideal solution would solve for this code would allow me to quickly discern:

  • Critically: an array of property names that that object has
  • Ideally: an array of computed property names that object has
  • Icing-on-the-Top: an array of computed properties that include setters along getter

Anyway have any ideas?

----- UPDATE -----

To be a little more explicit about my precise use case. The fictional MyObject is actually a property that comes in from one my models:

App.MyModel = DS.Model.extend({
    prop1: DS.attr('string'),
    prop2: DS.attr('number'),
    prop3: DS.attr('my-object')
}

Where a Transform object is setup to handle serialization/deserialization:

App.MyObjectTransform = DS.Trnasform.extend({
    deserialize: function(serialized) {
        return App.MyObject.create(serialized)
    },
    deserialize: function(deserialized) {
        return deserialized;
    }
}

This way when I'm working with MyModel in a handlebars template I can do something like:

{{prop1}}
{{prop2}}
{{#each prop3}}
    {{key}} = {{value}}
{{/each}}
like image 710
ken Avatar asked Oct 12 '13 16:10

ken


2 Answers

In Ember v2.0.0-beta.1 you can use {{each-in}} helper, which lets you to iterate over object keys and their values in your templates.

For example, sample object:

App.MyObject = Ember.Object.extend({
  randomComputedProperty() {
    return 'foobar';
  }     
});

Instantiated this way:

let $object = App.MyObject.create({
  prop1: 'value1',
  prop2: 'value2',
  prop3: ['element1', 'element2']
});

And iterated over in template using {{each-in}} helper:

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

Produces following results:

`prop1`:`value1`
`prop2`:`value2`
`prop3`:`element1,element2`

JSBin demonstrating this.

It's worth to mention that using {{each-in}} helper:

is a one time snapshot look at the object, it will not observe properties being added/removed/changed.

Thanks @Kingpin2k for pointing this out. Demo, note that update to prop1 isn't reflected in the DOM.

like image 109
Daniel Kmak Avatar answered Sep 25 '22 03:09

Daniel Kmak


Here are some ideas.

Object's Keys method 1

You can iterate over the properties and filter out the keys from the prototype chain (using the hasOwnProperty() method):

var obj = App.MyObject.create({stuff: "stuff!"});

var objKeys = []
for(var key in obj) {
  if(obj.hasOwnProperty(key)){
    objKeys.push(key);
  }
}
console.log(objKeys); // ['stuff']

Object's Keys method 2

On newer browsers you can directly get an array of the object's properties using the Object.keys() method:

console.log(Object.keys(obj)); // ['stuff']

Ember.Object's computed properties

Ember provides a way to iterate over the computed properties of a class using the eachComputedProperty() method

App.MyObject.eachComputedProperty(function(name, meta){
  console.log(name, meta);  // randomComputedProperty
});

JSBin example demonstrating these methods

Update

You could have a computed property on your model that re-arranges the MyObject's data into an array which can then be displayed by handlebars:

App.MyModel = DS.Model.extend({
  prop1: DS.attr('string'),
  prop2: DS.attr('number'),
  prop3: DS.attr('my-object'),

  prop3PropertyArray: function(){
    var prop3, 
        propertyArray = [];

    prop3 = this.get('prop3');

    for(var key in prop3) {
      if(prop3.hasOwnProperty(key) && key !== "toString"){
        propertyArray.push({key: key, value: prop3.get(key)});
      }
    }

    return propertyArray;
  }.property('prop3')
});

If prop3 contained:

prop3: App.MyObject.create({
  stuff: "stuff!",
  anotherRandomKey: "more value here"
})

then prop3PropertyArray would be:

[
  {
    key: "stuff",
    value: "stuff!"
  },
  {
    key: "anotherRandomKey",
    value: "more value here"
  }
]

which can then be displayed in handlebars using an {{#each}}..{{/each}} helper:

{{#each item in prop3PropertyArray}}
  {{item.key}} = {{item.value}}<br>
{{/each}}

Updated JSBin example

like image 23
CraigTeegarden Avatar answered Sep 21 '22 03:09

CraigTeegarden