I've got a mentally taxing problem here, where I've got a JSON object retrieved using a collection in Backbone. This is what the object looks like:
{
"MatchID": "00000001",
"Date": "1970-01-01T00:00:00.000Z",
"OriginalID": "",
"Stage": {
"StageNumber": "0",
"StageType": "Stage Type"
},
"Round": {
"RoundNumber": "0",
"Name": "Round Name"
},
"Leg": "1",
"HomeTeam": {
"TeamID": "0",
"Name": "Home Team Name"
},
"AwayTeam": {
"TeamID": "0",
"Name": "Away Team Name"
},
"Venue": {
"VenueID": "0",
"Name": "Venu Name"
},
"Referee": null,
}
What I want to do with this data, is filter it based on a particular attribute, such as the Venue.Name or Date attributes (which are different depths into the object, and can be deeper than two levels for some of the other data). I've got the following code inside a Backbone collection to filter and return a new collection with the contents filtered appropriately:
findWhere: function (Attribute, Value)
{
return new Project.Collections.Fixtures(this.filter(function (fixture)
{
return eval('fixture.attributes.' + Attribute) == Value;
}));
}
This allows me to specify in an attribute which attribute I want to filter by, and what I want it to be equal to, for any depth of object. The problem is, I really don't want to use "eval" to do this, but obviously I can't use "[Attribute]" for something like "AwayTeam.TeamID", as it won't work.
Does anyone know of a method I can use to achieve this functionality without using eval?
Something like this would let you traverse the hierarchy of objects to find a value:
var x = {
y: {
z: 1
}
};
function findprop(obj, path) {
var args = path.split('.'), i, l;
for (i=0, l=args.length; i<l; i++) {
if (!obj.hasOwnProperty(args[i]))
return;
obj = obj[args[i]];
}
return obj;
}
findprop(x, 'y.z');
You could add this as a method to your Fixture
object:
Fixture = Backbone.Model.extend({
findprop: function(path) {
var obj = this.attributes,
args = path.split('.'),
i, l;
for (i=0, l=args.length; i<l; i++) {
if (!obj.hasOwnProperty(args[i]))
return;
obj = obj[ args[i] ];
}
return obj;
}
});
and use it to extract the value
var f = new Fixture();
f.findprop("HomeTeam.TeamID");
The findWhere
method could then be rewritten as
findWhere: function (Attribute, Value)
{
return new Project.Collections.Fixtures(this.filter(function (fixture){
return fixture.findprop(Attribute) === Value;
}));
}
And a Fiddle to play with http://jsfiddle.net/nikoshr/wjWVJ/3/
Attributes in JavaScript objects can be accessed by square-bracket, string identifiers as well as the standard dot-notation.
In other words, this:
fixture.attributes.something
is the same as this:
fixture.attributes["something"]
You can also pass variable names in to the square brackets, the value of the variable is used as the key to retrieve.
So you can change your code to this:
findWhere: function (Attribute, Value)
{
return new Project.Collections.Fixtures(this.filter(function (fixture)
{
return fixture.attributes[Attribute] === Value;
}));
}
As you pointed out in the comments, this only handles one level objects and attributes. To get the nested attributes, you'll need to split the "Attribute" variable and loop through the parts. I like @nikoshr's solution for that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With