PouchDB put call getting 409: Document update conflict - backbone.js

stack:nodejs, backbone.js v1.3.3, underscore.js v1.8.3, JQuery v2.2.4, cordova v6.1.1, https://pouchdb.com/download.html v6.0.5, https://github.com/jo/backbone-pouch v?, https://github.com/apache/cordova-plugin-device
I've polled the todos-db for the record using the _id and updated the _rev attribute, but I can't find my way out of these conflicts, so all help appreciated:
In my TodoModel, I'm doing:
return Backbone.Model.extend( {
idAttribute: "_id",
db: new PouchDB( "todos-db" ),
sync: this.BackbonePouch.sync( {
db: this.db,
fetch: "query",
options: {
query: {
include_docs: true
}
}
} ),
initialize: function(){
this.listenTo( Backbone, "updateRec", function( model ){
this.updateRec( model );
} );
},
updateRec: function( revRec ){
var self = this;
console.log( "revRec:", revRec );
this.db.get( revRec._id, { conflicts: true } ).then( function( doc ){
console.log( "doc:", doc ); // doc has no conflicts
revRec._rev = doc._rev;
return self.db.put( revRec );
} ).then( function( result ){
console.log( "updateRec result:", result );
return result;
} ).catch( function( err ){
// TODO: the above 'put' is throwing multiple confict errors, yet the db is updating after 7 tries
console.log( err );
} );
}
} );
});
In the log, revRec gives me:
_id:"2016-09-27T16:45:34.297Z"
_rev:"5-b554a2b4989efedac3ca3ccb679aa42e"
completed:false
delegatedTo:"Jen"
due:"Friday"
priority:"A"
project:"home"
task:"MBath concept"
The 'put' result gives me:
{ok: true, id: "2016-09-27T16:45:34.297Z", rev: "6-c6647848d965c35c7ac4f968cac7a91b"}
and the catch err is:
CustomPouchError {status: 409, name: "conflict", message: "Document update conflict", error: true}

You might want to look into pouchdb-upsert or read about conflicts.
In your code, I believe your particular error most likely stems from race conditions in requesting the same document multiple times (e.g. if the user clicks very quickly?). pouchdb-upsert would automatically handle such errors for you.

Related

`node` api getting error on `post` - body param being as labels how to solve this?

I am posting the data to back-end using postman, which works fine. Using the same api I am trying to post the data through angular gives me the issue. But I understand that something going on wrongly between my form data with post process which i am not able to understand.
here is the post function:
.post(function( req, res ){
console.log(' called ', req.body ); 1. //getting all properties
var family = new Family();
family.username = req.body.username,
family.password = req.body.password,
family.familyLeader = req.body.familyLeader,
family.husband = req.body.husband,
family.wife = req.body.wife,
family.kids = req.body.kids;
console.log( 'family username', req.body.username ); 2.//undefined? not getting
family.save(function( err, newFamily ) {
if( err ) {
if ( err.code == 11000) {
return res.json({ success: false, message: 'A user with that username already exists. '});
}
else {
return res.send( err );
}
}
res.json({ message: 'Family created!', newFamily: newFamily });
});
})
There is 2 console I have in above call, in the first console I am getting the properties like this: ( I guess here is the issue, properties being as lable!? )
called { '{"username":"arif","password":"sadfdsa","familyLeader":"sadffsa","husband":"sadfsad","wife":"sadfsad","kids":2}': '' }
and the next console give the value like this:
family username undefined
I have removed header from $http request, and it works fine.
my code with issue is : with header
vm.createNewFamily = function() {
$http({
method : 'POST',
url : '/api/family',
data : vm.form,
headers : {'Content-Type': 'application/x-www-form-urlencoded'}
}).success( function ( data ) {
console.log('retured!', data );
})
}
and the solution is : ( header removed )
vm.createNewFamily = function() {
$http({
method : 'POST',
url : '/api/family',
data : vm.form
}).success( function ( data ) {
console.log('retured!', data );
})
}
Experts - Please confirm the solution!

how to check the return status of the store 's sync In Extjs

I use the the
store.sync({
success:function(){},
failure:function(){}
});
to sync with the server; when the server return {success:false} or {success:true};
how I check the json from the server in the store.sync.
I have knew that:success is called by The function to be called upon successful completion of the sync ,even if return {sucess :false} ,not only the {success:true};
You need to change the reader's successProperty to false in the store's proxy.
store.proxy.reader.successProperty = false;
or
var store = Ext.create('Ext.data.Store', {
(...)
proxy : {
type : 'ajax',
(...)
reader : {
successProperty : false,
(...)
}
}
});
and then you can use this:
store.sync({
callback : function (batch, options) {
var operations = batch.operations;
for (var x in operations) {
var operation = operations[x];
if (operation.request) {
console.log('operation.request ---> ', operation.request);
}
if (operation.response) {
console.log('operation.response ---> ', operation.response);
var object = Ext.decode(operation.response.responseText, false);
console.log('success --->', object.success);
}
}
}
});

Uncaught TypeError: Cannot read property 'responseText' of undefined

buttons: [
{
text: "Add User",
id: "new-record-add-button",
handler: function() {
var form = this.up('form').getForm();
form.submit({
url: BasePath+'/main/admin/adduser',
method: 'POST',
waitTitle: 'Authenticating',
waitMsg: 'Please Wait',
success: function(form, action) {
win.close()
Ext.Msg.show({
title:'Success'
,msg:'User added successfully'
,modal:true
,icon:Ext.Msg.INFO
,buttons:Ext.Msg.OK
});
},
failure: function(form, action) {
console.log(action.response.responseText);
obj = Ext.JSON.decode(action.response.responseText);
console.log(obj);
Ext.Msg.alert('Error',obj.errors)
form.reset();
}
})
//this.up("window").close();
}
},
{
text: "Cancel",
handler: function() {
this.up("window").close();
}
}
]
I am getting the following error when I reach the failure function in my form:
Uncaught TypeError: Cannot read property 'responseText' of undefined
This is my php code:
public function adduserAction()
{
$response = new JsonModel();
//$error = array();
$errors="";
if(!ctype_alpha($_POST["first_name"])) {
$errors.="First Name cannot contain characters and numbers";
}
if(!ctype_alpha($_POST["last_name"])) {
$errors.="Last Name cannot contain characters and numbers";
}
if(!filter_var($_POST['email_address'], FILTER_VALIDATE_EMAIL)) {
$errors.="Email should be of the format john.doe#example.com";
}
if(empty($_POST["role"])) {
$errors.="Role cannot be empty";
}
if($errors!="") {
$response->setVariables(array("success"=>false, "errors"=>$errors));
}
else {
$response->setVariables(array("success"=>true, "errors"=>$errors));
}
return $response;
}
responseText is an ExtJs thing - it represents the actual text returned from the server (eg, using echo) before being decoded.
You should get it in asynchronous callbacks within the operation or request objects, unless there was a server exception of a sort or if you set success to false, that's why you don't get it in the failure handler.
To really understand what's going on with it I recommend you have a look at Connection.js.
if you do a form submit through ExtJs, then on success of the form submission it needs response.responseText to be set as {"sucess":"true"}. if you are submitting the form to some page you have to make sure that you will be returning this object from backend. Or else you have to override the existing onSuccess method.
The second way is something like this,
Ext.override(Ext.form.action.Submit,{
onSuccess: function(response) {
var form = this.form,
success = true,
result = response;
response.responseText = '{"success": true}';
form.afterAction(this, success);
}
});
Place this snippet in your application and see the magic. Cheers. :)

how can I update a model with custom idAttribute

in my simple backbone application, I am trying to update a model and every time it send a put request instead of post.
Well, this is my model named categoryModel
define(['Backbone'], function (Backbone) {
var CategoryModel = Backbone.Model.extend({
defaults: {
ID: '',
Name: 'Empty',
TagID: '0',
GID: '0'
},
idAttribute: "ID",
initialize: function () {
if (!this.get('Name')) {
this.set({ 'Name': this.defaults.Name });
}
}
});
return CategoryModel;
});
this is the collection
define(['Backbone','../../models/categories/categoryModel'], function (Backbone, categoryModel) {
var CategoryCollection = Backbone.Collection.extend({
url: '/parentcategory/Actions',
model: categoryModel
});
return new CategoryCollection;
});
here are my methods in the view
on a keychange event
createNewItem: function (e) {
var $this = $(e.currentTarget);
$('#selectedCategoryName').html($this.val());
//it creates a new model
globals.NewCategory = new CategoryModel({ Name: $this.val() });
}
on handleDrop event
handleDropEvent: function (event, ui) {
var draggable = ui.draggable;
//check if name has set
if (!globals.NewCategory) {
alert("Please write a category name");
$('#createNewCategory').focus();
return;
}
//get itemID
var itemID = draggable.attr("id").split('_')[1];
var itemDesc = draggable.attr("id").split('_')[0];
//check items category
if (itemDesc == "Tag") {
//check if tagID already exists
if (globals.NewCategory.TagID) {
alert("you have already specify a tag from this category");
return;
}
globals.NewCategory.set("TagID", itemID);
} else if (itemDesc == "gTag") {
if (globals.NewCategory.GID) {
alert("you have already specify a tag from this category");
return;
}
globals.NewCategory.set("GID", itemID);
}
categoriesCollection.create(globals.NewCategory, {
silent: true,
wait: true,
success: function (model, response) {
model.set("ID", response);
alert(model.id);
}
});
}
The categoriesCollection.create is called twice. Firstly for setting the TagID (on a success request it gets an ID ) and secondly for setting the GID.
Since the ID has been set, shouldn't had sent a POST request instead of PUT on the second call?
What am I doing wrong?
Thanks
The standard behaviour is to send a POST if the model is new ( doesn't have an ID attributed ) and send a PUT if the model id is set.
In your case it's working as designed, if you want it to use POST to send UPDATES you have to override Backbone.sync to work as you need, but I think it's easier for you to make your backend RESTful and create a PUT listener controller method for updates.
Another thing, if I got it right you are using create() to update models in your collection, I would advise you not to do that and instead use the save() directly in the model you want to update, the code will be a lot more readable.
Cheers.

Ext.data.HttpProxy callback on failure

I've the following ExtJS. The listener "write" is called when the response is a success (the response is JSON like: {"success":true,"message":"......"}). But how do I attach a callback when the response is not a success? ({"success":false,"message":"......"})
tableStructure.proxy = new Ext.data.HttpProxy({
api: {
read: '/controller/tables/' + screenName + '/getstructure/' + table,
create: '/controller/tables/' + screenName + '/createcolumn/' + table,
update: '/controller/tables/' + screenName + '/updatecolumn/' + table,
destroy: '/controller/tables/' + screenName + '/destroycolumn/' + table
},
listeners: {
write: tableStructure.onWrite
}
});
You want to catch the HttpProxy's exception event.
listeners: {
write: tableStructure.onWrite
exception: function(proxy, type, action, options, response, arg) {
if(type === 'remote') { // success is false
// do your error handling here
console.log( response ); // the response object sent from the server
}
}
}
You can find the full documentation in the Ext docs for Ext.data.HttpProxy down in the events section.
You should be able to make use of the write event itself. The write event's signature is:
write(dataproxy,action,data,response,record,options).
You can access the success variable from the action object and check if the value is true or false. You should be able to access the success variable as:
action.result.success
You can do:
if(action.result.success != true ) {
// If success is not true
} else {
// If success is true
}
You can also set an exception handler on the Ext.data.Store wrapping the HttpProxy, provided that you send a response code other than 200.
var store = new CQ.Ext.data.Store({
proxy : new CQ.Ext.data.HttpProxy({
method : "GET",
url : '/some_url'
}),
reader : new CQ.Ext.data.JsonReader(),
baseParams : {
param : 'some value'
}
});
store.on("beforeload", function() {
CQ.Ext.getBody().mask("Please wait...", false);
});
store.on("exception", function() {
CQ.Ext.getBody().unmask();
CQ.Ext.Msg.show({
title: 'Error',
msg: '<span style="color:red">Bad request.</span><br/>',
icon: CQ.Ext.Msg.ERROR,
buttons: CQ.Ext.Msg.OK
});
});

Resources