Backbone save with LocalStorage with fetched DB data? - javascript

UPDATE
Ok, so I am still getting into the world of Backbone. But I have an issue with adding in localStorage into the Model.
So this is sorta off working, but I do not know what is going on?
var Model = Backbone.Model.extend({
//localStorage: new Backbone.LocalStorage("SomeCollection"),
url: "/GetMyData",
defaults: {
"id": "",
"datatest1": "",
"test2": ""
}
});
var NewTest = new Model();
NewTest.fetch();
console.log ( NewTest ); //This as DB data
console.log ( NewTest.attributes ); //This is empty
How can the 'attributes' on the 1st console.log contain db data and then the second one be completely empty? The 1st console.log is also empty, if I uncomment the localStorage, so I am guesting I doing something wrong?
Ok, I am not sure what I am doing wrong, but I am using Backbone and on a fetch call, save that id using the LocalStorage plugin. Now I have the fetch call and LocalStorage working apart but can not get them working together.
So my LocalStorage Code
var Model = Backbone.Model.extend({
localStorage: new Backbone.LocalStorage("SomeCollection"),
defaults: {
"id": "",
"datatest1": "",
"test2": ""
}
});
var NewTest2 = new Model();
NewTest2.set({
"id": "99",
"datatest1": "TEST-1-Q22",
"test2": "TEST-2-CL22"
});
NewTest2.save();
So this works, no problems with that. Now I add in a collection, and fetch data form my database. So my fetch code, with collection
var Model = Backbone.Model.extend({
defaults: {
"id": "",
"datatest1": "",
"test2": ""
}
});
var Col = Backbone.Collection.extend({
model: Model,
url: "/GetMyData"
});
var NewTest3 = new Col();
NewTest3.fetch();
console.log( NewTest3 );
I should also say that I am using PHP Slim as the base. The /GetMyData path gets the data from a MySQL database via a PDO connection, which I then convert into a JSON object for Backbone.
Which I assume is good, as that all works, the console.log's list of attributes displays the right data form my DB.
Now when I put the two together, I can not seem to get it to work.
var Model = Backbone.Model.extend({
defaults: {
"id": "",
"datatest1": "",
"test2": ""
}
});
var Col = Backbone.Collection.extend({
localStorage: new Backbone.LocalStorage("SomeCollection2"),
model: Model,
url: "/GetMyData"
});
var NewTest4 = new Col();
NewTest4.fetch();
console.log( NewTest4.save() );
This console.log returns, Uncaught TypeError: undefined is not a function. So I am not sure why? When I set the data in my 1st test, it works fine. Now I have also tried moving the localStorge var into the model but with the same effect.
The main aim for doing this is so I can log all the data coming from the server. When I set a few different data tests, I very much like the way in which this plugin saved the data.
Thanks.
*Please note, I am dyslexic, so I may not have explained myself right, please tell me if there is anything I can re-word to explain myself better. Thank you for your understanding.

Related

Populate Backbone.js JSON response into nested collections inside nested collections/models

My problem is that I am just starting out with Backbone.js and are having trouble wrapping my head around a complex problem. I want to save a form that have infinite fields, and some of the fields also needs to have infinite options. I'm just worried I might have started at the wrong end with a JSON response, instead of building the models/collections first. Here is a short pseudocode of what I try to achieve.
id:
parent: <blockid>
fields: array(
id:
title:
helpertext
options: array(
id:
type:
value:
)
)
Currently I am working with a faked JSON response from the server, which I built from scratch, and now I want to divide it into models and collections on the client side.
//Fake a server response
var JSONresponse = {
"formid":"1",
"fields":[
{
"fieldid":"1",
"title":"Empty title",
"helper":"Helper text",
"type":"radio",
"options":[
{
"optionid":"1",
"value":"Empty option.."
},
{
"optionid":"2",
"value":"Empty option.."
}
]
},
{
// fieldid2
}
]
};
The idea is to add fields as I see fit, and then if the field type is radio/checkbox/ul/ol there must also be an "options" array within the field.
My work so far:
var app = {};
app.Models = {};
app.Collections = {};
app.View = {};
app.Models.Option = Backbone.Model.extend({
});
app.Collections.Options = Backbone.Collection.extend({
model: app.Models.Option
});
app.Models.Field = Backbone.Model.extend({
options: new app.Collections.Options()
});
app.Collections.Fields = Backbone.Collection.extend({
model: app.Models.Field
});
app.Models.Form = Backbone.Model.extend({
formid : "1",
fields: new app.Collections.Fields(),
initialize: function() {
}
});
How do I split up my JSON response into all these models and collections?
(Perhaps I should re-evaluate my approach, and go for something like form.fieldList and form.optionList[fieldListId] instead. If so, how would that look like?)
Edit: Here is a little jsfiddle after many fixes, but I still don't really know how to make the inner options list work.
The easiest solution would be using Backbone Relational or Backbone Associations.
The documentation should be enough to help you get started.
If you don't want to use a library you could override the parse function on the Form model.
app.Models.Form = Backbone.Model.extend({
defaults: {
fields: new app.Collections.Fields()
},
parse: function(response, options) {
return {
formid: response.formid,
fields: new app.Collections.Fields(_.map(response.fields, function(field) {
if (field.options) {
field.options = new app.Collections.Options(field.options);
}
return field;
}))
};
}
});
Now if you fetch a form from the server, the response will be parsed into an object graph of models and collections.
form.get('fields') will return an app.Collections.Fields collection. form.get('fields').first().get('options') will return an app.Collections.Options collection, if any options exist.
Also, you could create the form model like this:
var form = new app.Models.Form(JSONresponse, {
parse: true
});
This would result in the same object structure.
It's quite hard to handle the case of nested models and collections right in plain Backbone.
Easiest way of handling this will be something like this:
var Option = Nested.Model.extend({
idAttribute : 'optionid',
defaults : {
optionid : Integer
value : ""
}
});
var Field = Nested.Model.extend({
idAttribute : 'fieldid',
defaults : {
fieldid : Integer,
title : "",
helper : "",
type : "radio",
options : Option.Collection
}
});
var Form = Nested.Model.extend({
idAttribute : 'formid',
defaults : {
formid: Integer,
fields: Field.Collection
});
https://github.com/Volicon/backbone.nestedTypes
And that's it. Yep, you'll get direct access to the attributes as free bonus, just form.fields.first().options.first().value, without that get and set garbage.

Cannot render Backbone collection in Backbone View

I am trying to render a view for a collection using Backbone.View. But I cannot render the comment view to show the individual comments as a list inside the comments view. Only comments form is rendered. when visited the url of the collection from the address bar the below array is returned as I have written it on the server side code with express.
What can be the issue here I cannot manage to fix? It seems very natural to achieve it with this code, but it is certain that I am missing something. General issue is I am stuck at such detailed points although I can learn a say mvc framework, Backbone, Node, express etc.
CommentsView:
var CommentsView = Backbone.View.extend({
initialize: function (options) {
this.post = options.post;
this.collection = new Comments({post: this.post});//injecting collection from this views options, was injected to this view form router.
this.collection.on('add', this.addComments, this);
},
addComments: function (comment) {
this.$el.append(new CommentView({ model: comment }).render().el);
},
render: function () {
this.$el.append("<h2> Comments </h2>");
this.$el.append(new CommentFormView({post: this.post}).render().el);
return this;
}
});
This is the array returned when the url of collection is visited form the address bar:
[
{
"_id": "547e36df0ca19b2c1a6af910",
"postId": "547d00e30ca19b2c1a6af90b",
"name": "comment one",
"date": "Mon 21 Oct 2014",
"text": "gibberjabber"
}
]
Router method when the route to the comments of the related post is routed to:
comments: function(_id) {
var csv = new CommentsView({ post: this.posts.findWhere( {_id: _id} ) });
this.main.html(csv.render().el);
}
I think it could have something to do with your constructor function for this.collection. When creating a Collection, you should pass in the array as the first parameter and object literal with the options as the second (if you didn't define it when creating the collection class. What I'm thinking is that the "add" event on the collection isn't getting fired so the comments are not being rendered.
var Comments = Backbone.Collection.extend({
model: Post
});
this.collection = new Comments(posts)
I'm guessing that posts is just an array of models

Backbone not parsing JSON correctly

Overview
I have a JSON object being passed to my backbone model. I have a parse function in the backbone model to convert some of the incoming attributes. The issue is when I fetch this model the attributes are not parsed and are just added to the model. The image at the bottom shows that instead of converting password to Password and deleting password it just adds password to the attributes of the object.
Here is my code:
JSON
When I use postman to call my web service I get the response:
{"type":null,"idTeacher":1,"name":"Sean","password":"tst","email":null,"dob":1392940800000}
Model:
window.Teacher = Backbone.Model.extend({
urlRoot: "http://localhost:8080/SIMS/resource/teacher",
defaults: {
"id": null,
"Name": "",
"Password": "",
"email": "",
"dob": "",
"type": ""
},
parse: function(response){
response.id = response.idTeacher;
response.Password = response.password;
response.Name = response.name;
delete response.name;
delete resoponse.password;
delete response.idTeacher;
return response;
}
});
window.TeacherCollection = Backbone.Collection.extend({
model: Teacher,
url: "http://localhost:8080/SIMS/resource/teacher",
parse: function(response){
return response;
}
});
Main.js // This is
before: function(callback) {
if (this.teacherList) {
if (callback) callback();
} else {
console.log('........................................javascript........');
this.teacherList = new TeacherCollection();
console.log('Loading List: Size: ' + this.teacherList.length);
this.teacherList.fetch({success: function() {
console.log('........... ftech success...........');
$('#contents').html( new TeacherListView({model: app.teacherList}).render().el );
if (callback) callback();
}});
}
}
If I debug my Backbone I can see that my parse did not parse any of the variable and the delete calls in the parse did not work either.
UDATE ANSWER
Thanks for the help. The fact that I hadn't the code in the collection class was an issue. But the second reason was that I wasn't looping through the collection to change each of the attributes.
That's because when you call the fetch method for your collection, the parse method that is called is the parse of the collection and not the parse of your teacher model.
When you call the fetch method from the collection the collections expects to receive an array of models and not just one teacher as you described
You are defining your parse method in your Model but calling your Collection fetch method.
In this case, only the parse method of your Collection will be called.

Ember data 1.0 beta how map embedded data

It seems that ember data have many changing up to version 1.0 beta. All works great with version 0.13. now I want update to higher version. In my case we have an embedded model 'user'
App.Post = DS.Model.extend({
subject: DS.attr('string'),
created: DS.attr('number'),
fcreated: function(){
debugger;
var d = new Date(this.get('created'));
return d.toLocaleDateString();
}.property('created'),
reporter: DS.belongsTo('user')
}
App.ApplicationAdapter = DS.RESTAdapter.extend({
namespace: 'restws'
});
The Json from server looks like this.
{
"posts": [
{
"id": "5226f2670364e70ae7d77266",
"subject": "Text",
"created": 1325410935048,
"reporter": {
"id": "5226f2660364e70ae7d771e2",
"firstName": "Doris",
"lastName": "Baumertr"
}
}
I get the following error code 'Uncaught TypeError: Cannot call method 'toString' of undefined'. In the ember source code I see, that in ember-data.js line 2236 the function throw the error 'buildRecord: function(type, id, data) .. ' After debugging I see that the properties type is undefined id is set with the correct id and data is undefined?
What is the mistake? How I can map the embedded data?
Here's actually the exact extractSingle method that you need to implement
App.PostSerializer = DS.RESTSerializer.extend({
extractSingle: function(store, type, payload, id, requestType) {
if(typeof payload.post.reporter !== "undefined") {
var reporter_id = payload.post.reporter.id;
payload.users = [payload.post.reporter];
payload.post.reporter = reporter_id;
}
return this._super.apply(this, arguments);
}
});
Here's a jsbin http://jsbin.com/EKItexU/1/edit?html,js,output
Note, that I had to redefine ajax method in RESTAdapter to emulate the server returning your JSON.
Also, if you are sideloading users in your JSON, than you'll have to update this method so it doesn't overwrite sideloaded users in your payload (payload.users property)
Support for embedded records is gone (for now).
You can handle embedded records yourself by implementing extractSingle and reorganizing your JSON payload.
Please read here for more info about the transition: https://github.com/emberjs/data/blob/master/TRANSITION.md#embedded-records
Hope it helps.

Forming JSON requests in backbone.js

Here is the JSON Object which i need to form.
{
"Header1": {
"Login": {
"SiteId": "",
"UserName": "",
"UserPassword": "",
"UserAlias": ""
},
"Credential": {
"Login": "",
"Password": ""
}
},
"Header2": {
"DestinationID": "",
"UserID": "",
"SourceID": ""
}
}
On the click of login, i need to form this JSON and send to my service using backbone.js. I am just confused on where to form this in backbone.js
var Client = Backbone.Model.extend({
defaults: {
}
});
Should i add my JSON Object to defaults and use them?
The backbone model usually relates to a model or db table on the server side. With this in mind you can use #model.set(attributes) to set the value in the model and then use #model.save to send to the server. If you are storing objects on your server model just define them in backbone before setting in the model.
#model = new Client()
new_object = new Object()
new_object.site_id = ""
new_object.UserName = ""
etc..
#model.set(
Header1: new_object,
Header2: somethingelse
)
#model.save()
If this is not the case and the model doesn't correspond to a model or table on the server you might be better off just using JQuery Ajax call and manually construct the JSON you need as above. Hope this helps.

Categories