One JSON object into few collection objects - javascript

I'm having a puzzler here. I have the following collection:
var TagsCollection = Backbone.Collection.extend({
model: TagModel,
parse : function(response) {
console.log(response);
// code to go
return response;
}
});
Now that fetches the following sample JSON object:
{
id: 10149682,
published: "2014-01-13 08:23:00",
title: "Title",
tags: "tag1,tag2,tag3,tag4"
}
now what I want is to insert some code that will re-map the existing response into the following format:
[{name: "tag1"}, {name: "tag2"}, {name: "tag3"}, {name: "tag4"}]
and load it into the collection. (An important note - using Backbone / Underscore methods - for ex. _.chain / _.reduce etc.).

You can split you tags key:
var tags = response.tags.split(',');
And map the resulting array
return _.map(tags, function(tag) {
return {name: tag};
});

You can also try something like:
var tags= "tag1,tag2,tag3,tag4";
var newArr = tags.split(',').map(function(tag){ return {name: tag} });
Important: This works in IE9+ if you need this to run in IE8 or older you need to polufill. You can fine the instructions here

Related

What is wrong with my JavaScript append function?

In the below method, an object o is appended to a list of objects qs. The commented part does not work, the now uncommented part does work. What is wrong with the commented part?
onCreate(o) {
// This works (using lodash)
this.setState({ qs: _.concat(this.state.qs, { id: this.getNextID(), ...o }) });
// Is this not the same like the above?
// let newQuestionnaire = {id: this.getNextID(), title: o.title, description: o.description};
// let questionnaires = this.state.qs.push(newQuestionnaire);
// this.setState({
// qs: questionnaires,
// });
}
Edit: Maybe it helps somebody: the first thing coming up on Google is push:
--> Dont do that.
Array Push return
The new length property of the object upon which the method was called
try this
let newQuestionnaire = {id: this.getNextID(), title: o.title, description: o.description};
this.setState({qs: [...this.state.qs, thisquestionnaires]})

How can I loop over over multiple ajax requests, and then execute code after everything has been complete? [duplicate]

This question already has answers here:
Wait until all jQuery Ajax requests are done?
(22 answers)
Closed 3 years ago.
Let me just start this by saying I've done a series of searches online, but can't seem to piece it together.
Requirements: Use jQuery :(
On click, I am using a .getJSON call to get an object with several layers.
Here's an example of the data:
myObj = {
title: 'some name',
items: [
{
name: 'item-1',
url: '/item-1'
},
{
name: 'item-2',
url: '/item-4'
},
{
name: 'item-3',
url: '/item-4'
},
{
name: 'item-4',
url: '/item-4'
},
]
}
I want to loop through all of the urls, and call an .ajax operation on them, and then store the new data I get back in their respective objects.
It would look like this:
myObj = {
title: 'some name',
items: [
{
name: 'item-1',
url: '/item-1',
properties: {//whole new set of data from url}
},
{
name: 'item-2',
url: '/item-4',
properties: {//whole new set of data from url}
},
{
name: 'item-3',
url: '/item-4',
properties: {//whole new set of data from url}
},
{
name: 'item-4',
url: '/item-4',
properties: {//whole new set of data from url}
},
]
}
Once all of that is complete and each object has this new bit of data, I then want to do something with the myObj, like render it to a jquery template (ugh), but the new data MUST be inside of each item.
Here's what I have so far:
var myItems = myObj.items;
$(myItems).each(function(index, item) {
var itemUrl = '/somestuff/' + item.url + '.js';
$.getJSON(itemUrl).done(function(itemData) {
item.data = itemData;
});
}).promise().done(function() {//render data to template})
The only problem I'm having is that sometimes the data doesn't exist yet (item.properties) when the template renders, and therefore cannot render undefined.
I've tried unsuccessfully chaining .done(), and have now come across using .when(), but don't know how to write the line of code to make .when() work properly.
Any help is appreciated, and I'd be happy to clarify details.
If you capture the Promise (technically a jQuery Deferred object, actually) generated by each AJAX request, and add them to an array, then you can call .when() to execute some code once all of the Promises are resolved. Something like this (untested):
var myItems = myObj.items;
var promises = [];
$(myItems).each(function(index, item) {
var itemUrl = '/somestuff/' + item.url + '.js';
var p = $.getJSON(itemUrl);
p.then(function(itemData) {
item.data = itemData;
return itemData;
});
promises.push(p);
});
$.when.apply($, promises).then(function() { //render data to template...
This is probably preferable to chaining the done() callbacks, because it still allows the requests to execute in parallel, which is likely to be faster (although this is somewhat dependent on the server, but that's a separate issue).

Jquery adding array of values to json object

I am trying to get a json object like the below
{
"Name":"UnitedStates",
"Info":[
{"StateName":"Washington",
"Commands":[
{"Type":"Men","Parameter":"10000"},
{"Type":"Women","Parameter":"30000"}
]},
{"StateName":"California",
"Commands":[
{"Type":"Kids","Parameter":"20000"}
]}
]}
I am trying the below
Fiddle
How can I add array of values to existing blank object.
var CountryName = 'UnitedStates';
var Data = {
Name: CountryName,
Info: [
commands :[]
]
}
Data.Info.push({'StateName': 'washington'});
Data.Info.commands.push(
{'Type': 'Men'},
{'Parameter': '1000'},
);
$('.displayJsonBlock').empty();
$('.displayJsonBlock').append('<pre><code>' + JSON.stringify(TemplateData) + '</pre></code>')
If you look at the error console output, you'll see it's giving you a syntax error because Info is trying to be both an object and an array at the same time:
Info: [
commands :[]
]
If you want to push into Info it needs to be an array, but that means you can't define properties in the literal like this. If you want to define properties like this it needs to be a an object like:
Info: {
commands :[]
}
But then you can't push.
I think what you're looking for is:
var CountryName = 'UnitedStates';
var Data = {
Name: CountryName,
Info: [] // info is just an array
}
Data.Info.push({
'StateName': 'washington',
commands: [] // each element of Info is an object with a commands array
});
Data.Info[0].commands.push( // you need to define which element of info. Here it's the first
{'Type': 'Men'},
{'Parameter': '1000'},
);
console.log(Data)
Of course you don't need to do two pushes you can push the whole object including commands:
Data.Info.push({
'StateName': 'washington',
commands: [
{'Type': 'Men'},
{'Parameter': '1000'}
]
})
Well, the structure of JSON data is incorrect, I think you do something like this
var CountryName = 'UnitedStates';
var Data = {
Name: CountryName,
Info: [
{commands :[]}
]
}
After
Data.Info.push({'StateName': 'washington'});
Data.Info['commands'] = [{'Type': 'Men'}, {'Parameter': '1000'}];
There is a good way, but I do not know if it is what you want.

Find model which doesnt have an attribute in Backbone collection

I know that we can find all models in collection like so, based on attributes
var friends = new Backbone.Collection([
{name: "Athos", job: "Musketeer"},
{name: "Porthos", job: "Musketeer"},
{name: "Aramis", job: "Musketeer"},
{name: "d'Artagnan"},
]);
friends.where({job: "Musketeer"});
However i want to find the model which doesn have the attribute, or the key. How to do it?
Something like
friends.where(not(job));
Any help is greatly appreciated
Backbone provide wide range of underscore methods for Backbone.Collection instances. One of such method is Backbone.Collection.filter which filters models in collection based on the result of a custom function. Here is an example of how it could be used:
var friends = new Backbone.Collection([
{name: "Athos", job: "Musketeer"},
{name: "Porthos", job: "Musketeer"},
{name: "Aramis", job: "Musketeer"},
{name: "d'Artagnan"},
]);
friends.filter(function(model) {
return _.isUndefined(model.get('job'));
});
JSFiddle for the code above: https://jsfiddle.net/Ljve5104/
I would try something like this, being friends a backbone collection.
function isMusketeer() {
return friend.get('job') && friend.get('job') === "Musketeer";
}
function hasNoJob() {
return !friend.get('job');
}
friends.find(hasNoJob); //The first without a job
friends.find(isMusketeer); //The first that is a musketeer
friends.filter(hasNoJob); // List of results that has no job
friends.filter(isMusketeer); // List of results that are musketeer
I just separate the criteria / predicates , and then applied to the collections underscore function you need, in this case can be for many results or one result, depending on your needs.

Populate Backbone.js JSON response into nested collections inside nested collections/models

My problem is that I am just starting out with Backbone.js and are having trouble wrapping my head around a complex problem. I want to save a form that have infinite fields, and some of the fields also needs to have infinite options. I'm just worried I might have started at the wrong end with a JSON response, instead of building the models/collections first. Here is a short pseudocode of what I try to achieve.
id:
parent: <blockid>
fields: array(
id:
title:
helpertext
options: array(
id:
type:
value:
)
)
Currently I am working with a faked JSON response from the server, which I built from scratch, and now I want to divide it into models and collections on the client side.
//Fake a server response
var JSONresponse = {
"formid":"1",
"fields":[
{
"fieldid":"1",
"title":"Empty title",
"helper":"Helper text",
"type":"radio",
"options":[
{
"optionid":"1",
"value":"Empty option.."
},
{
"optionid":"2",
"value":"Empty option.."
}
]
},
{
// fieldid2
}
]
};
The idea is to add fields as I see fit, and then if the field type is radio/checkbox/ul/ol there must also be an "options" array within the field.
My work so far:
var app = {};
app.Models = {};
app.Collections = {};
app.View = {};
app.Models.Option = Backbone.Model.extend({
});
app.Collections.Options = Backbone.Collection.extend({
model: app.Models.Option
});
app.Models.Field = Backbone.Model.extend({
options: new app.Collections.Options()
});
app.Collections.Fields = Backbone.Collection.extend({
model: app.Models.Field
});
app.Models.Form = Backbone.Model.extend({
formid : "1",
fields: new app.Collections.Fields(),
initialize: function() {
}
});
How do I split up my JSON response into all these models and collections?
(Perhaps I should re-evaluate my approach, and go for something like form.fieldList and form.optionList[fieldListId] instead. If so, how would that look like?)
Edit: Here is a little jsfiddle after many fixes, but I still don't really know how to make the inner options list work.
The easiest solution would be using Backbone Relational or Backbone Associations.
The documentation should be enough to help you get started.
If you don't want to use a library you could override the parse function on the Form model.
app.Models.Form = Backbone.Model.extend({
defaults: {
fields: new app.Collections.Fields()
},
parse: function(response, options) {
return {
formid: response.formid,
fields: new app.Collections.Fields(_.map(response.fields, function(field) {
if (field.options) {
field.options = new app.Collections.Options(field.options);
}
return field;
}))
};
}
});
Now if you fetch a form from the server, the response will be parsed into an object graph of models and collections.
form.get('fields') will return an app.Collections.Fields collection. form.get('fields').first().get('options') will return an app.Collections.Options collection, if any options exist.
Also, you could create the form model like this:
var form = new app.Models.Form(JSONresponse, {
parse: true
});
This would result in the same object structure.
It's quite hard to handle the case of nested models and collections right in plain Backbone.
Easiest way of handling this will be something like this:
var Option = Nested.Model.extend({
idAttribute : 'optionid',
defaults : {
optionid : Integer
value : ""
}
});
var Field = Nested.Model.extend({
idAttribute : 'fieldid',
defaults : {
fieldid : Integer,
title : "",
helper : "",
type : "radio",
options : Option.Collection
}
});
var Form = Nested.Model.extend({
idAttribute : 'formid',
defaults : {
formid: Integer,
fields: Field.Collection
});
https://github.com/Volicon/backbone.nestedTypes
And that's it. Yep, you'll get direct access to the attributes as free bonus, just form.fields.first().options.first().value, without that get and set garbage.

Categories