BackboneJS - get specific value from collection using _.max method - javascript

I want to get a specific value from a model inside a Collection. The Collection is sorted by ID (contest_id) which is served by the database and gets delivered as JSON. So, the JSON looks like:
data : [{
"contest_id" : "3",
"artist" : {
"artist_name": "some name",
"artist_cover" : "some image.jpg"
}
},
"contest_id" : "1",
....
}]
Now, I have glued something together:
var contestImage = _.max(this.collection.toJSON(), function(cnt){
return cnt.contest_id;
});
I get the highest contest_id, which is what I want but how do I proceed when I want to grab the image? and even display it?
Thanks in advance...

The max method should actually be available directly from your Backbone collection (although it's an Underscore method, it's mixed into Backbone's Collections), which means you can simplify your code a bit.
Something like this should do the trick:
var model = this.collection.max(function (cnt) {
return cnt.contest_id;
});
var contest_id = model.get('contest_id');
The first section returns the model you want, and the second gets the contest ID attribute.
To get the artist cover attribute, you can then convert it to JSON:
var artist_cover = model.toJSON().artist.artist_cover;
Or get the artist attribute from the model:
var artist_cover = model.get('artist').artist_cover;

This actually made it work:
var contestImage = _.max(this.collection.toJSON(), function(cnt){
return cnt.contest_id;
});
var latestImage = contestImage.artist.artist_cover;
Thanks for the answers though :-)

Related

Selecting a JSON object by number not by name

I try to store a JSON object with informations in multiple languages. Im not even sure they way i did it is good, any suggestions are welcome.
My current problem ist, that i dont know how to access the first language without knowing what language it is.
var Data = {
"NameIntern": "Something intern",
"en": {
"Name": "Some name",
"ModuleOrder": "123,333,22" }
};
document.write(Data[1].Name);
I just want to access the second object, sometimes its "en", sometimes its "de".
Thanks for any tipps!
Here is a pure javascript solution:
First: You get the keys of the object:
var keys = Object.keys(Data);
Then: The keys are stored in a array. You can access them with an index. Like:
Data[keys[0]]
Now: You can use a foor loop or whatever you want :)
Data is an object its not array so you cant access it like Data[0] you can access it like Data.en.
but as you say you dont know any thing about en or de so i suggest that you form the Data object like this :
var Data =[{
lang:"en",
langData:{
Name:"Some name"
}
}]
var Data = {
"NameIntern": "Something intern",
"en": {
"Name": "Some name",
"ModuleOrder": "123,333,22" }
};
var index = 0;
$.each(Data, function(key, val){
index += 1;
if (index == 2){
// key is the language, like in this example key is 'en'
console.log(key);
}
});
var name = (Data.en || Data.de || {})['Name'];
(Data.en || Data.de || {}) get's value of Data.en or Data.de if both doesn't exist, return empty object, so that script doesn't throw exception for Name property
()['Name'] same as myObject['Name'], myObject.Name
assign value to name variable, it will be Some name or undefined at least
If you have more languages, add them all, notice: it will return first found lang
var name = (Data.en || Data.de || Data.ru || Data.fr || {})['Name'];
Use Object.keys method to get list of object property names:
console.log(Data[Object.keys(Data)[1]]['Name']); // "Some name"

Add [DataObject] to exsisting array with var key

Using Cordova, I am trying to get an Object to add to an array. I have this working on node JS using :
theData = {[varkey]:DataObject};
But I can't get this to work the same way within my javascript that cordova runs.
I need to do the following:
var TownName = 'Auckland', var townData = (JSON Data);
theArray = new Array();
theArray[TownName] = townData;
I need to be able to call it back as:
theArray['Auckland']
Which will return (JSON Data)
But it doesn't want to store the data with the key inside the array.
I have also tried:
theArray.TownName = townData;
theArray = [{TownName:townData}];
theArray = {[TownName]:townData}];
Nothing wants to store the data.
Any suggestions?
::EDIT::
data.theData =
"Auckland"[
{
"username":"pndemoname1",
"number":"373456",
"www":"http://373456.pndemoname1",
"icon":"/imgs/pndemoname1.png"
},
{
"username":"pndemoname2",
"number":"373458",
"www":"http://373458.pndemoname2",
"icon":"/imgs/pndemoname2.png"
}
data.town = "Auckland";
townData = new Array();
alert(JSON.stringify(data.theData))//Alerts theData
townData[data.town] = data.theData
alert(townData[townName]) //Alerts undefined
::EDIT2::
Re-defining the array within the function that deals with all of the data, seems to make it work.
As per my answer, the issue was that I assumed javascript vars are global.
Use objects or an array of objects.
A data structure like this:
{
town1: town1Data,
town2: town2Data,
}
Or more common:
[
{
name: "Town 1",
data: {...}
},
{
name: "Town 2",
data: {...}
},
]
For reference:
http://andrewdupont.net/2006/05/18/javascript-associative-arrays-considered-harmful/
I got what you're trying to do, to add property names dynamically to your object is first, by making sure you are using an OBJECT instead of an array, so when you want to store something you will do the following:
var _obj = {}, _something = 'xyz';
_obj[ _something ] = { ... }; // json structure
The problem you're facing is that you want to assign a string value as a key inside your array, which will not work.
However, you can still use the array you defined and do the following:
var _array = new array();
_array.push( { .... } ); // insert json structure
Remember! By using the array you will have to loop through all values every time you want to access your key, just as the best practice to avoid getting into errors.
Good luck.
The issue was that I didn't define the array within the function of where I was trying to add the information to.
I assumed the var was global (Too much PHP)

Turn Observable Array into nested JSON

I'm having a problem getting an array of information stored properly as JSON.
I made a fiddle to illustrate the problem. Enter a set of tags and take a look at the console to see the output.
More explanation:
So I have an input that takes in a comma-separated list of tags, which I then format.
function createTagArray() {
// given an input value of 'tag1, tag2, tag3'
// returns array = ['tag1', 'tag2', 'tag3']
}
I thought what I needed to do next was the following:
loop over the array and create a 'tag' object for each item which also includes an id for the tag and the id of the contact the tag is associated with.
Each object is pushed to tags, an observable array.
function single_tag(id, contactId, tagLabel) {
var self = this;
self.id = id;
self.contactId = contactId;
self.tagLabel = tagLabel;
}
function createTags() {
var array = createTagArray();
for (var i = 0; i < array.length; i++) {
self.tags().push(new single_tag(uuid.generate(), self.contactId, array[i]));
}
}
Then, I converted it into JSON
self.contactInformation = function() {
return ko.toJS({
"id": self.contactId,
"firstname": self.firstname(),
"lastname": self.lastname(),
... other fields ...
"tags": self.tags(),
})
}
But, when I inspect the console output of calling this function, tags is a collection of arrays, not a nice json object.
How do I get it formatted correctly?
I tried this suggestion, and the tag json is structured correctly, but it is stored with escaped quotes, so that seems wrong.
Thanks for all the help!
I would recommend you knockout.mapping plugin for KO, it allow map complicated JSON structure to view model, even without declarations.
From the documentation
Let’s say you have a JavaScript object that looks like this:
var data = {
name: 'Scot',
children: [
{ id : 1, name : 'Alicw' }
]
}
You can map this to a view model without any problems:
var viewModel = ko.mapping.fromJS(data);
Now, let’s say the data is updated to be without any typos:
var data = {
name: 'Scott',
children: [
{ id : 1, name : 'Alice' }
]
}
Two things have happened here: name was changed from Scot to Scott and children[0].name was changed from Alicw to the typo-free Alice. You can update viewModel based on this new data:
ko.mapping.fromJS(data, viewModel);
And name would have changed as expected. However, in the children array, the child (Alicw) would have been completely removed and a new one (Alice) added. This is not completely what you would have expected. Instead, you would have expected that only the name property of the child was updated from Alicw to Alice, not that the entire child was replaced!
...
To solve this, you can specify which key the mapping plugin should use to determine if an object is new or old. You would set it up like this:
var mapping = {
'children': {
key: function(data) {
return ko.utils.unwrapObservable(data.id);
}
}
}
var viewModel = ko.mapping.fromJS(data, mapping);
In the jsfiddle you were using Knockout 3.0 which doesn't have support for textInput. This was added in 3.2. To use version 3.2 you need to use a cdn such as this: http://cdnjs.com/libraries/knockout
There was typeo in your binding. sumbit should be submit.
There was a problem with your constructor for single_tag. id was not used so I removed it:
function single_tag(contactId, tagLabel) {
var self = this;
self.contactId = contactId;
self.tagLabel = tagLabel;
}
Currently also contactId is not set because the observable has not been set to a value.
To convert to JSON you need to use ko.toJSON instead of ko.toJS:
self.contactInformation = function() {
return ko.toJSON({
"firstname": self.firstname(),
"tags": self.tags(),
})
}
Now when the console writes out an array appears:
{
"firstname":"test",
"tags":[
{"tagLabel":"test1"},
{"tagLabel":"test2"},
{"tagLabel":"test3"}
]
}
JsFiddle
So my problem was more basic than I was realizing. I'm using JSON Server to serve up my data, and I was pulling information from two parts of the database (contacts & tags).
When I tried to update my tags, I was trying to apply them to a property that didn't exist on the contact JSON in my database. Posting the tags separately worked though.

Changing nested attribute with model.set in Backbone

I'm trying to do what I hope is a simple thing -- doing a model.set only on a sub attribute of the object.
Right now, I have a model that looks like this:
{
"attr1" : true,
"attr2" : this.model.get("username"),
"attr3" : $('#tenant_select').val(),
"attr_array": [
{
"id": "sub_1",
"state": "active"
},
{
"id": "sub_22",
"state": "not_active"
}
]
}
I want to be able to grab reach into myMode.attr_array.state and change the value. However, using .set I've only been able to change attributes on the first level, i.e. attr_array.
Is there an way to do this using model.set?
You can do it (I'm wondering why you didn't manage to do it). But you have to be careful:
var array = this.get('attr_array');
array[1].state = 'active';
this.set('attr_array', array);
What's the problem here? Your model holds a reference of the object. Therefore the last line is useless, it won't change anything at all. It's simply equivalent to:
this.get('attr_array')[1].state = 'active';
And you lose any internal stuff Backbone does when you use set.
So what to do? Clone your object:
var array = _.clone(this.get('attr_array'));
array[1].state = 'active';
this.set('attr_array', array); // will trigger 'change' and 'change:attr_array' events

How to create an array in jQuery for holding values of each post?

What I want to do is set an icon for each category using jQuery. So far the code looks like this:
var category = $(".odd, .even").children('.views-field-field-category').text();
if (category=="funny") {
$(".odd, .even").children('.views-field-field-category').html('image-tag');
}
Since the variable category gathers all of the category values in that page and combines them (so that it looks like "funny gifs videos gifs" etc) I've decided that I need an array to hold them each seperately. Now I've tried to do it in various ways, but without any success. Can you please help and show me how to set it up so that I could use if (category[i]=="funny") { do this }?
You can create an object:
var o = {
'funny' : 'html-tag',
'gifs' : 'html-tag2',
'crazy' : '...'
}
And use html callback function.
$(".odd, .even").children('.views-field-field-category').html(function(i, html){
var prop = $(this).text().toLowerCase();
return o[prop];
})

Categories

Resources