Kendo UI - Specify parameter name on dataSource read - asp.net-mvc

With Kendo UI, I am using an autocomplete box to try and retrieve data from my server. It is hitting an ASP.NET MVC controller with the following signature.
public ActionResult aspect(string term){
// ...
}
This means that the request needs to have the correct parameter in the url. Now the issue I am running into is that I cannot discover a way to specify this in the dataSource mechanics. I have read the documentation on parameterMap dozens of times and it makes absolutely no sense to me in any way.
This is complicated further by the fact that the page in question actually has 10-15 autocomplete text boxes at any one time, each dynamically created with dynamic identity.
The code I am using so far is as follows;
$(".autocomplete").kendoAutoComplete({
dataTextField: "Name",
dataSource: {
type: "json",
transport: {
read: {
url: "/search/aspect"
}
}
}
});
So is there anything I can do to tell it how to name the parameter it passes?
To make it more clear what I am trying to do, if I were doing this in jQuery, I would use ...
$.ajax({ url: '/search/aspects', data: { term: (insert the data here) } });
But because of the way all of this works, there is no set "selector" to get the autocomplete input, so I cannot retrieve its value from the input form element.

First, enable server-side filtering by setting this option:
dataSource: {
serverFiltering: true,
Then the value is passed as one of the parameters into the transport.parameterMap function.
If you were to log the object passed in to the parameterMap function like this:
$(".autocomplete").kendoAutoComplete({
dataTextField: "Name",
dataSource: {
serverFiltering: true,
type: "json",
transport: {
read: {
url: "/search/aspect"
},
parameterMap: function (data, action) {
console.log(data);
}
}
}
});
then you would get an object that looks like this:
{
"filter":{
"logic":"and",
"filters":[
{
"value":"something",
"operator":"contains",
"field":"Name",
"ignoreCase":true
}
]
}
}
So you can use this to get the value entered into the AutoComplete box by doing:
$(".autocomplete").kendoAutoComplete({
dataTextField: "Name",
dataSource: {
serverFiltering: true,
type: "json",
transport: {
read: {
url: "/search/aspect"
},
parameterMap: function (data, action) {
if(action === "read") {
return {
term: data.filter.filters[0].value
};
} else {
return data;
}
}
}
}
});

I think that there is a misunderstanding about the relation between DataSource and AutoComplete. AutoComplete has the input and uses a DataSource for retrieving the data: the input does not belong to the AutoComplete and as consequence you cannot get the input that is using a DataSource from a method that is from the DataSource (as transport.read.data or transport.parameterMap).
You need to unique identify which element has the input and the value that it contains.
What I do propose is getting the value using document.activeElement.value. Since you are typing it, the element that has the focus should be the element that you are using.
The code would be:
$(".autocomplete").kendoAutoComplete({
dataTextField: "Name",
dataSource: {
type: "json",
transport: {
read: {
url: "/search/aspect",
},
parameterMap : function (data, type) {
if (type === "read") {
return { term : document.activeElement.value }
}
}
}
}
})
Alternatively, you can enable serverFiltering and then Kendo UI links the input field with the filtering condition. The code would be:
$(".autocomplete").kendoAutoComplete({
dataTextField: "Name",
dataSource : {
serverFiltering: true,
type : "json",
transport : {
read : {
url : "/search/aspect"
},
parameterMap: function (data, type) {
if (type === "read") {
return { term : data.filter.filters[0].value }
}
}
}
}
});

I'm a little confused as to what you're wanting to do. If you are just trying to pass the string term to the controller you can specify the data:
$(".autocomplete").kendoAutoComplete({
dataTextField: "Name",
dataSource: {
type: "json",
transport: {
read: {
url: "/search/aspect",
data: { term: "value" }
}
}
}
})

Thanks for the clarification and help OnaBai. Here is the code that I got working after hours of frustration!
$("#contractsSearchField").kendoComboBox({
dataTextField: "name",
dataValueField: "id",
autoBind: false,
placeholder:'select...',
filter: "contains",// a filter must be present for the datasources serverFiltering argument to work properly.
minLength: 3,
dataSource: new kendo.data.DataSource({
serverFiltering: true,//We must turn on serverFiltering and sorting, otherwise, the combobox only works once and will not change it's values.
serverSorting: true,
group: { field: "searchtype" },
transport: {
read: {
url: "contract.cfc?method=getContractForDropdown",
// We are not passing the data here like we do in the autosuggest. The combobox is a different type of an animal.
dataType: "json",
contentType: "application/json; charset=utf-8", // Note: when posting json via the request body to a coldfusion page, we must use this content type or we will get a 'IllegalArgumentException' on the ColdFusion processing page.
type: "GET"
},//read
// Pass the search term that was typed in by the user. This works because when the user types into the input box, it becomes that active element in the form.
parameterMap : function (data, type) {
if (type === "read") {
return { searchTerm : document.activeElement.value }
//return { searchTerm: data.filter.filters[0].value }
}
}//parameterMap
}//transport
})//dataSource
}); //...kendoComboBox...

Related

How to dynamically change kendo UI treeview datasource

I have a kendo ui treeview and a dropdownbox on my asp.net mvc page. The dropdown box can have two values. Depending upon which one has been chosen, I want to change the datasource url, which is a method in a controller. The data type and structure of data from both the url will be the same. Essentially I want to change url: '#Url.Content("~/Document/GetMyDocument")' dynamically. The following is my treeview code:
<script>
$("#treeview").kendoTreeView({
checkboxes: {
checkChildren: true,
},
dataSource: {
transport: {
read: {
url: '#Url.Content("~/Document/GetMyDocument")',
type: "post",
dataType: "json"
}
},
schema: {
model: {
text: "Name",
spriteCssClass: "fa fa-folder",
children: "Files"
}
}
},
dataTextField: ["Name", "FileName"],
dataValueField: ["id"],
check: onCheck
});
You can specify the URL of the treeview dataSource as function
transport: {
read: {
url: function (e) { }
}
}
You can then listen for the change event of the DropDownList and call
$('#treeview').data('kendoTreeView').dataSource.read();
Inside the url function you can get the value of the DropDownList and resolve the url dynamically:
var ddl = $('#myDDl').data('kendoDropDownList');
var value = ddl.value();
return value == "someValue" ? "/foo/bar": "/bar/baz";

Kendo UI TreeView search with Virtualization

I am using Kendo UI TreeView with virtualization feature (ASP.net MVC); it helps me to load the top level initially & loads further levels on-demand.
Now there is a requirement to include “search” functionality to search nodes in the TreeView.
Unfortunately I don’t have all the nodes pre-loaded in my TreeView to perform search; can you please suggest if there are any alternatives to perform search dynamically inside TreeView.
Thank you
-nm
I ran into a similar problem and managed to fix it by implementing two Controller methods
Controller.LoadNodes(int? parentId)
Controller.SearchNodes(string searchTerm)
LoadNodes would return a flat list of direct children. Whereas SearchNodes would return a nested list of matched search terms and their parents.
My example used a SQL Server backup and followed the Hierachyid Data Type tutorial.
Once you've got that setup in the search button click event swap out the datasource for your treeview. Notice you have to set the datasource using the setDataSource method based on a post in the Telerik forums titled "Error when attempting to change datasource on treeview".
function ExpandNodes(nodes) {
return $.map(nodes, function (x) {
x.expanded = x.children.length > 0;
if (x.expanded)
ExpandNodes(x.children);
return x;
});
};
$("#search-btn").click(function(){
var searchText = $("#SearchText").val();
var treeview = $("#TreeView").data("kendoTreeView");
if(searchText.trim() != "")
{
url = "Controller/SearchNodes?searchText=" + searchText;
data.setDataSource(new kendo.data.HierarchicalDataSource({
transport: {
read: {
url: url,
dataType: "json",
type: "POST",
contentType: "application/json; charset=utf-8"
},
parameterMap: function (options) {
return JSON.stringify(options);
}
},
schema: {
parse: function (response) {
return ExpandNode(response);
},
model: {
id: "node_id",
children: "children",
expanded: true
}
}
}));
}
else
{
url = "Controller/LoadNodes";
data.setDataSource(new kendo.data.HierarchicalDataSource({
transport: {
read: {
url: url,
dataType: "json",
type: "POST",
contentType: "application/json; charset=utf-8"
},
parameterMap: function (options) {
return JSON.stringify(options);
}
},
model: {
id: "node_id",
}
}
}));
}
data.dataSource.read();
});

kendo ui Combobox binded to a Grid losts it's value and text after Grid's Cancel button pressed

I have two views in database. Bonuses and employees. One(employee)-to-many(bonuses).
I have kendo ui grid (kendo web), which displays ajax results from controller called Bonuses
And an autocompliting element - Employee Combobox binded with Employee filed of a grid.
Grid's datasource:
// bind json result from /Bonuses/GetPagedJsonBonuses
var bonusesDataSource = new kendo.data.DataSource({
transport: {
read: "#Url.Action("GetPagedJsonBonuses", "Bonuses")",
update: {
url: "#Url.Action("Edit", "Bonuses")",
type: "PUT"
},
create: {
url: "#Url.Action("Create", "Bonuses")",
type: "POST"
},
parameterMap: function(options, operation) {
if (operation === "update" || operation === "create") {
// updates the BonusDTO.EmployeeId with selected value
if (newValueEmployeeId !== undefined)
options.EmployeeId = newValueEmployeeId;
}
return options;
}
},
schema: {
data: "Data", // PagedResponse.Data
total: "TotalCount", // PagedResponse.TotalCount
model: {
id: "BonusId", // Data
fields: {
EmployeeId: { type: "number" },
EmployeeLastName: {
type: "string",
editable: true,
//validation: { required: {message: "Employee's last name is required"}}
},
Amount: {
type: "number",
editable: true,
nullable: false,
validation: {
required: { message: "Amount is required to be set" }
}
}
} // fields
} // model
}// schema
});
Grid element looks like this:
// creates bonuses grid control
$("#bonusesGrid").kendoGrid({
dataSource: bonusesDataSource,
toolbar: ["create"],
editable: "inline",
columns: [
"BonusId",
"EmployeeId",
{
field: "EmployeeLastName",
editor: employeeAutocompletingEditor,
template: "#=EmployeeLastName#"
},
"Amount",
{
command: ["edit"],
title: " "
}
],
save: function(e) {
if (newValueEmployeeId !== undefined && newValueEmployeeLastName !== undefined) {
e.model.EmployeeId = newValueEmployeeId; // it's a hack to bind model and autocomplete control
e.model.EmployeeLastName = newValueEmployeeLastName;
}
},
edit: function(e) {
setCurrentValueEmployeeIdAndLastName(e.model.EmployeeId, e.model.EmployeeLastName);
},
cancel: function(e) {
setCurrentValueEmployeeIdAndLastName(e.model.EmployeeId, e.model.EmployeeLastName);
}
});
Autocompleting combobox has it's own datasource using ajax:
// datasource for autocomlete combobox to lookup employees names from
var employeesDataSource = new kendo.data.DataSource({
transport: {
read: "#Url.Action("GetJsonEmployeesByLastName", "Bonuses")",
},
parameterMap: function(options, operation) {
if (operation === "update" || operation === "create") {
setNewValueEmployeeIdAndLastName(options.Id, options.LastName);
}
return options;
},
});
Autocompliting combobox look's like this:
function employeeAutocompletingEditor(container, options) {
$('<input required data-text-field="LastName" data-value-field="EmployeeId" data-bind="value:' + options.field + '"/>')
.appendTo(container)
.kendoComboBox({
// sets the local variables to update values of current row.
change: function() {
setNewValueEmployeeIdAndLastName(this.value(), this.text());
},
dataBinding: function (e) {
console.log("dataBinding: ", e, this.dataItem());
},
dataBound: function (e) {
console.log("dataBound: ", e, this.dataItem());
},
dataSource: employeesDataSource
});
}
I use Editor binding to pass values(EmployeeId) and Text (EmployeeLastName) from grid to combobox.
I also use a hack like temporal variables (newValueEmployeeId, currentValueEmployeeId) to
send selected Employee in combobox and pass it to grid for correct save. A found it's a most common practice to pass a value back to grid.
My problems is:
If I press Edit button on my grid first time The combobox displays current employee's name from grid row:
If I press Cancel button and again press Edit button, combobox doesn't display current value of grid (employee's name)
IF I type some name, change some other values, and Udate(save) value, next time combobox again displays employees name, but only once before Cancel was pressed.
I'm very new in Kendo UI and this problem drives me crazy...
I think that combobox losts it's binding or doesn't update smth. I tried to set values while onBound and onBinding events, but this doesn't help. Please help me with an advice and example.
PS all evenets and functions is my try to debug and find solution.
only one fix helped me:
var employeeList = new List<Employee>()
employeeList.add(new Emplpyee()) // add fake employee record.
return Json(employeeList)
I don't know why, but grid control start make cyclying empty ajax requests if I return empty list of employees or null. This doesn't work:
return Json(new List<Employee>());
return Json(null);
I think it's a problem in kendo combobox itself ,because it's not ready to receive and handle empty list or null as json result.
Also I heared something, that JQuery doesn't support empty or null results anymore...maybe that's the reason

Passing Multiple Checkbox value using jquery ajax

I am displaying multiple records on my ASP.NET MVC 4 view where each record has a checkbox. I want the user to be able to select multiple records (by checking checkboxes) and click Delete button in order to delete them. So far I can call the Delete Action method via jquery ajax but the problem is my action method does not seem to be accepting the passed array.
Here is my jquery code:
$(function () {
$.ajaxSetup({ cache: false });
$("#btnDelete").click(function () {
$("#ServicesForm").submit();
});
$("#ServicesForm").submit(function () {
var servicesCheckboxes = new Array();
$("input:checked").each(function () {
//console.log($(this).val()); //works fine
servicesCheckboxes.push($(this).val());
});
$.ajax({
url: this.action,
type: this.method,
data: servicesCheckboxes,
success: function (result) {
if (result.success) {
}
else {
}
}
});
return false;
});
});
and here is my action method:
[HttpPost]
public ActionResult DeleteServices(int[] deleteservice)
{
if (deleteservice != null)
{
//no hit
}
}
What am I missing?
Edit
I also tried console.log(servicesCheckboxes); before $.ajax() which outputs ["3", "4"] but still get null when I pass data as specified in answer below data: { deleteservice: servicesCheckboxes }. Even I tried data: [1,2] but still action method shows null for deleteservice in action method.
Just pass the array to your action:
$.ajax({
url: this.action,
type: this.method,
dataType: "json"
data: { deleteservice: servicesCheckboxes }, // using the parameter name
success: function (result) {
if (result.success) {
}
else {
}
}
});
Or, just use the serialize() jquery method to serialize all fields inside your form:
$.ajax({
url: this.action,
type: this.method,
dataType: "json"
data: $(this).serialize(),
success: function (result) {
if (result.success) {
}
else {
}
}
});
In your controller:
[HttpPost]
public ActionResult DeleteServices(int[] deleteservice)
{
bool deleted = false;
if (deleteservice != null)
{
// process delete
deleted = true;
}
return Json(new { success = deleted });
}
Finally got it working. "MVC detects what type of data it receive by contentType" as explained here so I made the following changes to $.ajax()
$.ajax({
url: this.action,
type: this.method,
dataType: "json"
//data: { deleteservice: servicesCheckboxes }, // using the parameter name
data: JSON.stringify({ deleteservice: servicesCheckboxes }),
contentType: 'application/json; charset=utf-8',
success: function (result) {
if (result.success) {
}
else {
}
}
});

JQueryAutoComplete Not showing results

I am trying to bind the text box and the JQuery AutoComplete feature. When I checked the Firebug AJAX Request & Response it returns like the following. But the textbox is not showing any items. Could you please advise me, what I am doing wrong? Thanks.
Here is my coding:
$("#<%= TextBox1.ClientID %>").autocomplete({
source: function (request, response) {
$.ajax({
url: "/contractors/web_services/wsSM.asmx/SearchDrugs",
type: "POST",
dataType: "json",
data: {
'LocationID': "10543",
'Search': request.term
},
success: function (data) {
response($.map(data.d, function (item) {
return {
value: item.FullDrugName,
id: item.DrugID
}
}))
}
});
},
delay: 1,
minLength: 2,
select: function (event, ui) {
alert(ui.item.id);
}
});
DataType property is representing the type of data that you're expecting back from the server.
you define data type as json but server returns you a xml output. You should change your DataType property to xml
In addition to #fealin's answer, you're going to need to change the way you process the xml response. It doesn't look like you have a d property on the return data, and you also need to look for the correct nodes in the XML structure and pull out their text to build the response array that you return to the widget.
Based on the XML you've provided, it might look something like this:
$("#<%= TextBox1.ClientID %>").autocomplete({
source: function (request, response) {
$.ajax({
url: "/contractors/web_services/wsSM.asmx/SearchDrugs",
type: "POST",
dataType: "json",
data: {
'LocationID': "10543",
'Search': request.term
},
success: function (data) {
response($(data).find("Drug").map(function (_, el) {
var $el = $(el);
return {
label: $el.find("FullDrugName").text(),
value: $el.find("DrugID").text()
};
}));
});
},
delay: 1,
minLength: 2,
select: function (event, ui) {
alert(ui.item.id);
}
});
Here's an example that's just using the XML string (without an AJAX request): http://jsfiddle.net/J5rVP/29/

Resources