Fetch data from different urls using the same collection in backbone js - javascript

I have a collection which has to call 4 external apis Eg: http://www.abc.com, http://www.fgt.com, http://www.jkl.com and http://www.rty.com.
I have a Collection named Todos.js. Is there a way I can fetch the 4 apis together in a single collection since all the four apis would provide me the same model response
So the response I get from the 4 apis has the same data structure i.e. "name" and "link".
Is there a way I can append all the responses in the same collection? What is the best way to achieve this?

I think the way is to override fetch, where you make the Ajax call to each of the APIs. Store the returned partial sets in a temporary array, and when all 4 are complete, create the collection using this.reset. (You could use JQuery's Deferred I suppose, or just keep an internal count of how many calls have returned.)
Something like this:
var Collection = Backbone.Collection.extend({
fetch: function() {
this.completeCount = 0;
this.errorCount = 0;
this.temp = [];
this.urls = [ 'url1', 'url2', 'url3', 'url4' ];
var self = this;
// make a $.get call for each URL and add
_.each(this.urls, function(url) {
$.get(url, { success: function(data) {
console.log("Got partial collection from " + url);
self.addPartial(data);
// alternatively, just call "self.add(data);" here
}, error: function(response) {
console.log("Oops, the Ajax call failed for some reason... ignoring");
self.completeCount ++;
self.errorCount ++;
} });
});
},
// add a JSON array that contains a subset of the collection
addPartial: function(data) {
this.completeCount ++;
var self = this;
// add each item to temp
_.each(data, function(item) {
self.temp.push(item);
});
// if all have been received, then create the collection
if (this.completeCount == this.urls.length) {
this.reset(this.temp);
}
}
});
Here's a Fiddle where I replaced $.get with a method that just returns dummy data after a short delay.
Response to comment
Adding the responses to the collection as they come in is probably better (it's easier anyway). Here's an updated Fiddle.

I know it's an old question, but if someone reaches in here this information may help.
To preserve the data previosly fetched by a collection, you can change the url and call the method fetch() any times needed with this options:
reset: false,
remove: false,
Like this
yourCollection.fetch({reset: false, remove: false, [other]: [wathever]})
And that's all, no need for overriding the method. (Maybe in 2012 it was necesary, dunno. The fact is that those options work for Backbone 1.1.2 or later). Be aware that im not sure if this will merge or just add the new data even if it's reppeated.
The documentation (http://backbonejs.org/#Collection-fetch) is a little confusing about the 'reset' option, because it says is settled false by default, perhaps that may only apply when the url remains static and single.

Related

Reading to JSON URLs with jQuery

I need to read two JSON URLs with jQuery, mangle them together and then proceed updating my UI from the JSON data.
With the two URLs in URLA and URLB and a global variable globalDataA I tried:
function useBothData(dataB) {
// use dataB and globalDataA
};
function useDataA (data) {
globalDataA = data
$.getJSON (URLB, useBothData);
};
$.getJSON (URLA, useDataA);
The idea is that after loading the 1st URL I load the 2nd and then work with them. However this does never seem to return. (I get the Brwoser warning "Script takes too long".)
How can I arrange jQuery's getJSON calls for the two URLs (and their success functions), so that I can then use their data in finally one function?
You can use the callback function of getJSON
$.getJSON(URLA, useDataA, function(dataB) {
//useBothData = globalDataA + dataB
$.getJSON(URLB, useBothData, function(result) {
//do more stuff
})
});

Make Ajax call for all items in array?

I want to make an Ajax call for every item in an array, and when all the calls have returned, I want to call another function.
To make things a little more complicated, I'm using Papa Parse to make the Ajax call.
This is my code:
getCsvData: function(url) {
var _this = thisl
Papa.parse(url, {
download: true,
complete: function(data) {
return data;
}
});
},
getBackendData: function() {
var _this = this;
var results = {};
_this.numeratorIds.forEach(function(d) {
var url = _this.constructUrl(d.id, d.query_type);
results[url] = _this.getCsvData(url);
});
// When everything is finished...
// call another function to render the data.
},
I'm not sure this is quite right - is there a better way of doing things?
NB: I realise it's slower to do multiple Ajax calls than to chain URL parameters and make a single call, but I think it's the right thing to do in my situation - I am working with a very large, very static database, and it will mean that I can cache these queries more often.
Why you are trying to do make multiple AJAX calls instead doing of that the controller return List of object that you want. Then you will not need to make multiple Ajax calls. What you will need is just one Ajax and you will have list of objects that you want and then you can bind that data onto your views.
Hope it make sense.

How to merge multiple jsonp requests in a backbone.js model sync?

What am I trying to achieve?
There is a I am trying to update a nice jenkins radiator application made by Clayton Lengel-Zigich. It is a backbone.js application that fetches the status of a jenkins master server using its jsonp api and displays job status. I want to change this application to fetch from multiple masters and show the status for many jobs.
What have I tried?
I have tried to update the sync function to do two jsonp requests and then merge the result. The original file can be found here: https://github.com/clayton/jenkins-radiator/blob/master/src/radiator.js
sync: function(method, model, options) {
var paramsA = _.extend({
type: 'GET',
dataType: 'jsonp',
processData: true,
url: "http://serverA:8080/api/json?jsonp=?"
}, options);
var a = $.ajax(paramsA);
var paramsB = _.extend({
type: 'GET',
dataType: 'jsonp',
processData: true,
url: "http://serverB:8080/api/json?jsonp=?"
}, options);
var b = $.ajax(paramsB);
function MergeJobs(o, ob) {
for (var z in ob.jobs) {
o.jobs.push(ob.jobs[z]);
}
return o;
}
var joinedJson = []
a.done(function(jsonA) {
joinedJson = jsonA;
});
b.done(function(jsonB) {
MergeJobs(joinedJson, jsonB);
//joinedJson = jsonB;
})
return joinedJson;
},
What I got
I expected that I would be able to see the merged results in the webpage however I only see the results for one of the servers. Which server gets displayed is random, indicating to me that my merge is overwriting, not merging.
I don't know a lick of javascript so I am at the stage where I don't even know where to look next. Perhaps the _.extend section is what actually updates the model? If so, is there a way to achieve what I want another way?
You can create separate models and display them on the same If the models have the same structure I suggest you create an array containing all your models and then pass them to a collection. If your models are totally different then pass them to a view and have some logic in the view to handle all your models.
This site (http://backbonetutorials.com/) has some great tutorials to get started with models and collections just in case you haven't used backbone that much.
There's no guarantee as to which of your requests finishes first. If B finishes before A, it will merge jsonB into the empty joinedJson (simply setting it to jsonB) and then when A finishes it will overwrite joinedJson with jsonA.
That's not your only problem; at the time you return joinedJson there's no guarantee that either request has finished; you're treating asynchronous requests as if they were synchronous.

backbone model fetch JSON element by ID

I am using backbone for the first time and I am really struggling to get it to function correctly with a JSON data file.
I have a model Like so:
window.Test = Backbone.Model.extend({
defaults: {
id: null,
name: null,
},
url: function() {
return 'json/test.json/this.id';
},
initialize: function(){
}
});
When a test item is clicked I then try to bring up the details of the pacific model that was clicked by doing
testDetails: function (id) {
var test = new Test();
test.id = id;
test.fetch({ success: function(data) { alert(JSON.stringify(data))}});
},
However this does not work, I am unable to correctly say "get the JSON element with the passed ID"
Can anyone please show me how to correctly structure the models URL to pull the element with the ID.
Thanks
The problem here is that you're treating your JSON data file like a call to a server. That won't work and it's the reason you're getting a 404. If you're accessing a file locally, you have to load the file first. You can do this with jQuery using the .getJSON() method, or if the file's static, just load it into memory with a script block (though you'll probably need to assign a var in the file). Most likely, you'll use jQuery. An example of this can be found here:
Using Jquery to get JSON objects from local file.
If this is an array of JSON, you can load the array into a collection, and use the "at" method to access the particular element by id. If it's entirely JSON, you'll have to create a custom parser.
your url is incorrect for one. you are returning the literal string 'this.id'. you probably want to do something more along the lines of
url: function () {
return 'json/test.json/' + this.id;
}
I would start by fixing your url function:
url: function() {
return 'json/test.json/' + this.get('id');
}
The way you have it now, every fetch request, regardless of the model's id, is going to /json/test.json/test.id

How to cache the result of $.post-request in jQuery?

I have a small jQuery script that gets information by looking at an ID.
What is the best way to prevent that the same data are requested more than once (e.g. what's the best practices for caching in jQuery)?
I have tried to use $.post and $.ajax with option "cache" set to true, but the request is being sent more than once.
Is it better to save collected data and use sets to see whether you'll have to request it or not?
Any ideas and suggestions are welcome!
If it matters, I use ASP.Net MVC on the server-side.
The cache option you saw on the documentation, refers to the browser's cache.
You can implement a pattern of self-memorizing functions in many ways, the goal is that the function result for determined argument (id in your case) is only computed once.
Since you are using an Ajax request, I would suggest you to use a callback argument also, e.g.:
var getInfo = (function () {
var cache = {}; // results will be cached in this object
return function (id, callback) {
if (cache[id] != null) { // if exist on cache
callback(cache[id]);
return;
}
// doesn't exists on cache, make Ajax request and cache it
$.post("info.url", { "id": id }, function (data) {
cache[id] = data; // store the returned data
callback(data);
});
};
})();
Example usage:
getInfo(5, function (data) {
alert(data);
});

Categories

Resources