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

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.

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" } }
);

Custom control Openui5

sap.ui.core.Element.extend("custom.barNlineChartControl", { metadata : {
properties : {
"Job" : {type : "string", group : "Misc", defaultValue : null},
"Threshold" : {type : "int", group : "Misc", defaultValue : null},
}
}});
sap.ui.core.Control.extend("control.barNlinechart", {
/* the control API */
metadata : {
aggregations : {
"items" : { type: "custom.barNlineChartControl", multiple : true, singularName : "item"}
},
events: {
"select" : {},
"selectEnd": {}
}
},
//D3 Code below:
onAfterRendering: function() {
var that = this;
/* get the Items aggregation of the control and put the data into an array */
var aItems = this.getItems();
var data = [];
for (var i=0;i<aItems.length;i++){
var oEntry = {};
for (var j in aItems[i].mProperties) {
oEntry[j]=aItems[i].mProperties[j];
}
data.push(oEntry);
}
alert(JSON.stringify(data));
Code of view & control
multiBarLineGraph = new control.barNlinechart({
layoutData: new sap.ui.layout.GridData({span: "L12 M12 S12"}),
items: {
path : "/genericData",
template : new custom.barNlineChartControl({Job:"{Job}",Threshold:"{Threshold}"}),
}
}),
var multiBarData = {
"genericData":[
{
"Job": "Doctor",
"Threshold": 45,
"Hospital1": 30,
"Hospital2": 100,
"Hospital3": 90,
},
{
"Job": "Teacher",
"Threshold": 65,
"School1": 60,
"School2": 75,
},
]};
When the alert in d3 code executes I get Job & Threshold but other data from JSON array are missing which is obvious as the properties set here only accept job and threshold. As the JSON is dynamic how to write custom control so that I can pass the complete data to control everytime no matter how dynamic the data be.
You could use type: "any" for your items and dont use the element custom.barNlineChartControl at all:
Edit: as an aggregation controls the lifetime of the aggregated objects you have to use a property in this case.
sap.ui.core.Control.extend("control.barNlinechart", {
/* the control API */
metadata : {
properties : {
"items" : { type: "any" }
},
events: {
"select" : {},
"selectEnd": {}
}
},
and then in your view:
multiBarLineGraph = new control.barNlinechart({
layoutData: new sap.ui.layout.GridData({span: "L12 M12 S12"}),
items: { path : "/genericData" }
}),
this.getItems() would return an array of whatever has been been set / bound.

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",
},

Why does the Kendo Grid show false in all records of my grid, even when some have true?

I have put together a simple jsfiddle demonstrating the issue. It has a grid with two records. One has a true value in in the Boolean column and the other has a false.
I have logged the data to the console so you can see the values that the grid is getting.
Yet the grid shows false for both rows.
http://jsfiddle.net/codeowl/KhBMT/
Thanks for your time,
Scott
Code for StackOverflow:
var _Data = [
{ "SL_TestData_ID": "1", "SL_TestData_String": "Bool is 1", "SL_TestData_Boolean": "1" },
{ "SL_TestData_ID": "2", "SL_TestData_String": "Bool is 0", "SL_TestData_Boolean": "0" }
];
var _kendoDataSource = new kendo.data.DataSource({
transport: {
read: function (options) {
console.log('Transport READ Event Raised - Data: ', JSON.stringify(_Data, null, 4));
options.success(_Data);
}
},
schema: {
model: {
id: "SL_TestData_ID",
fields: {
SL_TestData_ID: { editable: false, nullable: false },
SL_TestData_String: { type: "string" },
SL_TestData_Boolean: { type: "boolean" }
}
}
},
error: function (a) {
$('#TestGrid').data("kendoGrid").cancelChanges();
}
});
// Initialize Grid
$("#TestGrid").kendoGrid({
columns: [
{ field: "SL_TestData_ID", title: "ID" },
{ field: "SL_TestData_String", title: "String" },
{ field: "SL_TestData_Boolean", title: "Boolean" }
],
dataSource: _kendoDataSource
});
I found that if I altered my select statement to return "TRUE"/"FALSE" for my TINYINT column in the database it worked. Eg;
SELECT
SL_TestData_ID,
SL_TestData_Number,
SL_TestData_String,
SL_TestData_Date,
SL_TestData_DateTime,
if (SL_TestData_Boolean = 1, "TRUE", "FALSE") as SL_TestData_Boolean
FROM
SL_TestData;
Regards,
Scott

Kendo DataSource: How to define "Computed" Properties for data read from remote odata source

Situation:
kendo DataSource
var ordersDataSource = new kendo.data.DataSource({
type: "odata",
transport: {
read: {
url: "http://localhost/odata.svc/Orders?$expand=OrderDetails"
}
},
schema: {
type: "json",
data: function(response){
return response.value;
}
total: function(response){
return response['odata.count'];
}
},
serverPaging: true,
serverFiltering: true,
serverSorting: true
})
the json data read from the odata source is like:
{
odata.metadata: "xxxx",
odata.count: "5",
value: [
{
OrderId: 1,
OrderedDate: "2013-02-20",
OrderInfoA: "Info A",
OrderInfoB: "Info B"
OrderDetails: [
{
OrderDetailId: 6,
OrderDetailInfoC: "Info C",
OrderDetailInfoD: "Info D"
},
{
//Another OrderDetail's data
}
]
},
{
// Another Order's data
}
]
}
Question 1:
1.If I wanna define a "computed" property: OrderedDateRelative, which should be the number of days between Today(2013-02-25) and the Day the Order was Created(2013-02-20), Like: "5 days ago", HOW can i achieve this in the client side?
Answer to Question1: http://jsbin.com/ojomul/7/edit
Question 2 --UPDATE--
2.Every Order has its Nested Property OrderDetails, so is it possible to define a Calculated Field for the Nested OrderDetails Property? Like: OrderDetailInfoCAndD for each OrderDetail, and the value should be something like: OrderDetailInfoC + OrderDetailInfoD, which is "Info C Info D"?
Thanks,
dean
You can create a calculated field by specifying the model of the data source:
dataSource = new kendo.data.DataSource({
data: [
{ first: "John", last: "Doe" },
{ first: "Jane", last: "Doe" }
],
schema: {
model: {
// Calculated field
fullName: function() {
return this.get("first") + " " + this.get("last");
}
}
}
});
Here is a live demo: http://jsbin.com/ojomul/1/edit
Here is a way to use calculated field in Kendo Grid.
var crudServiceBaseUrl = "http://demos.telerik.com/kendo-ui/service",
dataSource = new kendo.data.DataSource({
transport: {
read: {
url: crudServiceBaseUrl + "/Products",
dataType: "jsonp"
}
},
pageSize: 20,
schema: {
model: {
total: function (item) {
return this.UnitPrice * this.UnitsInStock;
}
}
}
});
$("#grid").kendoGrid({
dataSource: dataSource,
pageable: true,
height: 550,
sortable: true,
filterable: true,
toolbar: ["create"],
columns: [
{ field: "UnitPrice", title: "Unit Price"},
{ field: "UnitsInStock", title: "Units In Stock", width: "120px" },
{ field: "total()", title: "Total" }]
});
Below an example to use it in a grid. It can then also sort the column.
$("#grid").kendoGrid({
dataSource: {
data: [
{ first: "John", last: "Doe" },
{ first: "Jane", last: "Doe" }
],
schema: {
model: {
// Calculated field
fullName: function() {
return this.first + " " + this.last;
},
fields: {
first: { type: "string" },
last: { type: "string" }
}
}
}
},
columns: [
{
// Trigger function of the Calculated field
field: "fullName()",
title: "Fullname"
},
{
field: "first",
title: "firstname"
}
]
});