extjs4 proxy rest multiple request issue - rest

Hi I am encountering a wierd behavior with my application:when I modify an item and then my proxy doas a put request, the first time is ok, the second time it sends two requests: the first with the data of the previous one, the second one with the actual data, the third time it sends three requests, onmy system it is not a big issue, because at end I get the right value on my database, but on my customer's system the result it is not always correct. Then I would like to remove this behavior.
this is my store:
Ext.create('Ext.data.Store',
{
storeId: 'bbCompaniesStore',
model:'Company',
pageSize: pageSize,
proxy:
{
idProperty : '_id',
type: 'rest',
url: 'data/companies/',
autoload: true,
noCache: true,
sortParam: undefined,
actionMethods:
{
create : 'PUT',
read : 'GET',
update : 'POST',
destroy: 'DELETE'
},
reader:
{
type: 'json',
root: 'data',
totalProperty: 'total'
},
},// proxy
listeners: {
exception: function(proxy, response, operation) {
Ext.gritter.add({
title: MongoVision.text['action.' + operation.action] || operation.action,
text: (operation.error ? operation.error.statusText : null) || MongoVision.text.exception
});
// Ext JS 4.0 does not handle this exception!
switch (operation.action) {
case 'create':
Ext.each(operation.records, function(record) {
record.store.remove(record);
});
break;
case 'destroy':
Ext.each(operation.records, function(record) {
if (record.removeStore) {
record.removeStore.insert(record.removeIndex, record);
}
});
break;
}
}
}
}
);
this is my model:
Ext.define('Company',
{
extend: 'Ext.data.Model',
fields: [
{
name : 'id',
type : 'string'
},
{
name :'firm',
type : 'string',
allowBlank: false
},{
name : 'p'
},
{
name: 'linee'
},
{
name : 'c'
},
{
name : 'data',
type: 'date'
},
{
name :'note'
},
{
name :'paese'
},
{
name : 'email'
},
{
name : 'telefono'
},
{
name : 'type'
},
{
name : 'website'
},
{
name : 'session_id'
},
{
name : 'group_id'
}
],
proxy : {
type : 'rest',
url : 'data/companies/'
}
}
);
after googling around I found a similar issue for extjs3, with no solution, I think it is strange that after so long time, there is no yet a solution; it should work now

I faced the same issue, resolved it by simply passing
batchActions: true when creating the Proxy. The default behavior for 'rest' proxies is to turn off batching.... (See extjs/src/data/proxy/Rest.js)

Related

How to update with mongoose

I have this record
{
"_id" : ObjectId("5dfdff479ad032cbbc673507"),
"selection" : [
{
"highlights" : "test",
"comment" : "CHANGE THIS",
"el" : "body:nth-child(2)>div:nth-child(2)#root>div.App>p:nth-child(1)"
},
{
"highlights" : "Barrett’s lyrical prose opens with a clever and tender solution",
"comment" : "",
"el" : "body:nth-child(2)>div:nth-child(2)#root>div.App>p:nth-child(2)"
}
],
"category" : [],
"status" : "",
"url" : "http://localhost:3000/theone",
"title" : "React App test",
"__v" : 4
}
And I want to update the comment. I have tried to use update and findOneAndUpdate and nothing is working. Here is my attempt
WebHighlight.findOneAndUpdate(
{
_id: req.params.highlight,
"selection.highlights": "test"
},
{ "selection.$.comment": "yourValue" }
);
That req.params.highlight is the id (I even hardcoded it)
I also tried this
WebHighlight.findById(req.params.highlight, (err, book) => {
var test = [...book.selection];
test[0].comment = "somethibf"
book.save();
res.json(book);
});
And nothing is working.
This is the model
const webhighlightsModel = new Schema({
selection: { type: Array, default: "" },
category: { type: Array, default: [] },
title: { type: String },
url: { type: String },
status: { type: String, default: "" }
});
Actually your code seems to work, but findOneAndUpdate returns the old document if you don't give {new: true} option.
I think for this reason, you think the update wasn't successfull, but if you check your collection, you will see the update.
WebHighlight.findOneAndUpdate(
{
_id: req.params.highlight,
"selection.highlights": "test"
},
{ "selection.$.comment": "yourValue" },
{ new: true }
)
.then(doc => res.send(doc))
.catch(err => res.status(500).send(err));
Also I think it would be better if selection had a sub schema like this:
const mongoose = require("mongoose");
const schema = new mongoose.Schema({
selection: [
new mongoose.Schema({
highlights: String,
comment: String,
el: String
})
],
category: { type: Array, default: [] },
title: { type: String },
url: { type: String },
status: { type: String, default: "" }
});
module.exports = mongoose.model("WebHighlight", schema);
So with this every selection would an _id field, and it would be better to update with this _id.
You should use the $set operator to update existing values:
WebHighlight.findOneAndUpdate(
{
_id: req.params.highlight,
"selection.highlights": "test"
},
{ '$set': { "selection.$.comment": "yourValue" } }
);

mongoose populate field using _id of its own document

I'm creating an appliction using MEAN stack in which i've one to one chat feature. I'm using mongoose and have 3 schemas :
Users
{
name: {
type: String,
required: true
},
email: {
type: String
},
phone: {
type: Number,
required: true
},
profile_pic: {
type: String,
default: null
},
password: {
type: String
},
salt: {
type: String
}
}
Messages
{
message : {
type : String,
required : true
},
timestamp : {
type : Number,
required : true
},
from : {
type : String,
required : true
},
conversation_id : {
type : mongoose.Schema.Types.ObjectId,
required : true
}
}
Conversations
{
users : [ {
type: type : mongoose.Schema.Types.ObjectId,
ref : User
}]
}
Now, when user goes to his messenger i want to show him all his past conversations with latest messages so right now i'm exceuting find command on Conversation and populating User
then after getting all conversations i'm executing find command for each conversation to get their latest message, so by this there are so many find operations are done on database in single request. i.e. why i need some solution like populate latest message for each conversation ( like i can populate using _id of conversation )
Edit
Here is the code i'm using right now :
let completeConversations = [];
conversation.find({ "users": req.body.token_data.id }).populate({ path: 'users', select: 'name profile_pic' }).exec((err, conversations) => {
if (err) throw err
if (conversations.length == 0) {
res.status(200);
res.json({ message: "No Conversations Found" })
} else {
conversations.forEach(element => {
messages.find({ conversation_id: element._id }).sort('-timestamp').limit(1).exec((err, message) => {
if (err) {
res.status(200);
res.json({ message: "Latest Message Not Found", conversations })
} else {
element = JSON.parse(JSON.stringify(element));
element.latest = message[0];
completeConversations.push(element);
}
if (completeConversations.length === conversations.length) {
res.json(completeConversations)
}
})
});
}
})
thanks in Advance

How to auto populate nested associations of sails blueprint for url /model/<id>/association

I have two models Users and Chat with many to many association.
User.js
module.exports = {
attributes: {
name: {
type : 'string'
,required : true
},
email:{
type : 'string'
,email : true
,required: true
,unique : true
},
enpassword : {
type: 'string'
},
online : {
type: 'boolean',
defaultsTo: false
},
socketid: {
type: 'string'
},
chats : {
collection: 'chat',
via: 'users',
dominant: true
}
};
Chat.js
module.exports = {
attributes: {
messages : {
collection: 'message',
via : 'chat',
dominant : true
},
users : {
collection: 'user',
via : 'chats'
},
}
};
When I call sails blueprint /user/1/chats I am getting list of chats but users association of each chat is not populated.
How can I achieve this from Sails queries ?
Great question. Here is a really easy way to do this.
First, require the following module.
var nestedPop = require('nested-pop');
Next, run your query.
getPopulatedUsers = function(req, res) {
User.find()
.populate('chats')
.then(function(users) {
return nestedPop(users, {
chats: [
'messages',
'users' // I actually wouldn't recommend populating this since you already have the users
]
}).then(function(users) {
console.log(users);
res.json(users);
});
});
}
More docs on this can be found at the following link.
https://www.npmjs.com/package/nested-pop

Setting params in Kendo UI Grid when calling a rest service [Workaround]

I have a Kendo UI Grid that is calling a rest service. It works fine, as long as I do not try to use any params.
I know the the rest service is correct, as I can call it from a browser, and get correct results [depending on the param I send]. Also, when I look the server log I see that it is calling the rest service with no params.
My code is below:
document).ready( function() {
var crudServiceBaseUrl = "rsPC.xsp",
dataSource = new kendo.data.DataSource({
transport: {
read: {
url: crudServiceBaseUrl + "/PCByStatus",
filter: {field: "status", value: "2" }
dataType: "json",
update: {
url: crudServiceBaseUrl + "/PC/Update",
dataType: "json"
},
destroy: {
url: crudServiceBaseUrl + "/PC/Destroy",
dataType: "json"
},
create: {
url: crudServiceBaseUrl + "/PC/Create",
dataType: "json"
},
parameterMap: function(options, operation) {
if (operation !== "read" && options.models) {
return {models: kendo.stringify(options.models)};
}
}
},
batch: true,
pageSize: 20,
scrollable: {
virtual: true
},
height: 543,
schema: {
model: {
id: "PCId",
fields: {
PCId: {type:"string"},
serialNumber: {type: "string"},
officeLoc: {type: "string"},
unid: {type:"string"},
model: {type:"string"},
checkInDate: {type: "string"}
}
}
}
});
// Grid
grid = $("#grid").kendoGrid( {
dataSource: dataSource,
columns : [ {
field : "serialNumber",
title : "Serial Number"
}, {
field : "model",
title : "Model"
}, {
field : "officeLoc",
title : "Office Location"
}, {
field : "checkInDate",
title : "Check In Date",
template: "#= kendo.toString(kendo.parseDate(checkInDate, 'yyyy-MM-dd'), 'MM/dd/yyyy') #"
} ],
pageable: {
refresh: true,
pageSizes: true,
buttonCount: 5
},
dataBound : addExtraStylingToGrid,
reorderable : true,
filterable : true,
scrollable : true,
selectable : true,
sortable : true,
});
I still cannot get this to work and am a bit stumped.
I have two rest services, one returns all data, one takes "status" as a part and return a subset of the data that equals the parm.
The URL is:
http://localhost/scoApps/PC/PCApp.nsf/rsPC.xsp/PCByStatus?status=2
When entered into browser I get the correct number of records.
So I changed the code (see below). I have included all of the code for the CSJS:
$(document).ready( function() {
// Double Click On row
$("#grid").on(
"dblclick",
" tbody > tr",
function() {
var grid = $("#grid").data("kendoGrid");
var row = grid.dataItem($(this));
window.location.replace("xpFormPC.xsp" + "?key=" + row.unid + "target=_self");
});
// Add hover effect
addExtraStylingToGrid = function() {
$("table.k-focusable tbody tr ").hover( function() {
$(this).toggleClass("k-state-hover");
});
};
// Search
$("#search").keyup( function() {
var val = $('#search').val();
$("#grid").data("kendoGrid").dataSource.filter( {
logic : "or",
filters : [ {
field : "serialNumber",
operator : "contains",
value : val
}, {
field : "officeLoc",
operator : "contains",
value : val
}, {
field : "model",
operator : "contains",
value : val
} ]
});
});
var crudServiceBaseUrl = "rsPC.xsp",
dataSource = new kendo.data.DataSource({
transport: {
read: {
url: crudServiceBaseUrl + "/PCByStatus",
dataType: "json"
},
update: {
url: crudServiceBaseUrl + "/PC/Update",
dataType: "json"
},
destroy: {
url: crudServiceBaseUrl + "/PC/Destroy",
dataType: "json"
},
create: {
url: crudServiceBaseUrl + "/PC/Create",
dataType: "json"
},
parameterMap: function(options, operation) {
if (operation == "read"){
options.field = "status"
options.value = "2"
return options;
}
if (operation !== "read" && options.models) {
return {models: kendo.stringify(options.models)};
}
}
},
batch: true,
pageSize: 20,
scrollable: {
virtual: true
},
height: 543,
schema: {
model: {
id: "PCId",
fields: {
PCId: {type:"string"},
serialNumber: {type: "string"},
officeLoc: {type: "string"},
unid: {type:"string"},
model: {type:"string"},
checkInDate: {type: "string"}
}
}
}
});
// Grid
grid = $("#grid").kendoGrid( {
dataSource: dataSource,
columns : [ {
field : "serialNumber",
title : "Serial Number"
}, {
field : "model",
title : "Model"
}, {
field : "officeLoc",
title : "Office Location"
}, {
field : "checkInDate",
title : "Check In Date",
template: "#= kendo.toString(kendo.parseDate(checkInDate, 'yyyy-MM-dd'), 'MM/dd/yyyy') #"
} ],
pageable: {
refresh: true,
pageSizes: true,
buttonCount: 5
},
dataBound : addExtraStylingToGrid,
reorderable : true,
filterable : true,
scrollable : true,
selectable : true,
sortable : true
});
// Edit
function onEdit(e) {
}
// Change
function onChange(args) {
var model = this.dataItem(this.select());
ID = model.ID;
}
;
});
What am I doing wrong?
=========================================
I have a workaround. Or possibly this is the way it is supposed to be done.
var crudServiceBaseUrl = "rsPC.xsp", dataSource = new kendo.data.DataSource(
{
transport : {
read : {
url : crudServiceBaseUrl
+ "/PCByStatus?status=2",
dataType : "json"
},
Now I just construct the URL I want. Not so elegant I suppose, but it works.
I have a workaround. Or possibly this is the way it is supposed to be done.
var crudServiceBaseUrl = "rsPC.xsp", dataSource = new kendo.data.DataSource(
{
transport : {
read : {
url : crudServiceBaseUrl
+ "/PCByStatus?status=2",
dataType : "json"
},
Filter is used for client side data unless you set serverFiltering to true.
Here is the filter kendo documentation and the serverFiltering documentation.
I use parameterMap when I need to send parameters that are not created by filtering the control that I'm using. The kendo documentation provides an example using parameterMap.
Here is an example of how I've used it in the past:
var appsDataSource = new kendo.data.DataSource({
transport: {
read: {
url: apiUrl + "App"
},
parameterMap: function (data, action) {
if (action === "read") {
data.lobid = lobId;
data.parent = isParent;
return data;
} else {
return data;
}
}
}
});
Try changing the parameterMap:
parameterMap: function(options, operation) {
if (operation == "read"){
options.field = "status";
options.value = "2";
return options;
}
if (operation !== "read" && options.models) {
return {models: kendo.stringify(options.models)};
}
}
and update the read definition to remove filter. One thing to consider is that you are not returning anything from the read method if it doesn't meet the criteria of not being a read and options is not null. That leaves out any other combination that isn't obviously handled in your existing code.

Correct way to return from mongo to datatable

I'm using mongoose and returning documents from a collection to be displayed using datatables. I'm having some issues though. The client-side code is
var table = $('#dataTables-example').DataTable( {
"bProcessing" : true,
"bServerSide" : true,
"ajax" : {
"url" : "/mongo/get/datatable",
"dataSrc": ""
},
"columnDefs": [
{
"data": null,
"defaultContent": "<button id='removeProduct'>Remove</button>",
"targets": -1
}
],
"aoColumns" : [
{ "mData" : "name" },
{ "mData" : "price" },
{ "mData" : "category" },
{ "mData" : "description" },
{ "mData" : "image" },
{ "mData" : "promoted" },
{ "mData" : null}
]
});
Then this handled on the server-side using the following
db.once('open', function callback ()
{
debug('Connection has successfully opened');
productSchema = mongoose.Schema({
name: String,
price: String,
category: String,
description: String,
image: String,
promoted: Boolean
});
Product = mongoose.model('Product', productSchema, 'products');
});
exports.getDataForDataTable = function (request, response) {
Product.dataTable(request.query, function (err, data) {
debug(data);
response.send(data);
});
};
If I use the above code the datatable fails to display the documents, claiming no matching records found BUT it does correctly display the number of docs Showing 1 to 2 of 2 entries. If I change the server side code to response with data.data instead of data, the documents are correctly populated in the table BUT the number of records is no longer found, instead saying Showing 0 to 0 of 0 entries (filtered from NaN total entries)
exports.getDataForDataTable = function (request, response) {
Product.dataTable(request.query, function (err, data) {
debug(data);
response.send(data.data);
});
The actual data being returned when querying mongo is
{ draw: '1', recordsTotal: 2, recordsFiltered: 2, data: [ { _id: 5515274643e0bf403be58fd1, name: 'camera', price: '2500', category: 'electronics', description: 'lovely', image: 'some image', promoted: true }, { _id: 551541c2e710d65547c6db15, name: 'computer', price: '10000', category: 'electronics', description: 'nice', image: 'iamge', promoted: true } ] }
The third parameter in mongoose.model sets the collection name which is pluralized and lowercased automatically so it has no effect in this case.
Assuming your Product variable has been declared early on and global, try this:
products = mongoose.model('products', productSchema);
Product = require('mongoose').model('products');
Did you try to remove the dataSrc field in the DataTable configuration:
"ajax" : {
"url" : "/mongo/get/datatable",
},