Code
MyClass = Backbone.Model.extend({
url: '/apiurl/'+sessionValue+'',
defaults: {
data1: '',
data2: 1
}
});
var myobj = new MyClass ();
var myobjvalue = {
data1: "myvalue"
};
myobj.save(myobjvalue , {
success: function (myobj , response) {
alert("success");
},
error : function (myobj , response) {
var data = JSON.stringify(response);
console.log(data);
}
})
in the above code, save function successfully calls the REST api. (200 OK). However even after that it enters in error block.
value printed in console
{"readyState":4,"responseText":"Success","status":200,"statusText":"OK"}
What should I be doing?
===================================
What worked
Instead of string, I had to return actual object as part of REST API. apprently, backbone expects class object along with HTTP status. so responseText contained full myobj.
What worked
Instead of string, I had to return actual object as part of REST API. apprently, backbone expects class object along with HTTP status. so responseText contained full myobj.
Related
newbie here.
I am trying to understand how I need to structure asynchronous calls within my controller to fit my specific use case:
Consider the following code snippet from an Angular Module in "service.js" within my project:
function getSearchObjects(projectName, title) {
var payload = JSON.stringify({
"title": title
});
var request = $http({
method: 'post',
url: URL + '/search/' + projectName,
data: payload
});
return request.then(handleSuccess, handleError);
};
function runQuery(projectName, fromDate, toDate, sort, direction, columns) {
var from = Date.parse(fromDate);
var to = Date.parse(toDate);
var payload = JSON.stringify({
"fromDate": from,
"toDate": to,
"sort": sort,
"direction": direction,
"columns": columns
});
console.log(payload);
var request = $http({
method: 'post',
url: URL + '/query/' + projectName,
data: payload
});
return request.then(handleSuccess, handleError);
}
function handleSuccess(response) {
return response.data;
};
function handleError(response) {
if (!angular.isObject( response.data ) || !response.data.error) {
return( $q.reject( "An unknown error occurred." ) );
}
return $q.reject( response.data.error );
};
});
Within my controller, I am trying to troubleshoot the following function:
$scope.submit = function() {
var objectProperties = exportsStorageService.getSearchObjects($scope.selected.project.name, $scope.selected.search)
.then(function(result) {
exportsStorageService.runQuery($scope.selected.project.name, $scope.selected.start_date, $scope.selected.end_date, objectProperties.sort, objectProperties.direction, objectProperties.columns)
},
function(error) {
console.log(error);
});
};
getSearchObjects matches a title ($scope.selected.search) selected in my UI and grabs the following more detailed object from an API call:
{ title: 'Duplication Example',
sort: '#_traac-timestamp',
direction: 'desc',
columns: [ '#_traac-remote_ip', 'c-platform-m-distinct-id_s', '_type' ] }
I am trying to grab the properties returned from getSearchObjects and pass them along with a few user selected values from my UI to runQuery, which then returns data from a database to the user, but when I check the values passed to runQuery using the above logic in my controller, I get the following values. All of the objectProperties values I am attempting to pass to runQuery are undefined:
project_name: "Example Project"
start_date: 1499770800000
end_date: 1499943600000
sort: undefined
direction: undefined
columns: undefined
I have been trying to debug this, but I am too new to using Angular and asynchronous calls to really understand what I am doing wrong. My best guess currently is that I am calling runQuery before the values retrieved from getSearchObjects are attached to objectProperties. Either that or I am incorrectly referencing the properties within the objectProperties variable.
Could someone help me troubleshoot this issue, and better understand what I am doing wrong?
Thank you in advance for your help!
When you do this:
var objectProperties = some async function...
You are assigning the promise of the async function to the variable, not the result of it.
The result is coming in the .then, like you declared:
.then(function(result) { ... }
So, instead of objectProperties.sort, objectProperties.direction, objectProperties.columns, try using result.sort, result.direction, result.columns :)
If you are new to Promises, take a look at this simple, but great tutorial.
EDIT
Based on your comment, you are receiving, inside the response.data, the following object:
{"objectMatch": {
"title": "doc-event",
"sort": "#_traac-timestamp",
"direction": "desc",
"columns": [
"m-doc-name_s",
"m-user_s",
"m-full-action-type_s",
"m-event-action-descriptor_s"
]}
}
So you have: response > data > objectMatch > properties you want.
The response.data you are extracting on your handleSuccess function:
function handleSuccess(response) {
return response.data;
};
So here, your result is response.data, containing the property objectMatch.
$scope.submit = function() {
var objectProperties = exportsStorageService.getSearchObjects($scope.selected.project.name, $scope.selected.search)
.then(function(result) {
...
},
...
If all of that is correct, you should be able to access the values you want using result.objectMatch.<sort, direction or columns>, like:
exportsStorageService.runQuery($scope.selected.project.name, $scope.selected.start_date, $scope.selected.end_date,
result.objectMatch.sort, result.objectMatch.direction, result.objectMatch.columns)
I've been trying to make a request to a NodeJS API. For the client, I am using the Mithril framework. I used their first example to make the request and obtain data:
var Model = {
getAll: function() {
return m.request({method: "GET", url: "http://localhost:3000/store/all"});
}
};
var Component = {
controller: function() {
var stores = Model.getAll();
alert(stores); // The alert box shows exactly this: function (){return arguments.length&&(a=arguments[0]),a}
alert(stores()); // Alert box: undefined
},
view: function(controller) {
...
}
};
After running this I noticed through Chrome Developer Tools that the API is responding correctly with the following:
[{"name":"Mike"},{"name":"Zeza"}]
I can't find a way to obtain this data into the controller. They mentioned that using this method, the var may hold undefined until the request is completed, so I followed the next example by adding:
var stores = m.prop([]);
Before the model and changing the request to:
return m.request({method: "GET", url: "http://localhost:3000/store/all"}).then(stores);
I might be doing something wrong because I get the same result.
The objective is to get the data from the response and send it to the view to iterate.
Explanation:
m.request is a function, m.request.then() too, that is why "store" value is:
"function (){return arguments.length&&(a=arguments[0]),a}"
"stores()" is undefined, because you do an async ajax request, so you cannot get the result immediately, need to wait a bit. If you try to run "stores()" after some delay, your data will be there. That is why you basically need promises("then" feature). Function that is passed as a parameter of "then(param)" is executed when response is ready.
Working sample:
You can start playing with this sample, and implement what you need:
var Model = {
getAll: function() {
return m.request({method: "GET", url: "http://www.w3schools.com/angular/customers.php"});
}
};
var Component = {
controller: function() {
var records = Model.getAll();
return {
records: records
}
},
view: function(ctrl) {
return m("div", [
ctrl.records().records.map(function(record) {
return m("div", record.Name);
})
]);
}
};
m.mount(document.body, Component);
If you have more questions, feel free to ask here.
I am currently working on my webapp and in one of its components I am getting some DB data with :
var SelectHund = React.createClass({
getInitialState: function() {
return {
hunde:{}
};
},
componentDidMount: function(){
var that = this;
$.ajax({
type: "POST",
url: "/foodoo/index.php?method=getDogs",
data: JSON.stringify(planData),
success: function(response){
var hunde = JSON.parse(response);
console.log(hunde);
if(hunde.length >= 1){
that.setState({
hunde: hunde
});
}
},
error: function(){
}
});
},
render: function(){
if(this.state.hunde.length <= 0){
return(<div>test</div>);
}else{
// console.log(this.state);
// console.log(this.state.hunde);
var POS = this.state.hunde.map(function(i){
console.log(i);
return <option key={i.id} value={i.weight}>i.name</option>;
});
return(<select className="selectHund" name="hund">{POS}</select>);
}
}
});
The component gets called like this:
return (
<div>
<h2>{this.state.planname}<span className="close">x</span></h2>
<SelectHund changeHund={this.changeHund} />
...
With that method I run through the response object with the map function, the console.log of "i" returns the single objects like following :
Object {id: "1", user_id: "1", name: "Balou", weight: "15", activity: "1"…}
Object {id: "2", user_id: "1", name: "Franzi", weight: "70", activity: "1"…}
So I guess there is no error with the object handling.
Unfortunately I keep getting this error in the console :
Uncaught Error: Invariant Violation: SelectHund.render(): A valid ReactComponent must be returned. You may have returned undefined, an array or some other invalid object.
I have tried calling an external function outside of the ajax function to see if this may cause the error but it doesn't. Some other amateur tries to debug it failed as well - So I need your help ^^
Your render method does not return anything. You need to move this line:
return(<select onChange={that.props.changeHund} className="selectHund" name="hund">{POS}</select>);
to outside the success callback. Then you will be facing other problems, but it’s in the right direction.
Instead of doing Ajax inside the render function, move it to another lifecycle method (like componentDidMount) or a data model like Flux.
Then use states or props to handle internal component data (in your example, the hunde object). Following some examples from the docs/tutorials should get you started.
This is possibly just the way I am accessing the resource object but I have the service below:
angular.module('appointeddPortalApp')
.factory('Salon', function ($resource) {
// Service logic
// ...
// Public API here
return $resource('http://api.appointeddcore.dev/organisation/:id', {id: '#id'}, {
update: { method: 'PUT' },
query: { method: 'GET', isArray: false}
});
});
I'm using the query method like this:
var data = Salon.query($scope.options);
console.log(data);
From the console.log() :
Resource {$get: function, $save: function, $query: function, $remove:
function, $delete: function…}
offices: Array[20]
total: 33
__proto__: Resource
My problem is trying to access total or offices I get undefined
console.log(data.total); // undefined
Because Salon.query() returns immediately with an empty object and updates the variable data if the data is present, try this:
var data = Salon.query(function(callbackdata){
//function is called on success
console.log(callbackdata);
console.log(callbackdata.total);
});
I have a rails controller which sends a mash-up of models as a global json object. Something like this
{
dogs : { species: {}, ...},
cats : { food: {}, ...},
foxes : { },
...,
...
}
On my client side, I have all these entities neatly segregated out into different backbone models and backbone collections.
On some onchange event, I need to send a mashup of some model attributes back to the server as a HTTP POST request and the server sends a response which again spans values across a few models.
How do I setup Backbone.sync to deal with such an ajax scenario? I do not want to change the rails backend because its quite a steady implementation. Or do I make vanilla $.ajax requests through jQuery in one of my backbone views and handle it in a callback on ajax success/failure?
I think there are a couple of ways to do this via backbone. I think I'd start out with a model to represent the mashup:
var MashupModel = Backbone.Model.extend({
});
Then you can pass in any models like you would normally (or a collection for that matter):
var my_mash = new MashupModel({
dog: dogModel.toJSON(),
cat: catModel.toJSON(),
foxes: foxCollection.toJSON()
});
// do stuff if you need...
Then do what you want when the response comes back like normal:
my_mash.save({}, {
success: function(model, response) {
// do stuff here to put new data into the proper models / collections
},
error: function() { alert("I FAIL!"); }
});
That's all well and good... however, I think it would be better to push the above down into the MashupModel object instead of at the request level. Again, several ways:
var MashupModel = Backbone.Model.extend({
initialize: function(attrs) {
// can't remember the actual code, but something along the lines of:
_.each( attrs.keys, function(key) {
this.set(key, attrs.key.toJSON();
});
},
save: function(attrs, opts) {
var callback = opts.success;
opts.success = function(model, response) {
// do your conversion from json data to models / collections
callback(model, response);
};
// now call 'super'
// (ala: http://documentcloud.github.com/backbone/#Model-extend)
Backbone.Model.prototype.set.call(this, attrs, opts);
}
});
Or you could override toJSON (since backbone calls that to get the attrs ready for ajax):
// class definition like above, no initilize...
...
toJSON: function() {
// again, this is pseudocode-y
var attrs = {};
_.each( this.attributes.keys, function() {
attrs.key = this.attributes.key.toJSON();
});
return attrs;
}
...
// save: would be the same as above, cept you'd be updating the models
// directly through this.get('dogs').whatever...
Now, you can just do:
var my_mash = new MashupModel({
dog: dogModel,
cat: catModel,
foxes: foxCollection
});
// do some stuff...
my_mash.save({}, {
success: function(model, response) {
// now only do stuff specific to this save action, like update some views...
},
error: function() { alert("I FAIL!"); }
it would be possible, but may be difficult to modify backbone.sync to work with this structure. i'd recommend going with plain old jquery $.ajax requests. then on success, pull the info apart and populate your collections.
$.get("/whatever", function(data){
catCollection.reset(data.cats);
dogCollection.reset(data.dogs);
// etc
});
data = {};
data.cats = catCollection.toJSON();
data.dogs = dogCollection.toJSON();
// etc
$.post("/whatever", data);