Backbone save callbacks never hit - backbone.js

I have a backbone model:
define(function() {
var ContactModel = Backbone.Model.extend({
urlRoot: 'http://www.somedomain.com',
defaults : {
'name' : null,
'email': '',
'phone': '',
},
validate: function(attrs) {
var name_filter = /[a-zA-Z'.,-\s]+/;
var email_filter = /^([a-zA-Z0-9_\.\-])+\#(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
var errors = [];
if(attrs['name'].length<1){
errors.push({input_tag: 'name', error: 'Please enter your First Name'});
}
if(attrs['phone']==='' && attrs['email']===''){
//messages['name'] = 'You must include a phone number or email';
errors.push({input_tag: 'phone', error: 'You must include a phone number or email'});
}
if(attrs['email']!==''){
if (!email_filter.test(attrs.email)){
errors.push({input_tag: 'email', error: 'Please enter a valid email address'});
}
}
if(errors.length > 0){
return errors;
}
}
});
return ContactModel;
});
In my view, I set the attribute values like this:
this.model.set({
name:$('#name').val(),
phone:$('#phone').val(),
email:$('#email').val(),
});
I do the validation, then save the model with:
this.model.save({
success: function(model){
console.log('successfully saved and model is ');
console.log(model);
},
error: function(){
console.log('there was an error');
}
});
The model gets saved on the server, but success or error callbacks are never hit. What am I doing wrong?

Worked after I changed to:
this.model.save([], {
success: function(model){
console.log('successfully saved and model is ');
console.log(model);
},
error: function(){
console.log('there was an error');
}
});

Related

Cordova contact plugin not working

After calling this function I am getting the following error:
"TypeError: Cannot read property 'pickContact' of undefined"
$scope.pickContact = function() {
navigator.contacts.pickContact(function(contact) {
if(contact) {
$scope.requestData.guestName = contact.displayName;
if(contact.phoneNumbers && contact.phoneNumbers.length > 0) {
$scope.requestData.phoneNo = contact.phoneNumbers[0].value;
} else {
$scope.requestData.phoneNo = null;
}
$scope.$apply();
} else {
$ionicPopup.alert({
title: 'Error!',
template: 'Unable to get contact details'
});
}
}, function(err) {
console.log('Error: ' + err);
$ionicPopup.alert({
title: 'Error!',
template: 'Unable to get contact details'
});
});
};
Use the $cordovaContacts plugin for get contacts and inject the dependency in your controller.
This plugin is available only on devices, not in the browser please do test on device.
For this plugin first you need to install ngCordova, this will support you for many more plugins and implementations.
Install plugin using following command,
cordova plugin add cordova-plugin-contacts
Example :
.controller('MyCtrl', function($scope, $cordovaContacts, $ionicPlatform) {
$scope.addContact = function() {
$cordovaContacts.save($scope.contactForm).then(function(result) {
// Contact saved
}, function(err) {
// Contact error
});
};
$scope.getAllContacts = function() {
$cordovaContacts.find().then(function(allContacts) { //omitting parameter to .find() causes all contacts to be returned
$scope.contacts = allContacts;
}
};
$scope.findContactsBySearchTerm = function (searchTerm) {
var opts = { //search options
filter : searchTerm, // 'Bob'
multiple: true, // Yes, return any contact that matches criteria
fields: [ 'displayName', 'name' ] // These are the fields to search for 'bob'.
desiredFields: [id]; //return fields.
};
if ($ionicPlatform.isAndroid()) {
opts.hasPhoneNumber = true; //hasPhoneNumber only works for android.
};
$cordovaContacts.find(opts).then(function (contactsFound) {
$scope.contacts = contactsFound;
};
}
$scope.pickContactUsingNativeUI = function () {
$cordovaContacts.pickContact().then(function (contactPicked) {
$scope.contact = contactPicked;
}
}
});
Hope this will help you !!

Uncaught TypeError: Cannot read property 'idAttribute' of undefined

I am using Backbone-Relational, and I recieve the following error:
Uncaught TypeError: Cannot read property 'idAttribute' of undefined
When I access the show_note route.
App.Router = Backbone.Router.extend({
routes: {
'note/:_id': 'show_note'
},
show_note: function(_id) {
console.log('this is the show_note route for _id: ' + _id);
var note = new App.Models.Note.findOrCreate({ _id: _id });
var note_view = new App.Views.main_note({ model: note });
note.fetch();
}
});
The console.log recieves the '_id'. But when I attempt to instantiate var note, I recieve the error. How do I fix this?
EDIT 1
Adding the Note model:
App.Models.Note = Backbone.RelationalModel.extend({
urlRoot: '/notes',
idAttribute: '_id',
relations: [{
type: Backbone.HasMany,
key: 'tags',
relatedModel: 'App.Models.Tag',
reverseRelation: {
key: 'note',
includeInJSON: '_id'
}
}]
});
EDIT 2
Stacktrace added
I solved the issue by removing findOrCreate(), and ended up retrieving the model data like so:
App.Router = Backbone.Router.extend({
routes: {
'note/:_id': 'show_note'
},
show_note: function(_id) {
var note = new App.Models.Note({ _id: _id });
note.fetch({
success: function(data) {
var mainNoteView = new App.Views.main_note({ model: note });
$('#mainNote').append( mainNoteView.render().el );
},
error: function(err) {
console.log(err);
}
});
}
});

Backbone save model success and error

I have this backbone code, create a view and model, and calls the save method to save data to database:
var form = document.forms[0];
var RetailerModel = Backbone.Model.extend({
urlRoot: ' retailer.php',
defaults: {
name: 'company-name',
address: 'company-address',
phone: 'company-phone',
icon: 'http://localhost/icon.png'
}
});
var RetailerCollection = Backbone.Collection.extend({
});
var RetailerView = Backbone.View.extend({
className: 'retailer',
template: _.template($('#retailer-template').html()),
initialize: function() {
var obj = {
name: form.name.value,
address: form.address.value,
phone: form.phone.value
};
var o = this;
this.model.save(obj, {
success: function(model, response) {
console.log(model);
console.log(response);
o.render();
console.log('success');
},
error: function(model, response) {
console.log(model);
}
});
},
render: function() {
$('#retailer-list').append(this.$el.html(this.template(this.model.toJSON())));
return this;
}
});
var RetailerViews = Backbone.View.extend({
});
$('#submit').click(function(e){
var retailer_model = new RetailerModel();
var retailer_view = new RetailerView({model: retailer_model});
form.reset();
});
And the php code for receiving data is as follow:
<?php
$connect = mysql_connect('127.0.0.1','root','xxxxxx');
if (!$connect) {
die('Could not connect: ' . mysql_error());
}
mysql_select_db("retail", $connect);
if($_SERVER['REQUEST_METHOD'] == 'POST') //POST GET PUT DELETE
{
$data = json_decode(file_get_contents('php://input'), true);
}
$name = $data['name'];
$address = $data['address'];
$phone = $data['phone'];
$icon = $data['icon'];
if(!(mysql_query("INSERT INTO retailer (name, address, phone, icon)VALUES ('".$name."', '".$address."','$phone', '".$icon."')")))
{
echo 200;
}
else{
echo 'record has not been insert to db';
}
mysql_close($connect);
?>
One problem I'm having is that when the error function is called, the model returned from server still has modified attributes. I am wondering why this is happening and how can I make sure that if error happens, model stays unchanged.
Another question is in the php code, when the sql query is successful, if I echo 200, or '200', backbone will call success, but if I echo a string, backbone will call error, I'm wondering what's the logic behind it.
From the backbone docs:
Pass {wait: true} if you'd like to wait for the server before setting
the new attributes on the model.
If you don't want the model to update until after the save is success full pass wait: true as an option.
this.model.save(obj, {
success: function(model, response) {
console.log(model);
console.log(response);
o.render();
console.log('success');
},
error: function(model, response) {
console.log(model);
},
wait: true // Add this
});
The Backbone
save( so are others like fetch, update...)
returns a promise. You can use
save().done(
function( data ) {}, // success
function( err ) {} // fail
)
just like how you handle promises. The done() method is guaranteed to execute after the server has returned stuff.
See the jQuery API docs for AJAX.jqXHR for more information.
Backbone returns a promise.
Here is what I have to get it works.
save({wait: true}).success(function(data){
console.log(data); //returned data from server
}).error(function(error){
console.log(error); //error returned from server
});

Appending data to same collection after every pagination fetch

I am trying to populate instagram images using backbone,
I have basically 3 models as follows,
User model store all the user info related to instagram
App.Models.User = Backbone.Model.extend({
defaults: {
id: '',
access_token: '',
userid: '',
username: '',
full_name: '',
profile_picture: ''
},
urlRoot: "/api/user/",
initurl: function() {
return "https://api.instagram.com/v1/users/"+this.get('userid')+"/media/recent/?access_token=" + this.get('access_token');
},
initialize: function() {
this.set('id', $('#domdump .id').val());
this.fetch({
success: function(model) {
var photos = new App.Collections.Ig_photos([],{
url: model.initurl()
});
}
});
}
});
A model to store the next url for pagination
App.Models.Ig_next_url = Backbone.Model.extend({
defaults: {
next_url: ''
},
next_url:function(){
return this.get('next_url');
}
});
A model for the photo
App.Models.Ig_photo = Backbone.Model.extend({});
A collection for the multiple photo
App.Collections.Ig_photos = Backbone.Collection.extend({
model: App.Models.Ig_photo,
initialize: function(model, options) {
this.url = options.url;
this.nextSet();
},
sync: sync_jsonp,
parse: function( response ) {
if(response.pagination && response.pagination.next_url && response.pagination.next_url != this.url){
var next_url = new App.Models.Ig_next_url({ next_url: response.pagination.next_url });
this.url = next_url.next_url();
}
return response.data;
},
nextSet: function(){
this.fetch({
success: function(photos){
var ig_photos_views = new App.Views.Ig_photos_view({ collection: photos});
console.log(photos);
}
});
}
});
Also i have some views that does the render with a load more button that calls the nextset of the collection.
What i was trying to achieve is the photos get appended to the collection upon nextset() and the collection get updated with pervious data + new data but right now its getting overwritten.
Also is it okay to instantiate new collection from the modelfetch ?
You shouldn't need to make a new view. You should instead listen to the "add" event being triggered on the collection and render new items accordingly.
nextSet: function(){
this.fetch({add : true}); // The add option appends to the collection
}
This option is detailed in the very good documentation.

Backbone ID double-increment and wrong start

I have a model that looks like this:
var TodosModel = Backbone.Model.extend({
defaults: {
id: null,
content: 'Something Todo',
completed: false
},
url: function() { return 'api/'+this.id; }
});
I'm adding models via:
var todoID = _.uniqueId();
var todoContent = this.newTodoField.val();
var todoCompleted = false;
// Ensure there's something to save
if(todoContent.length>0){
var _this = this;
// Create model
var todo = new TodosModel({
id: todoID,
content: todoContent,
completed: todoCompleted
});
todo.save({}, {
wait: true,
success: function(model, response) {
// Let the events deal with rendering...
_this.collection.add(model);
},
error: function(model, response) {
console.log('Could not create todo');
}
});
}
The problem I'm having is that for some reason every id is double incremented - so if I start with no elements I get 1,3,5,7...
Which holds alright, except if I reload and those ID's are brought in from the API, and then the next generated _.uniqueID is based on the count rendered out.
Any help would be greatly appreciated, here's the full code: http://sandbox.fluidbyte.org/todos/js/todos.js

Resources