I am using a requirejs with backbone. The script runs without error but model.fetch() does not update the model. The two files for Backbone.js are:-
In main.js I have
'use strict';
require(['pageElements'],function(pageElements){
$( document ).ready(function() {
var country = new pageElements.country();
country.fetch({
success: function(e){
console.log(country.get('areaLevelZeroID')); // returns undefined
}
});
});
});
In pageElements.js I have
define(function() {
var country = Backbone.Model.extend({
url : 'resources/js/backBoneSandBox/countries.php',
parse: function(data){
newData = JSON.parse(data);
console.log(newData.areaLevelZeroID); // returns 1
return data;
}
});
return ( country );
});
Where the parse function is returning the correct value but not updating the model.
resources/js/backBoneSandBox/countries.php is tested and returns the jSON String
{"areaLevelZeroID":"1","areaLevelZeroName":"Afghanistan"}
I must be missing something really simple but I just can't see what. Thank you in advance for any advice you can offer.
In general flow is fetch - parse - set - success handler.
In your case you receive string response from the server, so you have to parse it to JSON, before calling set on the model. Thats why, you had to return newData;
Related
I'm trying to set up a model using backbone that loads from a remote url: https://api.github.com/legacy/repos/search/javascript. Here is what I have so far.
var Repo= Backbone.Model.extend({});
var RepoCollection = Backbone.Collection.extend({
url : "https://api.github.com/legacy/repos/search/javascript",
model : Repo
});
var repos = new RepoCollection();
repos.fetch({success: function(){
console.log(repos.models);
}});
This just gives me an empty array. Why does this not work? This url just contains a non-empty JSON array. I've also tried the parse function without any success.
parse : function(data) {
return data.results;
}
If the github api does not support this kind of call, does anyone have an example of a remote url where I can use backbone to fetch data?
Edit: I should add that I looked at the network console on Chrome and I am getting a 200 OK response with correct JSON response from github. I guess I'm just having trouble figuring out how to access that data and populate my RepoCollection with it.
Your data is wrapped in a repositories key, not in results and looks like this
{
"repositories": [
...
]
}
Try
var RepoCollection = Backbone.Collection.extend({
url : "https://api.github.com/legacy/repos/search/javascript",
model : Repo,
parse : function(data) {
return data.repositories;
}
});
and a demo http://jsfiddle.net/nikoshr/vHX7C/
You can try:
repos.fetch({success: function(data){
console.log(data);
}});
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
Struggling to load json from file (myData.json) on URL into an object so I can access property values.
-- The data loads immediately, I need it a lot in the app.
-- I'm going to access the data throughout the app, not just as part of one function that happens immediately after the data loads.
-- I've ensured the data in my file is properly formatted json.
Following the example on the jquery API, shouldn't I be able to do something simple like:
alert(jqxhr.myProperty);
and get the value? What step am I missing here? I've tried running eval and a variety of things like
var myObj=JSON.parse(jqxhr);
to no avail.
Please....thank you.
// Assign handlers immediately after making the request,
// and remember the jqxhr object for this request
var jqxhr = $.getJSON("example.json", function() {
alert("success");
})
.success(function() { alert("second success"); })
.error(function() { alert("error"); })
.complete(function() { alert("complete"); });
// perform other work here ...
// Set another completion function for the request above
jqxhr.complete(function(){ alert("second complete"); });
I think you are making it too complicated :)
var JSON;
$.getJSON('example.json', function(response){
JSON = response;
alert(JSON.property);
})
//feel free to use chained handlers, or even make custom events out of them!
.success(function() { alert("second success"); })
.error(function() { alert("error"); })
.complete(function() { alert("complete"); });
the getJSON function automatically converts your response into a proper JSON object. No need to parse.
You mentioned that you are using this data all over the place, so you will have to wait for the ajax call to complete before the data is accesible. That means either wrapping your entire application in the getJSON callback. Or using a custom event to determine like so:
var JSON;
$(window).on('JSONready', function(){
alert(JSON.property);
});
$.getJSON('example.json', function(response){
JSON = response;
$(window).trigger('JSONready');
});
$('#elem').on('click', function(){
//event likely to take place after ajax call has transpired
//it would still be better to assign this listener in a callback,
//but you can get away with not doing it, if you put in a catch
if(JSON){
alert(JSON.property);
}
});
EDIT
After a quick live debug, the real reason for the data being unavailable was this: javascript that consumes JSON was located in a file include the page document NORTH of inline javascript performing the call. As a result JSON was not a global variable, and scope prevented its usage. If you truly need a variable to be global so it can be used with inline JS as well as any and all included js files, you may do so like this:
(function(){
var limitedScopeVariable = 25;
window.globalScopeVariable = 30;
})();
$(function(){
alert(globalScopeVariable); //works!
alert(limitedScopeVariable); //fails!
});
EDIT 2
As of jQuery 3.0, callback functions are different: The
jqXHR.success(), jqXHR.error(), and jqXHR.complete() callback methods
are removed as of jQuery 3.0. You can use jqXHR.done(), jqXHR.fail(),
and jqXHR.always() instead
from the comments #mario-lurig
the json data is passed to the callback function of $.getJSON.
So this would work:
var jqxhr;
$.getJSON("example.json", function(data) {
jqxhr = data;
});
// alert(jqxhr.property);
// caution: this won't work immediately on load, since the ajax call runs asynchronously and hasn't finished at that time
// it should be available at a later time, like a click event
$('a#something').click(function(){
if(jqxhr){
alert(jqxhr.property);
}else{
alert('getJSON not yet complete or failed');
}
});
I think this would be what you are looking for, you are trying to access the data returned from your call not the caller object itself. In your example, jqxhr is the object that handles the JSON call not the data. So,
$.getJSON("example.json", function(data) {
yourDATA = data;
})
//Use your data here
alert(yourDATA.aProperty);
The very first example on this page is similar to what I explained.
I fetch a json object from the server and populate my view. I then change the data, push it back to the server. I then fetch a new copy of the data hoping it will refresh my view with any changes. However that doesn't happen. TIA
$(document).ready(function() {
var customer_id = get_customer_id();
var data = load_model();
contract_model = ko.mapping.fromJS(data,{});
ko.applyBindings(contract_model);
}
function load_model(){
var url = '/ar/contract_json?contract_id='+get_contract_id();
var data = '';
$.ajax({
type:'GET',
url:url,
async:false,
success: function(returningValue){
data = returningValue;
}
});
return data;
}
This initial load works fine. I then do some stuff and change one of the observables and push that data back to server. Server gets the update and then I do a new fetch of the data so that view will refresh (i know i can pass back the new data in one step but this in code i haven't refactored yet).
function refresh_data(contract_model){
var url = '/ar/contract_json?contract_id='+get_contract_id();
$.post(url,function(data){
console.log(data);
ko.mapping.fromJS(contract_model,{},data);
ko.applyBindings(contract_model);
console.log(ko.mapping.toJS(contract_model))
});
}
function refresh_data(contract_model){
var url = '/ar/contract_json?contract_id='+get_contract_id();
$.post(url,function(data){
console.log(data);
ko.mapping.fromJS(contract_model,{},data);
console.log(ko.mapping.toJS(contract_model))
});
}
function push_model(contract_model,refresh){
var url = '/ar/update_contract';
var data = {'contract':ko.mapping.toJSON(contract_model)}
delete data['lines'];
$.post(url,data,function(return_value){
if (refresh){
refresh_data(contract_model);
};
});
}
The console messages all show the new data coming back but my view never updates.
I believe the problem is with the order of parameters you pass into the ko.mapping.fromJS function when you are updating contract_model.
You have:
ko.mapping.fromJS(contract_model,{},data);
you want:
ko.mapping.fromJS(data, {}, contract_model);
#seth.miller's answer is correct. You can also leave out the middle "options" parameter if your contract_model is the same one that was mapped earlier. If there are only two arguments, ko.mapping.fromJS checks if the second argument has a "__ko_mapping__" property. If so, it treats it as a target, otherwise it treats it as an options object.
Based upon #DBueno's observation - for anyone using typescript I strongly recommend commenting out this method signature from your knockout.mapping.d.ts file.
// fromJS(jsObject: any, targetOrOptions: any): any;
Yes - just comment it out.
You'll then get a compile time error if you try to do :
ko.mapping.fromJS(item.data, item.target);
and you can replace it with the much safer
ko.mapping.fromJS(item.data, {}, item.target);
Safer because whether or not item.target has been previously mapped (and therfore would have a __ko_mapping__ property) it will always copy the properties.
Using the following as an example:
var Case = Backbone.Model.extend({
initialize: function(){
this.bind("error", function(model, error){
console.log(error)
});
},
url: function() {
return '/api/kase?id=' + this.get("id");
},
validate: function(attrs) {
return "An error";
}
});
In this case the validate method does not get called:
var kase = new Case();
kase.save();
In this case the validate method does not get called either:
var kase = new Case({subject: null});
kase.save();
In this case the validate method does get called, but the POST request is still made on save:
var kase = new Case();
kase.set("subject",null);
// An error
kase.save();
// POST http://localhost.local/api/kase?id=undefined 404 (Not Found)
Is this the expected behaviour? Am I missing something with regard to 'cancelling' the POST/PUT request when client side validation fails? Or should I be checking for a valid model before hitting the save method? (think the penny may have just dropped).
Any guidance would be most appreciated.
A set that fails won't update the model data while a call to save without parameters will post/put the current state of the model to the server (empty in your case). On the other hand, if you call your save method with the data to be validated, it will stop if the validation fails:
var kase = new Case();
kase.save({subject:null});
should log an error and stop before posting to the server.
Do you have code elsewhere that is calling save on the model?
Backbone does not call the server when setting a model's attributes; even if the validation fails.