Backbone Collection fetch not working - javascript

Hello i have 1 collection and model:
var Album = Backbone.Model.extend({
url: "api/album",
defaults: {
name: ""
}
});
var AlbumCollection = Backbone.Collection.extend({
url: "api/albums",
model: Album
});
If i try to fetch data from that url like this:
var newCollection = AlbumCollection();
newCollection.fetch({
success: function(data) {
console.log(11)
console.log(data)
}
})
its does not fetch data from that url - models in collection are empty. And in network tab in browser - i see there is not www.myurl.com/api/albums - call...
but if if i use jquery get it works:
$.get('api/albums', function(data) {
console.log(data);
})
return valid json.
I cant figure it out, i spent countless hours debuggin this, and searching for a problem, please help.

you missed new keyword
var newCollection = new AlbumCollection();
newCollection.fetch({
success: function(data) {
console.log(11)
console.log(data)
}
})

Related

Why is my datasource not returning all my data in Angular grid application>?

Let me first preface this by saying...I'm a noob and have been pouring over documentation already but I have not found a resolution.
I have built a custom report in PowerSchool SIS using AngularJS to form my grid and am using JSON data to fill it. The problem I am currently having is the grid is only populating 100 items even though there are close to 200 record items.
This is my JS:
//Begin Module - Loads AngularJS
define(['angular', 'components/shared/index'], function(angular) {
var attApp = angular.module('attApp', ['powerSchoolModule']);
// var yearid = window.location.search.split("=")[1];
//Begin Controller
attApp.controller('attCtrl', ['$scope', 'getData', '$attrs', function($scope, getData, $attrs) {
$scope.curSchoolId = $attrs.ngCurSchoolId;
$scope.curYearId = $attrs.ngCurYearId;
loadingDialog();
$scope.attList = [];
//Sets definition of the var dataSource to pull PowerQueries
var dataSource = {
method: "POST",
url: "/ws/schema/query/com.cortevo.reporting.attendance.absencebymonthschoolgrade",
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
},
data: {yearid},
dataType: "json",
pages:"50",
};
console.log(dataSource);
//Sets definition of the var dataSource to pull from JSON files
console.log('loading dataSource');
//var dataSource= {method: "GET", url: "attendancedata.json"};
getData.getAttData(dataSource).then(function(retData) {
if (!retData.record) {
alert('There was no data returned');
closeLoading();
} else {
console.log(retData);
if (!!retData.record[retData.record.length]) {
// retData.record.pop();
}
var i = retData.record.length;
while (i--) {
retData.record[i].attendance_date = new Date(retData.record[i].attendance_date) // Changes the text of the attendance date to a JS data
}
//Sets scope of attList and attName
$scope.attList = retData.record;
$scope.attName = retData.name;
console.log($scope.attList);
closeLoading();
}
});
}]); //End Controller
//Begins factory and invokes PowerQueries if available, error message will trigger if no data returned
attApp.factory('getData', function($http) {
return {
getAttData: function(dataSource) {
return $http(dataSource).then(function successCallback(response) {
return response.data;
},
function errorCallback(response) {
alert('There was an error returning data');
});
}
}
}); //End Factory
}); //End Module
We have confirmed there is nothing wrong with my datasource. I'm stuck and could use a guiding word. Any advice would be appreciated.
Try to hit the same endpoint using PostMan, maybe the API is not working.
Also I'm not sure if this url is valid:
url: "/ws/schema/query/com.cortevo.reporting.attendance.absencebymonthschoolgrade"

How to save data in Vue instance

The question is quite simple,
All I want is to get the data after the AJAX post saved in Vue instace's data.
Here is my code:
const VMList = new Vue({
el: '#MODAL_USER_DATA',
data: {
user: []//,
//userAcc: []
},
methods: {
getUserAcc: function ( userID ) {
this.user = { _id : userID };
var self = this
$.ajax({
url: "/listuser",
type: "POST",
data: this.user,
success: function(data) {
this.user = data ;
//this.userAcc = Object.assign({}, this.userAcc, data );
alert(JSON.stringify(this.user));//show the user correctly (e.g user = data)
$('#popupDeleteModal').modal('show');
alert(JSON.stringify(data));//show data,the entire json object,everything is good
},
error: function(err) {
console.log('error: ',err);
},
});
}
}
});
And after I trigger the getUserAcc(id) method,I try to verify the VMList.user value in browser console,and I get only the id.Seems like after the function is over the data is reset.How could I store the data from the AJAX post request in the user object from data:{...} ?
Thank you for help!!!
The problem is that this inside your ajax return function doesn't refer to the vue instance anymore.
The solution is to save the this keyword into a variable inside the function. Example:
getUserAcc: function ( userID ) {
var that = this;
this.user = { _id : userID };
$.ajax({
url: "/listuser",
type: "POST",
data: this.user,
success: function(data) {
that.user = data;
//Rest of your code
},
error: function(err) {
console.log('error: ',err);
},
});
}
Here is more information about the behavior of the keyword this: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

Backbone Model : Ajax request in parse override

I have a scenario where a fetch() call of a model will return data from which a property will need be passed to another API and return type from that API will be the actually required data.
var Issue = Backbone.Model.extend({
urlRoot: 'https://api.github.com/repos/ibrahim-islam/ibrahim-islam.github.io/issues',
parse: function(response, options){
var markdown = new Markdown({ text : response.body });
markdown.fetch({
contentType: 'application/json',
type: 'POST',
data: JSON.stringify( markdown.toJSON() ),
success: function(data){
response.body = data;
}
});
return response;
}
});
var Markdown = Backbone.Model.extend({
defaults:{
'text': '',
'mode' : 'markdown'
},
url: 'https://api.github.com/markdown'
});
So, when an Issue will be fetched:
var issue = new Issue({id: 1});
issue.fetch().then(function(){
//do stuff
});
It will have a property of body containing markdown syntax text which in turn I need to pass to another API and get the that response which will be passed down to view.
As can be seen from above, I tried overriding parse but its return type has to be an object and fetch will be async so what can I do here to make this work?
NOTE: I know aggregating the data in server and then receiving it will be best idea but that is not possible atm.
You could override the sync method in your Issue model to chain your requests.
var Issue = Backbone.Model.extend({
urlRoot: 'https://api.github.com/repos/ibrahim-islam/ibrahim-islam.github.io/issues',
sync: function(method, model, options) {
if (method !== 'read')
return Backbone.sync.apply(this, arguments);
// first request
var xhr = Backbone.ajax({
type: 'GET',
dataType: 'json',
url: _.result(model, 'url')
});
// second request
return xhr.then(function (resp1) {
var markdown = new Markdown({text : resp1.body || 'body'});
var data = markdown.toJSON();
// the callback to fill your model, will call parse
var success = options.success;
return Backbone.ajax({
url: _.result(markdown, 'url'),
dataType: 'html',
contentType: 'application/json',
type: 'POST',
data: data
}).then(function(resp2) {
// sets the data you need from the response
var resp = _.extend({}, resp1, {
body: resp2
});
// fills the model and triggers the sync event
success(resp);
// transformed value returned by the promise
return resp;
});
});
}
});
The options hash passed to Model.sync contains the callbacks to model.parse, you can use it to set the attributes on your model when you're satisfied with your data.
And a demo http://jsfiddle.net/puwueqe3/5/
I think you would have to override the model's fetch to get this to work
Consider what the default fetch looks like:
fetch: function(options) {
options = _.extend({parse: true}, options);
var model = this;
var success = options.success;
options.success = function(resp) {
var serverAttrs = options.parse ? model.parse(resp, options) : resp;
if (!model.set(serverAttrs, options)) return false;
if (success) success.call(options.context, model, resp, options);
model.trigger('sync', model, resp, options);
};
wrapError(this, options);
return this.sync('read', this, options);
},
(github)
That implementation would not support an async version of model.parse, but since you create a model class using .extend you can override this with your own implementation so lets look at what it does. It takes an options objects, creates a success callback and then delegates to Backbone.Sync.
It's that callback that calls parse and that's what needs to be made to support async.
The quickest, dirtiest way to do this is probably to just copy and modify the existing default fetch.
var MyModel = Backbone.Model.extend({
fetch: function(options) {
options = _.extend({parse: true}, options);
var model = this;
var success = options.success;
options.success = function(resp) {
function parser(resp, options, cb) {
...do your async request stuff and call cb with the result when done...
}
parser(resp, options, function(result) {
if (!model.set(result, options)) return false;
if (success) success.call(options.context, model, resp, options);
model.trigger('sync', model, resp, options);
});
};
wrapError(this, options);
return this.sync('read', this, options);
}
});
This is just an example of how you might try to solve this. I've not tested it and it might not work but I don't see any immediately obvious reasons why it shouldn't.

Backbone JSONP call from RESTful json API not working

I have a RESTful json API, which I need to access in my front-end Backbone site.
So, I did this:
/* Goal collection */
var GoalCollection = Backbone.Collection.extend({
model: GoalModel,
url: "http://staging.api.hiwarren.com:8080/api/v1/goals/?callback=?",
sync: function(method, collection, options) {
options.dataType = "jsonp";
// options.timeout = 10000;
return Backbone.sync(method, collection, options);
},
parse: function(response) {
return response.results;
}
});
/* View for the goal collection */
var GoalCollectionView = Backbone.View.extend({
tagName: 'ul',
initialize: function(callback){
var that = this;
_.bindAll(this, 'render');
that.collection = new GoalCollection();
that.collection.bind('reset', this.render)
that.collection.fetch({
dataType: 'jsonp',
success: function(collection, response){
that.render();
if(callback) callback(that);
},
error: function(collection, response){
throw new Error("Goal fetch error - " + response.statusText);
}
});
},
render: function(){
this.collection.each(function(goal){
var goalView = new GoalView({ model: goal });
this.$el.append(goalView.render().el);
}, this);
return this;
}
});
I am trying to use JSONP, because it is a different domain. I've followed answers to questions similar to this, as you can see in my code, but it doesn't work.
Instead, I get this error message:
Uncaught Error: Goal fetch error - load
Backbone.View.extend.initialize.that.collection.fetch.error
options.errorjquery.js:3094 jQuery.Callbacks.fire
jQuery.Callbacks.self.fireWithjquery.js:8261 done
jQuery.ajaxTransport.send.jQuery.prop.on.callback
jQuery.event.dispatchjquery.js:4116 jQuery.event.add.elemData.handle
What am I doing wrong? How can I make this work?
Are you sure that the domain you are trying to access has support for jsonp? Some sites only enable the json format.

Backbone.js default path (subdomain)

I am using CORS so all the API happens in api.mywebsite.com but the website is served via website.com.
I am wondering if there's a way I can set the setting of either jQuery or Backbone to always make AJAX requests to my api.mywebsite.com ?
In otherwords, I want to do this in my backbone collections:
url: '/books'
and have it automatically infer api.mywebsite.com/v1/books
For the collection you can specify the full URL:
YourApp.Collections.Books = Backbone.Collection.extend({
model: YourApp.Models.Book,
url: 'http://api.mywebsite.com/v1/books/'
});
And for individual resources you can use a function to generate the url:
YourApp.Models.Book = Backbone.Model.extend({
url: function() {
return 'http://api.mywebsite.com/v1/books/' + this.get('id')
}
});
Backbone has the urlRoot method that sets the root of all requests.
From the Backbone site:
var Book = Backbone.Model.extend({urlRoot : '/books'});
var solaris = new Book({id: "1083-lem-solaris"});
alert(solaris.url());
alerts "/books/1083-lem-solaris"
Of-course you can change that relative path to something else: put a dot in front to send it to the site root, or your specific site root, or give it an absolute path.
Documentation
Of course in jQuery you can build the URL to whatever you like in an AJAX request. Including to an absolute url as long as it's not another domain:
$.ajax({
type: "GET",
url: "http://api.mywebsite.com + "anything_you_want_to_add"
}).done(function(response) {
console.log(response);
receiveResponseMethodSomewhereElse(response);
});
And a quick Backbone example of using the url parameter of the Model or the Collection:
The showing the scripts I used:
<title>Backbone Test</title>
<meta charset="UTF-8">
<script src="jquery.js"></script>
<script src="underscore.js"></script>
<script src="backbone.js"></script>
And then I specifically pointed this backbone example at my localhost. You'd want to point it to your domain. I included all of the console logs and available responses for your debugging pleasure. Both options here are building urls from the book id as that's normall what your creating, Reading, Updating or Deleting from the server. I put this script directly within the body of the page and watched the console logs. Note: Backbone is expecting a JSON response.
<script>
var Book = Backbone.Model.extend({urlRoot: 'http://localhost/url_test'});
var BookCollection = Backbone.Collection.extend({
model: Book,
url: 'http://localhost/url_test'
});
var myExcellentBook = new Book({id: "book"});
var MyBooks = new BookCollection();
// getting it directly from the model
solaris.fetch({
success: function(model, response, options) {
console.log("SUCCESS");
console.log(model);
console.log(response);
console.log(options);
},
error: function(model, response, options) {
console.log("ERROR");
console.log(model);
console.log(response);
console.log(options);
},
complete: function(xhr, textStatus) {
console.log(textStatus);
}
});
// or fetch directly from the collection and
// normally you'd loop through the response or
// when creating new models, you can let backbone
// intialize them through the response
MyBooks.fetch({
success: function(model, response, options) {
console.log("SUCCESS");
console.log(model);
console.log(response);
console.log(options);
},
error: function(model, response, options) {
console.log("ERROR");
console.log(model);
console.log(response);
console.log(options);
},
complete: function(xhr, textStatus) {
console.log(textStatus);
}
});
</script>
And the php script at url_test is simply returning a JSON object.
<?php
echo '[{"id": "MyNewBook"}]';

Categories

Resources