Javascript Keeping variables in scope on success callback (jquery/backbonejs/parse function) - javascript

Below I am using backbone js to fetch a collection. On the request's response, I would like to perform some logic on the collection to massage the data. I am modifying the parse method on the parent collection (source types) to attach a child collection (source accounts) and only include a source type if there are actually source accounts.
I don't want to render this without having all the data loaded primarily, so I figure with javascript the only way to be safe is with a success callback.
As you can see in the below code, inside the parse function, I construct a new object called "response_object". The issue is that when i attempt to pack this object inside the success callback, the collection does not include any of the object that i packed into it. How would you rewrite this to make this work correctly?
window.AdminSourceTypes = Backbone.Collection.extend({
model: window.AdminSourceType,
url: '/api/sources',
parse: function(response){
// create response object
response_object = [];
x = 0;
_.each(response, function(item){
//get child collection (accounts) from one of "source type's" attributes
collection = new window.AdminAccounts();
collection.url = item.accounts_url;
//get all accounts
collection.fetch({
//only add the source type to the response object
//if there are accounts associated to it
success: function(accounts_collection){
if(accounts_collection.size() > 0){
response_object[x] = item;
}
}
});
x++;
});
return response_object;
}
});

This is what I went with:
window.sources = new window.AdminSourceTypes({
events: {
'reload':'render'
}
render: function(){... bla bla .... }
});
window.sources.fetch({});
window.AdminSourceTypes = Backbone.Collection.extend({
model: window.AdminSourceType,
url: '/api/sources',
parse: function(response){
cmp = this;
response_object = [];
x = 0;
y = 0;
_.each(response, function(item){‣
collection = new window.AdminAccounts();
collection.url = item.accounts_url;
collection.fetch({
success: function(data){
x++;
if(data.size()>0){
item.accounts = collection;
window.sources.add(item);
window.sources.trigger('reload');
}
}
});
});
}
});
So instead of waiting for the success callback, i'm just going to have the parse method return nothing, and just have the item get added to the collection if it satisifes my condition.

Related

pass collection of objects through http post in angular js

I have pass a collection of objects through http post in angular js.
The code is as follows:
$scope.selectedContent = function () {
var contents = $filter('filter')($scope.data.ContentId, { Selected: true }); // I could able to get all the selected objects here, No problem with it
var jsonData = angular.toJson(contents); //It is not able to convert to Json if there are more than 5 records
var promise = $http.post('/webapi/cmsApi/CmsPublishApprovedContent?jsonData=' + jsonData, {});
promise.success(function () {
window.location.reload();
});
[ReferrerFilterAttribute]
[HttpPost]
[System.Web.Http.ActionName("CmsPublishApprovedContent")]
public void CmsPublishApprovedContent(string jsonData)
{
var contents = JsonConvert.DeserializeObject<List<ContentNodeInWorkFlow>>(jsonData);
foreach (var content in contents)
{
_contentService.PublishContent(content.ContentId, userId);
}
}
}
The above code works fine if there are 5 records or less. If there are more records, I could able to get all the selected record
objects in the variable 'contents'. But the problem is occuring when converting to Json for all those objects. I
have about 500 records to pass through. How can do I it?
There is no specific reason to convert to JSON data. I just need to extract the ids of all the selected items. I have modified the above code as below:
$scope.selectedContent = function () {
var contents = $filter('filter')($scope.data, { Selected: true });
var abc = [];
angular.forEach(contents, function(content)
{
abc.push(content.ContentId); // got all the ids in the array now
});
var promise = $http.post('/webapi/cmsApi/CmsPublishApprovedContent' ,{contents : abc});
promise.success(function () {
window.location.reload();
});
}
I have just took an array and pushed all the content ids into it. I could able to see all the ids in the array now. I tried to pass the array as above.
How to retrieve those array in the code behind.
[ReferrerFilterAttribute]
[HttpPost]
[System.Web.Http.ActionName("CmsPublishApprovedContent")]
public void CmsPublishApprovedContent(int[] abc)
{}
I do not see any values obtained under int[] abc. What will be the datatype for the parameter in the method call above.
You need second argument of $http.post method. You have to send such data by POST requests, not in query of url. You can put some data into body of the post request.
You need this:
var postBodyWithHugeAmountOFData = {data: [1,2,3,4,5...500]};
$http.post(url, postBodyWithHugeAmountOFData).success(function () {});
Also, you must be ready to handle this request in your backend.
is there any specific reason u want to pass this data as a JSON?.
if u r using Web API in that case u can pass the object as it is but only make sure that collection in web API method contains all the property in javascript collection
Thank you for all your posts. It's working fine without converting to Json. The code is as below.
$scope.selectedContent = function () {
var contents = $filter('filter')($scope.data, { Selected: true });
var promise = $http.post('/webapi/cmsApi/CmsPublishApprovedContent' ,contents);
promise.success(function () {
window.location.reload();
});
}
and the signature would be
public void CmsPublishApprovedContent(List<ContentNodeInWorkFlow> abc)
{
}

Backbone adding data from model A to Collection with model B

In a model I have one some attributes.
I would like one of the attributes to be placed in a seperate collection with another model, after I altered the data.
Now altering the data is not a problem and I know how to create the new object.
However I don't know what the best way to go is with:
where to alter the data
how to get it in my collection.
I tried several things from sending the complete attribute to the collection, where I do I have a parse which should give back a new object.
This however fails.
I also tried to do the same with the model and a parse.
Then I tried to just return the object in the 'url' section of the collection.
but as expected this does not work either. After which I tried to stringify the object to json, but this didn't work either.
So now I am thinking it might be the best way to start altering the data in Model A, after the data has ben received, and then push or add the data to the collection.
Maybe anyone else has a better idea of doing this?
And how do I know the data is in Model A, so I can start running the script?
First try in the collection: by URL
SatPhotoDataCollection = Backbone.Collection.extend({
model: SatPhotoDataModel,
url: function() {
var obj = satPhotoModel.attributes.Layer;
var layerNames = {};
for (var i = 0; i < obj.length; i+=1) {
//do some massive things filling layerNames
}
return layerNames;
}
});
Same thing, not using URL but parse, sending the 'satPhotoModel.attributes.Layer' to the collection using:
SatPhotoDataCollection.add(satPhotoModel.attributes.Layer);
SatPhotoDataCollection = Backbone.Collection.extend({
model: SatPhotoDataModel,
url: "",
parse: function(data) {
var layerNames = {};
for (var i = 0; i < data.length; i+=1) {
//do some massive things filling layerNames
}
return layerNames;
}
});
Of course I did the same in the model satPhotoDataModel (model B) in the URL and Parse, however I must the 'layerNames' I return is really a collection of 'layers', so hence the need for a collection ;)
Now in the satPhotoModel (model A) which will have the Layer in it's attributes I could also try something like:
SatPhotoModel = Backbone.Model.extend({
initialize: function() {
},
url: "http://geoservertest/geoserver/DIWADIS/ows?service=WMS&version=2.0.0&request=GetCapabilities",
sync: function(method, model, options) {
options.dataType = "xml";
options.crossDomain = true;
options.contentType = 'application/json; charset=utf-8';
return Backbone.sync(method, model, options);
},
//we are expecting an XML since we want a normal object, we do this with parsing
parse: function(data) {
var obj = $.xml2json(data);
this.parseLayers(obj.Capability.Layer);
return obj.Capability.Layer;
},
defaults: {
Abstract: "",
BoundingBox: {},
CRS: [],
Ex_GeographicBoundingBox: {},
Layer: [],
Tile: ""
},
parseLayers: function(data) {
var layerNames = {};
for (var i = 0; i < data.length; i+=1) {
//do some massive things filling layerNames
}
SatPhotoDataCollection.add(layerNames);
}
});
I am just doubting if that is really the correct way to go.
So any help and enlightenment would be awesome :-)

Using Backbone Fetch Success Callback to Change Data Before Initializing View

I'm looking for a way to intercept the value returned from a server when I fetch a backbone model (a collection, strictly speaking) from the server, then modify it before continuing. I would think that I could do something like this
SessionController.prototype._initPages = function() {
return App.pages.fetch({
reset: true,
success: function(model, response, options) {
//modify the contents of response
}
};
And my modifications would be reflected in the model that's used to initialize the view.
However I was looking at the backbone source and I think I may have misunderstood something.
fetch: function(options) {
options = options ? _.clone(options) : {};
if (options.parse === void 0) options.parse = true;
var success = options.success;
var collection = this;
options.success = function(resp) {
var method = options.reset ? 'reset' : 'set';
collection[method](resp, options); //this line updates the model
if (success) success(collection, resp, options); // my success callback
collection.trigger('sync', collection, resp, options);
};
wrapError(this, options);
return this.sync('read', this, options);
}
For my needs, it seems the two commented lines need to be switched, though I assume I'm just misunderstanding how to use this feature.
How can I modify the server response before it becomes my model?
I think you could just override the parse function to modify your data as needed
http://backbonejs.org/#Model-parse

Calling Backbone.Model.Save converts child-Backbone.Model to object?

I'm creating a Backbone Model which has a child Backbone Model inside of it:
console.log("inside add item, video:", video instanceof Backbone.Model);
var playlistItem = new PlaylistItem({
video: video,
title: video.get('title')
});
afterwards, I save it:
playlistItem.save({}, {
success: function() {
console.log("Successfully saved.");
playlistItem.get('video').get('title');
}
});
In this example, I encounter an error -- video is not an instanceof Backbone.Model after calling save. Why?
I think you will need to override parse and toJSON.
toJSON: function() {
var json = Backbone.Model.prototype.toJSON.call(this);
// replace backbone model with json.
json.video = this.get('video').toJSON();
return json;
},
parse: function(data) {
// take json of video and set into model.
this.get('video').set(data.video);
delete data.video;
return data;
},
If you don't parse the json data like this, backbone is going to take the 'video' object from the json and overwrite your Backbone model.

override Backbone's Collection-fetch

I want to get my collection in a NON-RESTful way, so I decide to override the Collection.fetch with
App.carClc = Backbone.Collection.extend({
model : App.cardModel,
url : 'http://localhost/bbtest/data.php',
fetch : function() {
$.ajax({
type : 'GET',
url : this.url,
success : function(data) {
console.log(data);
}
});
}
});
I don't know how to set my collection to the response. I'm new to BackboneJS, thanks all of you!
If you want to add a custom "decorator" to fetch, but not override it completely, try:
var MyCollection = Backbone.Collection.extend({
//custom methods
fetch: function(options) {
//do specific pre-processing
//Call Backbone's fetch
return Backbone.Collection.prototype.fetch.call(this, options);
}
});
Here, you don't have to roll out your own $.ajax
Also, don't forget the return in the last line if you want to use the jQuery promise returned by Backbone's fetch method.
See http://japhr.blogspot.in/2011/10/overriding-url-and-fetch-in-backbonejs.html for more details.
Backbone collection has two methods to set new data add and reset. Let's say you want to replace all collection data with the incoming data and therefor use the reset:
App.carClc = Backbone.Collection.extend({
model : App.cardModel,
url : 'http://localhost/bbtest/data.php',
fetch : function() {
// store reference for this collection
var collection = this;
$.ajax({
type : 'GET',
url : this.url,
dataType : 'json',
success : function(data) {
console.log(data);
// set collection data (assuming you have retrieved a json object)
collection.reset(data)
}
});
}
})
I am using something like this:
$.when( $.ajax( URL, { dataType: "json" } ) )
.then( $.proxy( function( response ) {
ctx.view.collection.reset( response );
},ctx ) );
The main point beeing I use collection.reset(data) to reinitialize the collection
If you would like to keep fetch "thenable" for promises then you could also do something like this:
fetch: function() {
var self = this,
deferred = new $.Deferred();
$.get(this.url).done(function(data) {
// parse data
self.reset({parsed data});
deferred.resolve(); //pass in anything you want in promise
});
return deferred.promise();
}
If you need to do this for every model and/or collection, override Backbone.ajax.
Overriding Backbone.ajax gives you the request options that would be normally passed to $.ajax. You only need to return the response of $.ajax (or some other Promise) and don't need to worry about setting stuff in the collection/model.

Categories

Resources