Search code examples
javascriptknockout.jsknockout-2.0knockout-mapping-pluginrotten-tomatoes

Looping over an Objects Properties


I am writing a test program to pull data from the Rotten Tomatoes API and would like to know the best approach for looping over an objects properties after using the mapping plugin. The data is pretty straightforward and is being retrieved via jquery ajax.

Here is a small part of the data:

"ratings": {
  "critics_rating": "Certified Fresh",
  "critics_score": 99,
  "audience_rating": "Upright",
  "audience_score": 91
 }

This is part of a larger mapping and I'm performing a mapping like this in the ajax callback:

self.moviedetail = ko.mapping.fromJS(data);

I realize I can do the following which is what I'm trying to optimize:

<div data-bind-"with: moviedetail">
 <ul data-bind="with: ratings">
  <li>Critics Rating: <span data-bind="text: critics_rating"></span></li>
  <li>Critics Score: <span>data-bind="critics_score"</span></li>
   etc
 </ul>
</div>

I have not determined how I could loop over each of the ratings to display them like this in some kind of data agnostic way without checking each one. Using underscore I could loop over the properties and get the values for them, but don't know how to achieve the same thing in knockout.

The end result I'm looking for is this:

<ul>
  <li>critics_rating: Certified Fresh</li>
  <li>critics_score: 99</li>
  ....
</ul>

Notes: Per one of the answers which will definitely work, I can preprocess the data like this, however I'm looking to see if there is a way to do it on the view.

if (data.ratings!=='undefined') {
  self.ratings.removeAll();
  for(var prop in data.ratings) {
    if(data.ratings.hasOwnProperty(prop)) {
        self.ratings.push({name: prop, value: data.ratings[prop]});                         
    }
  }
}

Solution

  • I don't think you can do this with knockout by default.

    You could process the data array to put the incoming data in a structure you can bind in a generic way, like:

    "ratings" : {
        [ "name": "critics_rating", "value": "Certified Fresh" ],
        [ "name": "critics_score", "value": 99 ],
        ...
    }
    

    Then use HTML like

    <ul data-bind="foreach: ratings">
        <li>
            <span data-bind="text: name"></span>:
            <span data-bind="text: value"></span>
        </li>
    </ul>