backbone.LocalStorage with RequireJS - javascript

Im trying to get up and running with backbone localStorage via the install below
https://github.com/jeromegn/Backbone.localStorage
but I can't figure out how to actually integrate it into my application. I have connected the collection I want to be stored locally (saved) but Im unsure about how to save/fetch models (upon reload).
(function($){
require.config({
paths: {
jquery: "//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js",
underscore: "//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js",
backbone: "//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.2/backbone-min.js",
localStorage: "backbone.localStorage.js"
}
});
define('saved', ['localstorage'], function(){
var saved = Backbone.Collection.extend({
localStorage: new Backbone.LocalStorage('saved')
});
return saved;
});
//---------SINGLE ENTRY MODEL----------
var Entry = Backbone.Model.extend({
defaults: function(){
return{
word: '',
definition: ''
}
}
});
//------------ENTRY MODEL COLLECTION------------
EntryList = Backbone.Collection.extend({
localStorage: new Backbone.LocalStorage('saved'),
model: Entry
});
//-----INSTANCIATE COLLECTION----
var dictionary = new EntryList();
var saved = new EntryList();
.
.
.

actually you had already using the localStorage when you do something like this:
//------------ENTRY MODEL COLLECTION------------
EntryList = Backbone.Collection.extend({
localStorage: new Backbone.LocalStorage('saved'),
model: Entry
});
you're initiating variables dictionary and saved from the same collection, i guess you only want the saved to be localStorage? if it is, then it would not be what you expected.
It is because when you add the localStorage: new Backbone.LocalStorage('saved') property while extending the Backbone.Collection, this collection will be forever using the localStorage.
to use it to save, you just have to call saved.create({ word: 'abc', definition: 'i dun know'})
to fetch the saved entry, simply saved.fetch()
the example in the source gives a good view
by the way, you can always type "localStorage" to check if it is initiated or having any data on the browser console (i;m using Chrome Devtool)

Related

How to get single book details from server using backbone model?

I am creating simple book library using backbone.js. Functionalities are very simple.
1.) Get All Books
2.) Get Particular Book (from server)
3.) Display Books
from the collection i can get all the books. But how can I get single book from server using Models ? I need to make ajax call to server to get the book details. since the details may update pretty soon (I don't want to get it from all books collection)
So far I created Views, Model, Collections as follows
var Book: Backbone.Model.extend({
defaults:{
name: "",
id: ""
}
});
var Library: Backbone.Collection.extend({
model: Book,
url: function(){
return "/books";
},
fetchBooks: function(){
fetch({
success: success_callback,
error: error_callback
});
},
fetchBook: function(bookId){
//how to get single book ?
}
});
How do I get single item from the server using my existing models and collections ?
If you need to use your Model outside the scope of a collection, you need to specify the urlRoot property:
var Book: Backbone.Model.extend({
defaults: {
name: ""
// ** See Note on Defaults below ...
},
urlRoot: "/books"
});
After that you can initialize the Model with a given ID and fetch it:
fetchBook: function(bookId){
var book = new Book({ id: bookId });
book.fetch({
success: function() {
console.log('Received book: ' + book.toJSON());
}
});
}
This will result in a GET request to `/books/{id}'. Assuming the server returns JSON, all your results will be populated as attributes on the book instance.
** NOTE on Defaults: You definitely shouldn't have an id default to an empty string, as Backbone uses the presence or absence of an id to determine if a model has been saved on the server or not. For instance if you ever use model.save(...), Backbone will issue a POST if the id does not exist, or a PUT if the id does exist.

Backbone collection url not defined

I have the following Backbone code, that's supposed to create a collection with a model, and create a new model instance within it, and save it on the server.
var Project = Backbone.Model.extend({});
var Projects = Backbone.Collection.extend({
model: Project,
url: "/api/projects"
});
var projects = new Projects();
projects.add({
"title": "My Project"
}).sync();
However, I get the following error when running this;
A "url" property or function must be specified
I thought the model would inherit the url property from the collection as per the documentation. Why isn't it? What's wrong?
JSFiddle: http://jsfiddle.net/6L8v4dj8/
according to what I see in documentation you should call
projects.sync('create', projects.models[0]) http://backbonejs.org/#Sync
In this case you could use method create, for example:
var Project = Backbone.Model.extend({});
var Projects = Backbone.Collection.extend({
model: Project,
url: "/api/projects"
});
var projects = new Projects();
projects.create({
title: "My Project"
});
Creating a model will cause an immediate "add" event to be triggered on the collection, a "request" event as the new model is sent to the server, as well as a "sync" event, once the server has responded with the successful creation of the model.
documentation

Ember Data not creating an id for new instances

I created a prototype of an Ember app using the Local Storage adapter.
I am now trying to convert the app to use the Ember Data REST adapter with a back-end store.
In the local storage version of the app, Ember generates an id for a new record prior to saving it (and also even if the record is never saved).
For example, in my local storage app, I can log the id in both places
var gecko = this.store.createRecord('gecko', {
date: new Date(),
type: "gecko",
});
console.log(gecko.id, "gecko.id before save");
gecko.save();
console.log(gecko.id, "gecko.id");
By contrast, in the version of the app I'm making with the REST adapter for the back-end store, the id is not logged.
When I check the data Ember is sending to the server, the id is not included (probably because an id was never generated).
Here is the json that Ember is sending to my server
gecko: { type: "alloc", date: "2015-05-30T13:28:27.539Z"}
I am assuming that I am supposed to save the id that Ember generates on my server (which would of course allow it to retrieve the record by id provide my server implements that).
Question: why is there no id being generated?
this is the code
App = Ember.Application.create();
App.Router.map(function() {
this.route("gecko", { path: "/" });
});
App.ApplicationAdapter = DS.RESTAdapter.extend({
//haven't actually any created any code for this part yet
});
App.ApplicationStore = DS.Store.extend({
adapter: App.ApplicationAdapter.create()
});
App.Gecko = DS.Model.extend({
type: DS.attr('string'),
date: DS.attr('date')
})
App.GeckoRoute = Ember.Route.extend({
model: function() {
//currently does nothing. originally I tried to do `return this.store.find('gecko') but since there are no records yet on the backend, it's returning null which leads to an error which Array cannot map over
},
});
App.GeckoController = Ember.Controller.extend({
actions: {
createGeckoButtonClicked: function(){
var gecko = this.store.createRecord('gecko', {
date: new Date(),
type: "gecko",
});
console.log(gecko.id, "gecko.id before save"); //null
gecko.save();
console.log(gecko.id, "gecko.id"); //null
}
}
Note—I'm not sure if it's relevant, but I feel like I'm in a chicken/egg situation with the route because I can't return any entries before I have created them.
So therefore, I'm trying to setup the Ember app to be able to POST an entry to the server, then I will implement the route to retrieve it using return this.store.find('gecko').
When you use the RESTAdapter and save a model, ember-data expects for a valid payload that includes a unique id generated by your backend.
var gecko = this.store.createRecord('gecko', {
date: new Date(),
type: "gecko",
});
/*
Here ember-data expects a payload like this:
gecko: {id: 1, date: "", type: "gecko"}
The id is generated by your backend
*/
gecko.save().then(function(gecko){
console.log(gecko.get('id'))
})
Ember Data doesn't create ids, there isn't anything to stop it from generating non-unique ids. It isn't the source of truth when it comes to gecko records, your database is, so id generation belongs to the db. This is where POST vs PUT comes into play. I want to POST a new gecko record to /api/geckos or I want to PUT gecko record 123 into its place at /api/geckos/123.
If there are no entries in the database you should still be returning a valid response:
{
geckos: []
}
And two other quick things, you should be using getters/setters for property fetching and setting.
var gecko = this.store.createRecord('gecko', {
date: new Date(),
type: "gecko",
});
console.log(gecko.get('id'), "gecko.id before save");
var promise = gecko.save();
And save is an asynchronous process that returns a promise which you can wait to avoid race conditions.
promise.then(function(geckoRecord){
// geckoRecord and geck are the same here, but it's good to know
// it resolves the record
console.log(gecko.get('id'), "gecko.id after save");
console.log(geckoRecord.get('id'), "gecko.id after save");
});

Backbone - Save model changes to local object

I am building an app which will load a JSON file and use that to populate all models. I have to keep a list of changes and then post this back to the server after a 'publish' button is clicked.
I think a combination of using Backbone.LocalStorage and using model change events to then track which models have changes sounds right but it'd help to hear from someone who's gone down this route or solved similar!
Does this approach makes sense? Is there a better one?
If you are trying to track individual changes and not just the final state before saving, then it is probably a good idea to create an Audit model or something similar. You can hook into the change events as you suggested. Saving those Audit models to the server can be done using the standard version (or some batched modification) of Backbone.sync whenever you want. That model might look something like this:
var Audit = Backbone.Model.extend({
defaults : {
auditableType: "", auditableId: null, auditedChanges : ""
},
paramRoot : "audit"
});
var Audits = Backbone.Collection.extend({
model : Audit
});
Then create a Model prototype that all audited models can extend from:
var audits = new Audits();
var AuditedModel = Backbone.Model.extend({
initialize : function (options) {
this.listenTo(this, "change", function (model, options) {
audits.add({
auditableType : this.paramRoot,
auditableId : this.id,
auditedChanges : this.changed
});
});
}
});
Now just extend from your AuditedModel for any models you want to track changes on.
var User = AuditedModel.extend({
paramRoot : "user",
// Do whatever
});

Saving a model in local storage

I'm using Jerome's localStorage adapter with Backbone and it works great for collections.
But, now I have a single model that I need to save. So in my model I set:
localStorage: new Store("msg")
I then do my saves and fetch. My problem is that everytime I do a refresh and initialize my app a new representation of my model is added to localStorage, see below.
What am I doing wrong?
window.localStorage.msg = {
// Created after first run
"1de5770c-1431-3b15-539b-695cedf3a415":{
"title":"First run",
"id":"1de5770c-1431-3b15-539b-695cedf3a415"
},
// Created after second run
"26c1fdb7-5803-a61f-ca12-2701dba9a09e":{
"0":{
"title":"First run",
"id":"1de5770c-1431-3b15-539b-695cedf3a415"
},
"title":"Second run",
"id":"26c1fdb7-5803-a61f-ca12-2701dba9a09e"
}
}
I ran into same issue. Maybe you have something similar to this
var Settings = Backbone.Model.extend({
localStorage: new Store("Settings"),
defaults: { a: 1 }
});
var s = new Settings;
s.fetch();
I changed to
var s = new Settings({ id: 1 });
localStorage adapter check for id like
case "read": resp = model.id ? store.find(model) : store.findAll(); break;
so 0 or "" for id wont work and it will return all models in one
I'm new to backbone.js too, but it looks like the persistence model is analogous to database tables. That is to say, it's designed to create/delete/read records from a table. The localStorage adapter does the same, so what you are doing there is creating a Msg "table"
in localStorage, and creating a new Msg "record" each time, and the adapter gives each new Msg a unique id.
If you just have one object, it's probably easier to just use localStorage directly. The API is really straight forward:
localStorage.setItem("key","value");
Keep in mind that localStorage only deals with key/value pairs as strings, so you'd need to convert to/from string format.
Take a look a this question for more on doing that:
Storing Objects in HTML5 localStorage

Categories

Resources