I am using Titanium to build a desktop app using web technologies. I decided to use Backbone.js as my mvc. The problem is the application runs not on a server. This is my Backbone model and collection:
window.Student = Backbone.Model.extend({
initialize: function(){
this.bind("save", this.value_change);
},
value_change: function(){
alert("Student model saved for : " + this.attributes.first_name);
},
urlRoot : http://localhost:8080/student/,
});
window.Students = Backbone.Collection.extend({
model: Student,
url: 'http://localhost:8080/students/',
});
and try fetching the values from the server using
var students = new Students
students.fetch()
I get this error:
message: "'undefined' is not an object (evaluating '$.ajax')"
I am assuming this has to do with the url part. It is not able to fetch the values from the server. Any Ideas?
The problem is backbone saves models on a server. It does this by sending ajax requests to your server. What you want to do is overwrite the persistence mechanism
Use backbone.localStorage to save state in localStorage rather then a database
collection.fetch() will fire a reset event on the collection, and not a save event. Save is a Model method to execute a POST request to your server, when you want to persist your instance model on your server.
You should try this instead :
window.Student = Backbone.Model.extend({
});
window.Students = Backbone.Collection.extend({
model: Student,
url: 'http://localhost:8080/students/',
initialize: function(){
this.bind("reset", this.value_change);
},
value_change: function(){
alert("Students fetched ");
},
});
var students = new Students();
students.fetch();
I'm not sure what you mean when you say
The problem is the application runs not on a server
But if your javascript does not run on the same domain as your server, you may have some cross domain javascript issues... Here is post with an exemple using Ruby on Rails : http://www.tsheffler.com/blog/?p=428
Thanks for all your answers. The problem laid in loading jquery after backbone. I loaded jquery first and it worked out fine. Thanks to parshap from the irc of #documentcloud.
Try https://github.com/Ask11/backbone.offline
Allows your Backbone.js app to work offline
Related
I'm trying to figure out how to implement Backbone with handlebars (on the server and client) while maintaining SEO.
Consider that I have a RESTful API in where the urls look like:
/api/submissions/:type?/:category?:offset?:limit?
When someone hits mydomain.com/ it initializes my backbone here:
var site = window.site || {};
site.FeedSubmission = Backbone.Model.extend({
});
site.FeedSubmissions = Backbone.Collection.extend({
model: site.FeedSubmission,
url: '/api/submissions/?type=tip&offset=0,30'
});
site.FeedSubmissionView = Backbone.View.extend({
initialize: function() {
console.log(this.collection);
}
});
var submissions = new site.FeedSubmissions();
submissions.fetch({
success: function(coll, res, options) {
var feedSubmissionView = new site.FeedSubmissionView({
collection: submissions
});
feedSubmissionView.render();
},
error: function(coll, res, options) {
console.log('woops')
}
});
var feedSubmissionView = new site.FeedSubmissionView({
collection: submissions
});
This works and instantiates the view with my collection, but if a search engine tries indexing the site, it'll obviously cause trouble because the rendering of the view is being done with JS.
Basically I want the best of both worlds: I want to use Backbone but also get the benefit of serving html to search engines. I'm not going to spin up a phantomjs instance or some headless browser JUST to serve my content to search engines. Primarily because it's too much overhead and flaky at best.
What do I need to do? Bootstrap data into some json and dump that into the page and override Backbone's fetch and sync to populate the models/collections?
I am an IT student and I'm learning how to use Backbone.js. I read all the documentation but I find it easier to learn when I use example apps,because I never have been programming this type of apps,so it was hard and confusing to think of a way to build my own app, so I used https://github.com/dperrymorrow/example-backbone-app to make similar edited app. The example app doesn't have a server side.
Now I need to connect the app to use parse.com as a backend(server-side) instead to use local collection.
If someone could please tell me what should I change and transform in the code so it connects example app to parse.com app with REST API so when I edit something in the app to be syncronized with parse.com.
I will be really grateful if someone is willing to explain this in a more descriptive way than saying :"you should read documentatin" because I did,and I still don't get the point :)
Have a nice day.
It's just about having the right backbone models and collections and settings the right url on the collection and urlRoot on the model. Then you can just can just call backbone methods like sync, save or delete.
Best detailled answer covering also the REST explanation probably is this one.
Cant you just swap the backbone collection and model to Parse's ones?
Parse.com is a webservice providing REST interfaces for anything you like, Lets connect that to our Backbone models.
First of all Lets create a new app on Parse.com, mine is called FunkyAppartments.
Insert the script tag for loading Parse javascript lib into index.html or whathever:
<script src="http://www.parsecdn.com/js/parse-1.5.0.min.js"></script>
Switch the backbone model and collection to use parse types instead (and rename the fetch method if you have extended backbones, since we do not want to overide the one of parse):
//var Appartment = Backbone.Model.extend(); Backbone wo. Parse.com
var Appartment = Parse.Object.extend("Appartment");
//var Appartments = Backbone.Collection.extend({ Backbone wo. Parse.com
var Appartments = Parse.Collection.extend({
model: Appartment,
initializeData: function(){
var self = this;
var callback = function (data){console.log(data); self.reset(data)};
S.Appartments.loadAppartments(callback);
},
loadAppartments: function(callback){
debugger;
this.query = new Parse.Query(Appartment);
var result = this.fetch();
callback(result);
return result;
}
});
I added a debugger tag in the load appartments so that developer tools breaks in the middle of the controller, here I have access to the Appartment private type of the controller, hence i can store some data on the parse server and verify by pasting the below in the developer tools console.
var testAppartment = new Appartment();
testAppartment.save({name: "foobars"}).then(function(object) {
alert("yay! it worked");
});
Yei, the data shows up in the parse.com UI for the app we just added there. And more importantly it shows up in our frontend. That was easy!
I'm confused about send collection or model to the server.
This is my model:
var Person = Backbone.Model.extend({
defaults : {},
initialize : function() {}
});
and this is my collection:
var Usercollection = Backbone.Collection.extend({
model : Person,
url : 'https://api.parse.com/1/classes/_User/'
});
Now, if I would save a model on the server I have first to add in a collection and use save on model or first add in a collection and use save on collection? And least, I have to write an ajax call to post the collection or model in a server?
You should save your model to server.
Save a model: Call save() on model e.g.
var user = new UserModel();
user.save({name: 'SJ', age:'35'}, {
success: function (user) {
// I get a model here with id
}
});
Read these links for more information.
How to save your model data: SO Link
Sample code - by Thomas Davis in his screencast # backbonetutorials.com - Must watch
Server side code for wine cellar app
I have given you the link of server side code to have a look at the APIs to make things more meaningful to you. Hope this helps!
If you want to add the model to the collection after the model is saved, you need to use .create on the collection , which fires the add event on the collection after it gets created..
this.collection.create(model.toJSON() , options);
Use collection.create();
http://backbonejs.org/#Collection-create
Convenience to create a new instance of a model within a collection.
Equivalent to instantiating a model with a hash of attributes, saving
the model to the server, and adding the model to the set after being
successfully created. Returns the new model. ...
var Library = Backbone.Collection.extend({
model: Book
});
var nypl = new Library;
var othello = nypl.create({
title: "Othello",
author: "William Shakespeare"
});
I'm trying to integrate socket.io with backbone.js, so basicly I have a node server that gets data from a database and emit the data to a backbone client, the client's model should somehow retrieve the incoming data but I'm not sure how to put socket.io in the model now, just getting confused after lost of tries. Any expert please enlight me would be much appreciated!
Node server emit data to client in url /pics
app.get('/pics', function(req, res){
db.collection('pics', function(err, collection) {
collection.find().toArray(function(err, items) {
io.sockets.on('connection', function (socket) {
socket.emit('news', items);
});
});
});
});
Client in Backbone model should retrieve the emitted data(this model works for normal http data sending):
window.Pic = Backbone.Model.extend({
urlRoot: "/pics",
idAttribute: "_id",
initialize: function (){},
defaults: {
_id: null,
name: "",
date: "",
}
});
window.PicCollection = Backbone.Collection.extend({
model: Pic,
url: "/pics"
});
I must admit using Backbone on node + socket.io is quite interesting. Still haven't put my mind into it though. First thing first, have you considered using a plugin Backbone for websockets? Some people have created such.
To give another approach, I think you don't really have much of a choice. Using socket.io to listen to incoming data would result in something like that:
socket.on('model', function(attributes) {
// do something
});
So you'd have to have access to some collection where you could update manually your model.
If you wish to really use socket.io INSIDE your model, a more transparent way would be to extend your model to start listening to some custom event on its creation. I'll link a jsfiddle to show what could be done.
Edit: here you go.
Note that this is full of boilerplate. I'm trying to figure out a way to do a generic socketModel. I'll update if I find one.
I created a Android App using Phonegap, jquery and Kendo UI. Also i have a multiple ajax request.
Now on my application i have a create invoice ajax request which uses PUT in adding data to my Rest service. Everything works when if i already created a transaction ( invoice ) and try to create another one the quantity doesn't reverts back to 1 and it doesn't create a new Transaction but only returns the last transaction i created ( NOTE: it calls the Success callback from my ajax ).
My question is how can i clear the cache on android without exiting the app.
update
i discovered that when i successfully create an invoice after that the variables are still filled with data stored from the previous transaction. So how can i somehow reset everything to allow new data. i addded this location.reload(true); but would like to find another solution regarding this problem. thank you.
I experienced a very similar problem when testing the example ToDo backbone.js application in the Developing Backbone.js Applications book by Addy Osmani using Cordova (PhoneGap) and running it on an Android 2.3 emulator.
The problem that I was having was that the first GET or PUTs to a particular URL were being made, but subsequent requests or updates to the same model instance (i.e. same URL) were not sent to the RESTful server, even though the jQuery.ajax calls were returning success.
The issue turned out to be an issue with the Android browser in Android 2.3 not passing on subsequent requests to the same URL. After finding confirmation here: http://jorgenmodin.net/index_html/jquery-and-android-2.3-calling-a-url-again-gives-the-cached-result
I ended up modifying the backbone model and collection url: functions to append a unique timestamp to the URL's. This made each URL unique and then the browser made the ajax request every time as originally desired.
Here is an extract of the code that I used for the collection:
var TodoList = Backbone.Collection.extend({
// Reference to this collection's model.
model: app.Todo,
urlRoot: 'http://<RESTful_server_address_goes_here>/todos/',
url: function() {
var base = _.result(this, 'urlRoot') || urlError();
var ts = new Date().getTime();
// Make sure that there is a trailing slash on the url, and add a timestamp
return base + (base.charAt(base.length - 1) === '/' ? '' : '/') + '?_' + ts;
},
...
});
And here an extract of the code for the model:
app.Todo = Backbone.Model.extend({
url: function() {
var base = _.result(this.collection, 'urlRoot') || urlError();
// if not creating a new item, then append the item id
if (!this.isNew()) base = base +
(base.charAt(base.length - 1) === '/' ? '' : '/') +
encodeURIComponent(this.id);
// now append a timestamp
var ts = new Date().getTime();
return base + '?_' + ts;
},
...
});
Note that, amongst the many things that I tried before coming up with this solution, was simply to set the jQuery.ajax cache (see jQuery.ajax documentation) to false in an override for backbone.sync, but this DOES NOT WORK. Here is the code anyway:
app.sync = function(method, model, options) {
// THIS DOES NOT FIX THE PROBLEM !!
// IT ONLY PREVENTS CACHING ON GET OPERATIONS
// HOWEVER PUT OPERATIONS ARE STILL CACHED BY ANDROID 2.3 BROWSER!!
options.cache = false;
return Backbone.sync(method, model, options);
};