How to retrieve fields value from Kendo Grid Models using ColdFusion - coldfusion

How can I get posted field values from a Kendo model on the server end? I have a logger on the server end. This shows I received all of the fields, with column names and values. However, I am not sure how to retrieve those values:
Used Script:
<script>
$(document).ready(function () {
var crudServiceBaseUrl = "http://localhost:8500/test/test1.cfc?method=",
dataSource = new kendo.data.DataSource({
transport: {
read: {
url: crudServiceBaseUrl+"JsonRead",
dataType: "json"
},
create: {
url: crudServiceBaseUrl+"JsonCreate",
dataType: "json"
},
parameterMap: function(options, operation) {
if (operation !== "read" && options.models) {
return {models: kendo.stringify(options.models)};
}
return options;
}
},
batch: true,
pageSize: 20,
schema: {
type: "json",
model: {
id: "productid",
fields: {
productid: { editable: false, nullable: true },
productname: { validation: { required: true } },
unitprice: { type: "number", validation: { required: true, min: 1} },
discontinued: { type: "boolean" },
unitsinstock: { type: "number", validation: { min: 0, required: true } }
}
}
}
});
$("#grid").kendoGrid({
dataSource: dataSource,
pageable: true,
height: 430,
toolbar: ["create"],
columns: [
"productname",
{ field: "unitprice", title: "Unit Price", format: "{0:c}", width: "100px" },
{ field: "unitsinstock", title:"Units In Stock", width: "100px" },
{ field: "discontinued", width: "100px" },
{ command: ["edit", "destroy"], title: " ", width: "172px" }],
editable: "inline"
});
});
</script>
test1.cfc
<cfcomponent>
<cffunction name="init">
<cfreturn this>
</cffunction>
<cffunction name="JsonRead" returntype="any" description="Return all Product" access="remote">
<cfquery name="getallproducts" datasource="DataSource">
SELECT * from Products
</cfquery>
<cfset var aTmp = arraynew(1)>
<cfif getallproducts.recordcount>
<cfloop query="getallproducts">
<cfset stTmp = structNew()>
<cfloop list="#lcase(getallproducts.columnlist)#" index="col">
<cfset stTmp[col] = getallproducts[col][currentRow]>
</cfloop>
<cfset arrayAppend(aTmp,stTmp)>
</cfloop>
<cfelse>
<cfset stTmp = structNew()>
<cfloop list="#lcase(getallproducts.columnlist)#" index="col">
<cfset stTmp[col] = "">
</cfloop>
<cfset arrayAppend(aTmp,stTmp)>
</cfif>
<cfset ss=#SerializeJSON(aTmp)#>
<cfreturn ss>
</cffunction>
<cffunction name="JsonCreate" returntype="void" description="Create New Row" access="remote">
<cfargument name="models" type="string" required="yes">
<cfset data = urldecode(arguments.models)>
<cfset data = deserializeJSON(data, false)>
</cffunction>
</cfcomponent>

I think what you're asking for is a way to get at the data coming from your Kendo Grid once you save, update or delete. Here is an example of something you could do to loop through the data stored in the models argument coming from Kendo. Keep in mind if you set batch in your grid equal to true then you will have multiple rows of data coming from your grid.
remote void function JsonCreate(string models) output="false" {
var data = urldecode(arguments.models);
data = deserializeJSON(data, false);
}
EDIT: Example JsonRead Function below. If you don't specify return type as string ans returnformat as plain you have to set the return type to any and the returnformat to JSON.
remote string function JsonRead(string RemoteToken) returnFormat="plain" output="false" {
if ( TestToken(arguments.RemoteToken) ) {
return serializeJSON(QueryToStruct(QueryAllUsers()));
}
}
I also use dataType as JSON so your datasource would look something like this:
var serviceURL = kendoURL + "/services/Service.cfc?RemoteToken=" + RemoteToken + "&method=",
dataSource = new kendo.data.DataSource({
transport: {
read: {
url: serviceURL + "JsonRead",
dataType: "JSON"
},
update: {
url: serviceURL + "JsonUpdate",
dataType: "JSON"
},
destroy: {
url: serviceURL + "JsonDelete",
dataType: "JSON"
},
create: {
url: serviceURL + "JsonCreate",
dataType: "JSON"
},
parameterMap: function(options, operation) {
if (operation !== "read" && options.models) {
return {models: kendo.stringify(options.models)};
}
}
},
batch: true
...
Also, since this will have to be a remote function you'll want to provide some sort of security check to guard against unauthorized access. I use a RemoteToken shown above.

Related

Extend query function to support multiple search criteria in CouchDB/PouchDB

I'm trying to get a count of docs having level: 2, completed: true. However, I'm having trouble wrapping my head around introducing another criteria in the query function. Currently, as evident from the code; it is just printing out docs having completed: true. How can I extend this query to support another query parameter like level too?
[{
_id: 1,
name: 'Test_01',
level: 1,
completed: false
},
{
_id: 2,
name: 'Test_02',
level: 2,
completed: true
},
{
_id: 3,
name: 'Test_01',
level: 3,
completed: false
}]
const myMapReduceFun = {
map: (doc) => {
emit(doc.completed);
}.toString(),
reduce: '_count'
};
db.query(myMapReduceFun, {
key: true, reduce: true
})
.then((result) => {
console.log(result)
})
This is easily done with map/reduce. One strategy is to use complex keys, the other using clever demarcations in a string.
I prefer complex keys as it does not require having to assemble the key or other string based monkey business.
Consider the design document in the demo:
{
_id: "_design/my_index",
views: {
completed_str: {
map: `function (doc) {
emit(doc.completed + '/' + doc.level + '/')
}`,
},
completed_complex: {
map: `function (doc) {
emit([doc.completed,doc.level])
}`,
},
},
}
completed_str uses concatenation and a '/' to create two fields for completed and level
completed_complex uses an array to create a complex key
In the snippet below I've included an example of both approaches. The key (no pun intended) is to emit the 'completed' field first, then the 'level' field.
When toying with the queries, do note the difference in the value Key field returned by the view.
const gel = id => document.getElementById(id);
const g_view_result = 'view_result';
function getQuery() {
let view = gel('view').value;
let completed = gel('completed').value === 'true';
let level = parseInt(gel('level').value, 10);
if (view === 'complex') {
// use complex key view
return {
view: "my_index/completed_complex",
params: {
reduce: false,
include_docs: false,
start_key: [completed, level],
end_key: [completed, level],
}
}
}
// use simple string view
return {
view: "my_index/completed_str",
params: {
reduce: false,
include_docs: false,
start_key: [completed, level, ''].join('/'),
end_key: [completed, level, ''].join('/'),
}
}
}
async function query() {
try {
let html = [];
const view_result = gel(g_view_result);
view_result.innerText = '';
let query = getQuery();
let docs = await db.query(query.view, query.params);
html.push(['ID', 'Key'].join('\t'));
html.push(['----', '--------'].join('\t'));
docs.rows.forEach(row => {
html.push([row.id, row.key].join('\t'));
})
view_result.innerText = html.join('\n');
} catch (e) {
console.log('err: ' + e);
}
}
// canned test documents
function getDocsToInstall() {
return [{
_id: "1",
name: 'Test_01',
level: 1,
completed: false
},
{
_id: "2",
name: 'Test_02',
level: 2,
completed: true
},
{
_id: "3",
name: 'Test_01',
level: 3,
completed: false
},
{
_id: "4",
name: 'Test_4',
level: 3,
completed: true
},
{
_id: "5",
name: 'Test_05',
level: 2,
completed: true
},
{
"_id": "_design/my_index",
"views": {
"completed_str": {
"map": `function (doc) {
emit(doc.completed + '/' + doc.level + '/')
}`
},
"completed_complex": {
"map": `function (doc) {
emit([doc.completed,doc.level])
}`
}
}
}
]
}
let db;
async function initDb() {
db = new PouchDB('test', {
adapter: 'memory'
});
return db.bulkDocs(getDocsToInstall());
}
(async() => {
try {
await initDb();
} catch (e) {
console.log(e);
}
})();
<script src="https://cdn.jsdelivr.net/npm/pouchdb#7.1.1/dist/pouchdb.min.js"></script>
<script src="https://github.com/pouchdb/pouchdb/releases/download/7.1.1/pouchdb.memory.min.js"></script>
<label for="completed">Completed:</label>
<select name="completed" id="completed">
<option value="true">True</option>
<option value="false">False</option>
</select>
<label for="level">Level:</label>
<select name="level" id="level">
<option value="0">0</option>
<option value="1">1</option>
<option value="2" selected>2</option>
<option value="3">3</option>
</select>
<label for="view">View:</label>
<select name="view" id="view">
<option value="complex">Complex Key</option>
<option value="simple">Simple String Key</option>
</select>
<button id="query" onclick="query()">Query</button>
<div style='margin-top:2em'></div>
<pre id='view_result'>
</pre>

Full Calendar - How to distinguish past events and future events

I am having a hard time trying to remove past and future events that are not reflected by the current month. Currently this is what I have the following code below:
<cffunction name="FullCalendar">
<cfscript>
var calendarid = $.getbean('content').loadby(title='Regal Events').getcontentid();
</cfscript>
<cfsavecontent variable="local.str">
<cfoutput>
<h3>Upcoming Events</h3>
<div id="UpcomingCal" class="calendarResize">
</div>
<script>
mura.loader()
.loadcss("#$.siteConfig('requirementspath')#/fullcalendar/fullcalendar.css",{media:'all'})
.loadcss("#$.siteConfig('requirementspath')#/fullcalendar/fullcalendar.print.css",{media:'print'})
.loadjs(
"#$.siteConfig('requirementspath')#/fullcalendar/lib/moment.min.js",
"#$.siteConfig('requirementspath')#/fullcalendar/fullcalendar.min.js",
"#$.siteConfig('requirementspath')#/fullcalendar/gcal.js",
function(){
$('##RegalUpcomingCal').fullCalendar({
weekMode: 'liquid',
eventSources: [
{
url: '#variables.$.siteConfig('requirementspath')#/fullcalendar/proxy.cfc?calendarid=#esapiEncode("javascript",CalendarID)#'
, type: 'POST'
, data: {
method: 'getFullCalendarItems'
, calendarid: '#esapiEncode("javascript",CalendarID)#'
, siteid: '#variables.$.content('siteid')#'
, categoryid: '#esapiEncode('javascript',variables.$.event('categoryid'))#'
, tag: '#esapiEncode('javascript',variables.$.event('tag'))#'
}
<!---, color: '#this.calendarcolors[colorIndex].background#'
, textColor: '#this.calendarcolors[colorIndex].text#'--->
, error: function() {
$('##mura-calendar-error').show();
}
},
]
})
}
)
</script>
</cfoutput>
</cfsavecontent>
<cfreturn local.str />
</cffunction>
I was able to remove the dates but as it is generated, it does get ride of the structure of calendar which I am not sure why. However, I am not sure how to add the following code to be able to distinguish past and future events:
eventRender:function(event, tag){
var ntoday = new Date().getTime();
var eventEnd = moment( event.end ).valueOf();
var eventStart = moment( event.start ).valueOf();
if (!event.end){
if (eventStart < ntoday){
element.addClass("fc-content");
element.children().addClass("fc-content");
}
} else {
if (eventEnd < ntoday){
element.addClass("fc-content");
element.children().addClass("fc-content");
}
}
}
and not sure where to add it in the code. Any help would be appreciated.
Thanks
UPDATE
Currently I have the eventRender in my code but it still does not remove past or future events. what am I doing wrong?
<cffunction name="FullCalendar">
<cfscript>
var calendarid = $.getbean('content').loadby(title='Regal Events').getcontentid();
</cfscript>
<cfsavecontent variable="local.str">
<cfoutput>
<h3>Upcoming Events</h3>
<div id="UpcomingCal" class="calendarResize">
</div>
<script>
mura.loader()
.loadcss("#$.siteConfig('requirementspath')#/fullcalendar/fullcalendar.css",{media:'all'})
.loadcss("#$.siteConfig('requirementspath')#/fullcalendar/fullcalendar-custom.css",{media:'all'})
.loadcss("#$.siteConfig('requirementspath')#/fullcalendar/fullcalendar.print.css",{media:'print'})
.loadjs(
"#$.siteConfig('requirementspath')#/fullcalendar/lib/moment.min.js",
"#$.siteConfig('requirementspath')#/fullcalendar/fullcalendar.min.js",
"#$.siteConfig('requirementspath')#/fullcalendar/gcal.js",
function(){
$('##UpcomingCal').fullCalendar({
weekMode: 'liquid',
eventSources: [
{
url: '#variables.$.siteConfig('requirementspath')#/fullcalendar/proxy.cfc?calendarid=#esapiEncode("javascript",CalendarID)#'
, type: 'POST'
, data: {
method: 'getFullCalendarItems'
, calendarid: '#esapiEncode("javascript",CalendarID)#'
, siteid: '#variables.$.content('siteid')#'
, categoryid: '#esapiEncode('javascript',variables.$.event('categoryid'))#'
, tag: '#esapiEncode('javascript',variables.$.event('tag'))#'
}
<!---, color: '#this.calendarcolors[colorIndex].background#'
, textColor: '#this.calendarcolors[colorIndex].text#'--->
, error: function() {
$('##mura-calendar-error').show();
}
, eventRender:function(event, element, view){
var ntoday = new Date().getTime();
var eventEnd = moment( event.end ).valueOf();
var eventStart = moment( event.start ).valueOf();
if (!event.end){
if (eventStart < ntoday){
element.addClass("past-event");
element.children().addClass("past-event");
}
} else {
if (eventEnd < ntoday){
element.addClass("past-event");
element.children().addClass("past-event");
}
}
}
},
]
});
}
)
</script>
</cfoutput>
</cfsavecontent>
<cfreturn local.str />
</cffunction>

Algolia - Search with a condition to look into an array of string

I am using rails and algolia gem with mongoid datastore.
I am sending data to algolia for a model Question. One of the doc example in Algolia system is
objectID: 5691e056410213a381000000
text: "what is #cool about your name Mr. John? #name #cool"
asked_to: ["565571704102139759000000", "i7683yiq7r8998778346q686", "kjgusa67g87y8e7qtwe87qwe898989"]
asked_by: "564a9b804102132465000000"
created_at: "2016-01-10T04:38:46.201Z"
card_url: "http://localhost:3000/cards/5691e056410213a381000000"
answerers: []
has_answer: false
requestor_count: 0
status: "active"
popularity_point: 0
created_at_i: 1452400726
_tags: ["cool", "name"]
I want to find all those documents, where it meets these two conditions:
1) text contains your name
2) asked_to contains i7683yiq7r8998778346q686
I am using Twitter's typeahead javascript library. And my UI's javascript to implement algolia search is as follows:
<input class="typeahead ui-widget form-control input-md search-box tt-input" id="typeahead-algolia" placeholder="Search questions" spellcheck="false" type="text" autocomplete="off" dir="auto" style="position: relative; vertical-align: top;">
$(document).on('ready page:load', function () {
var client = algoliasearch("APPLICATION_ID", "SEARCH_KEY");
var index = client.initIndex('Question');
$('#typeahead-algolia').typeahead(
{
hint: false,
highlight: true,
minLength: 1
},
{
source: index.ttAdapter({hitsPerPage: 10}),
displayKey: 'text'
}
).on('keyup', this, function (event) {
if (event.keyCode == 13) {
$('#typeahead-algolia').typeahead('close');
window.location.href = "/?keyword="+encodeURIComponent($('#typeahead-algolia').val());
}
});
$('.typeahead').bind('typeahead:select', function(ev, suggestion) {
window.location.href = suggestion.card_url;
});
});
So my question is:
This code works perfectly. But how to add condition for asked_to contains i7683yiq7r8998778346q686 in above javascript to filter out result.
You can use a facet filter on the asked_to attribute in your query.
You first need to declare the attribute asked_to as an attribute for faceting in your index settings and then pass asked_to:i7683yiq7r8998778346q686 as a facet filter in your query via the facetFiltersquery parameter.
When your index settings are changed, you can change your source to add the facetFilters parameter:
$('#typeahead-algolia').typeahead(
{
hint: false,
highlight: true,
minLength: 1
},
{
source: index.ttAdapter({hitsPerPage: 10, facetFilters: "asked_to:i7683yiq7r8998778346q686"}),
displayKey: 'text'
}
).on('keyup', this, function (event) {
if (event.keyCode == 13) {
$('#typeahead-algolia').typeahead('close');
window.location.href = "/?keyword="+encodeURIComponent($('#typeahead-algolia').val());
}
});

Invoke ColdFusion cfc function using AJAX

I am trying to validate text input, with a sql check. Based on the result from the ajax call, I want to return the output as red or green.
HTML:
<script>
$("#cdsid").click(function() {
debugger;
var value = $.trim($("#svcdsid").val());
if (value != '') {
$.ajax({
type:"POST",
url:"SVCDS_filter.cfc?method=SVCDSIDExists",
data: "value",
cache:false,
dataType: "json",
success: function(){
alert('YES');
},
error: function(){
alert('NO');
}
});
} else {
$("#targetDiv").html("Please Enter SSID");}
});
</script>
I am getting "unexpected end of input". In debugger, after checking that the value is not null value, it skips to the end code. I am not sure why.
First You can Write a ajax function for checking your text input. In the ajax function you can pass the text value that you entered trough data. Url cfc function that you called for checking input text data,and the method is the name of your cfc function. Here it is "SVCDSIDExists". In the cfc file you can add new function that you checked for text value. The access="remote" for ajax.
You can check in your table with the field . If it have a record it return 1 else it return 0. This value you can get from data of success in ajax. based on this value you can change the color of your input box.
<script>
$("#cdsid").click(function() {
var value = $.trim($("#svcdsid").val());
if ($.trim(value).length != 0) {
$.ajax({
type:"POST",
url:"SVCDS_filter.cfc?method=SVCDSIDExists",
data: {
value : value
},
cache:false,
async : false,
success: function(data){
if(data = 1){
alert('YES');
$("#targetDiv").css('border',"1px solid green")
} else {
alert('NO');
$("#targetDiv").css('border',"1px solid red");
}
}
});
} else {
$("#targetDiv").html("Please Enter SSID");
}
});
</script>
<cffunction name="SVCDSIDExists" returntype="any" access="remote" returnformat="plain" >
<cfargument name="value" type="string" default="" required="yes">
<cfset variables.returnVal = 0>
<cfquery name="qGetSVCDSIDExists" result="result" datasource="#Application.ds#" username="#Application.UserName#" password="#Application.Password#">
select columnname
from your_table
where 1 = 1
<cfif StructKeyExists(arguments,"value")>
and columnname = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.value#">
</cfif>
</cfquery>
<cfif qGetSVCDSIDExists.recordCount >
<cfset variables.returnVal = 1 >
</cfif>
<cfreturn variables.returnVal>
</cffunction>

Unable to add radio buttons to Kendo UI grid

I'm trying to have a group of 3 radio buttons (each button in different column but the same row) in my Kendo grid but without success. I looked at the Kendo RowTemplate doc, but it's not directing me to any solution.
it works fine with checkboxes, but when i change the template to "radio" type, it changes to checkbox the second I click the edit button. any thoughts?
below is my kendoGrid properties, I put ** next to the 'template' line in the field property.
div.kendoGrid({
dataSource:
{ error: function (e) {
alert("An error occured: "+ e.xhr.responseText);
this.cancelChanges();
},
type:"json",
transport: {
read: {
url: "/users/read",
cache: false,
dataType: "json"
},
update: {
url: function(user){
var grid = $("#grid").data("kendoGrid");
var model = grid.dataItem(grid.select());
var roleIs;
if (user.Admin) {
roleIs="admin"
}
else if (user.Manager) {
roleIs="manager"
}
else if (user.User) {
roleIs="user"
};
return "users/update/"+model.id+"/"+roleIs+"/"+user.name
},
type: "PUT"
},
destroy: {
url: function(user){
return "/users/destroy/"+user.id+"/"+user.name
},
type: "DELETE"
},
create: {
url: function(user){
var roleIs;
if (user.Admin) {
roleIs="admin"
}
else if (user.Manager) {
roleIs="manager"
}
else if (user.User) {
roleIs="user"
};
return "users/create/"+user.login+"/"+user.name+"/"+roleIs+"/"
},
type: "POST"
},
parameterMap: function(options, operation) {
if (operation !== "read" && options.models) {
return {models: kendo.stringify(options.models)};
}
}
},
schema: {
model:
{ id: "id",
fields: {
id:{ type: "number",editable: false},
role:{ type: "string"},
login: { type: "string",editable: false},
name:{type: "string",editable: false},
Admin: { type: "boolean"},
Manager: { type: "boolean"},
User: { type: "boolean"}
}
}
},
pageSize: 30,
serverPaging: false,
serverFiltering: false,
serverSorting: false
},
selectable: "row",
navigatable: true,
pageable: true,
height: 400,
columns: [//{field: "id"},
{
field: "name",
title:"User Name",
filterable: true,
nullable: false,
editable: false
},{
field: "Admin",
**template: '<input type="checkbox" #= Admin ? "checked=checked" : "" # disabled="disabled"></input>'**,
width: 75
},{
field: "Manager",
**template: '<input type="checkbox" #= Manager ? "checked=checked" : "" # disabled="disabled"></input>'**,
width: 75
},{
field: "User",
**template: '<input type="checkbox" #= User ? "checked=checked" : "" # disabled="disabled"></input>',**
width: 75
},{
command: ["edit", "destroy"], title: "", width: "195px"
}],
editable:{mode: "inline"}
});
}
}
}
The formatting for edition is controlled by columns.editor
You need to write an editor function that defines the input as a radio button.