Kendo UI Dropdownlist slow loading from a large datasource - kendo-ui

I'm using Kendo dropdownlist in a template. It loads a list of client names which are used to sign a record. The client name list has 8k entries.
The form loads ok but if I select the dropdownlist to change the client name it takes around 10 seconds for the list to appear. Is there something I can do to speed this up?
My datasource:
var dsClients = new kendo.data.DataSource({
transport: {
read: {
url: "/data/clients/key",
dataType: "jsonp"
},
parameterMap: function(options, operation) {
if (operation === "read") {
return options;
}
}
},
serverSorting: true,
sort: [{ field: "text", dir: "asc" }]
});
The element in my template:
<input name="idclt_clm" data-bind="value:idclt_clm" data-value-field="value"
data-text-field="text" data-option-label="Select" data-source="dsClients"
data-role="dropdownlist" required validationMessage="Required" />

There are 2 options that I know of.
You can add virtualization, which I just found from
Kendo.
You can turn of auto-bind and use a search filter that require 2 characters before it triggers a search. Below is how I've done it with asp.net and JS
#(Html.Kendo()
.DropDownList()
.Name("GridName")
.HtmlAttributes(new { #class = "form-control" })
.DataSource(ds => ds.Read(read =>
read.Action("YourFunction","YourController").Data("filterFunction"))
.ServerFiltering(true))
.MinLength(2)//number of characters for a valid search
.Delay(250)//milliseconds delay to trigger search
.AutoClose(false)
.AutoBind(false)
.IgnoreCase(true)
.DataTextField("Text")
.DataValueField("Value")
.Placeholder("Enter at least 2 letters to search")
.Filter(FilterType.Contains)
)
<script>
function filterFunction() {
return {
text: $("#GridName").data("kendoDropDownList").input.val()
};
}
</script>
If the search is still slow, you can change the number of characters

Well, what if you do both? Is maybe not the best aproach, but for me it worked.
I have a ComboBox that gets its info from an cascade event, so it would try either way to fill it up. So, after send the request to fill on server-side, I have a client-side event:
.Filter(Contains).MinLength(n).Filtering("Action")
Which will get to server throgh ajax to catch a Session var with the table/list with which you are trying to fill up your CB. Then filtering the desired list and send it back to your CB.

Related

How to control enabled state of a button in a Kendo UI Grid

I have up and down arrows in my Kendo UI grid. For the first item on the grid I do not want do allow the item to move down (it is impossible) and for the last item I do not want the item to move up (also impossible).
How can I do this?
$(document).ready(function() {
//Set URL of Rest Service
var loc = (location.href);
var url = loc.substring(0,loc.lastIndexOf("/")) + "/xpRest.xsp/xpRest1";
var dataSource = new kendo.data.DataSource({
transport: {
read: {
url: url,
type: 'GET'
},batch: false
}});
dataSource.read();
$("#gridIDNoScroll").kendoGrid({
dataSource: dataSource,
pageSize: 15,
noRecords: true,
selectable : false,
columns : [{
field : "name"
},{
field : "strDate",
width : 150
},{
field : "$10",
width : 150
},{
command: [
{
text: "&nbsp",
//click: moveDown,
imageClass: "k-icon k-i-arrow-s",
icon: "k-icon k-i-arrow-s",
title: "Up",
enable: false
},
{
text: "&nbsp",
//click: moveUp,
imageClass: "k-icon k-i-arrow-n",
icon: "k-icon k-i-arrow-n"
}
],
width:"90px"
},
]
});
});
This worked for me when I needed to disable the button. Use the databound event to basically change the state, use off to remove the event handler, and then override the click event. Something like this:
$('.k-grid-add').addClass('k-state-disabled');
$('.k-header').off('click').on('click', '.k-grid-add', function (e) {
// add new logic here or ignore it
});
If you have multiple buttons in the toolbar, the something like this:
$('.k-grid-add').addClass('k-state-disabled');
$('a.k-grid-add').on("click", function (e) {
e.preventDefault();
e.stopPropagation();
});
You can use the dataBound event of the Grid to apply a k-state-disabled CSS class to the desired buttons in the first and last row of the Grid.
Keep in mind that k-state-disabled only applies a "disabled" look, but the click event will still fire and the command function will execute. You can skip the row move logic for disabled buttons.
On a side note, you can use a command name to find buttons in the DOM more easily. For example, a command button with a name foo will have a CSS class of k-grid-foo.

Setting Value programmatically in KendoUI multiselect

I have my KendoUI MultiSelect widget initialized like this:
$("#" + key).kendoMultiSelect({
placeholder: placeholder,
dataTextField: dataText,
dataValueField: dataValue,
filter: "contains",
autoBind: false,
dataSource: {
type: "jsonp",
transport: {
read: {
url: urlValue
}
},
error: function(e) {
console.log(e);
}
},
value: GetSavedJSONObject(key),
//value: [
//{ Name: "Chang", Id: 2 },
// { Name: "Uncle Bob's Organic Dried Pears", Id: 7 }
//],
select: removeMark,
change: multiselect_checkForChanges,
autoClose: isAutoClose
});
where GetSavedJSONObject(key) is an array of objects like this:
[Object { Id=1, Name="AA"}, Object { Id=2, Name="BB"}]
The issue I'm facing is when the page loads, I can see "AA" and "BB" in the multiselect widget and no call is made to the url. However, when I attempt to add more items to the widget, there are none to be added because the widget thinks the only items available are the items I specified in the "value" field of the widget during initialization.
In the Server Filtering demo, you will see that the example sets the value of the widget just like I did but when you try to add more items to the widget, then a call is made to the url for more data and the widget opens.
I'm sure this is user error but I just need some pointers on what to try next in order to get the widget to display the rest of the data.
EDIT:
When I made GetSavedJSONObject(key) return an array of the Ids so
[1,2,3]
I was able to click on the widget to get the rest of the data. However, the desired outcome is being able to set the values of the widget (because I have the Id/Name pairs) without having to make the call to the datasource and being able to click on the widget to fetch the rest of the data)
Keeping my array of Objects and setting the serverFiltering: true attribute fixed the issue. Hope this saves someone else time. sigh

jqgrid retain filter on reload

This question has been as a lot so please forgive me asking again.
I have a grid loaded from a url.
I use loadonce: true
I use filtertoolbar:
$("#status").jqGrid('filterToolbar', { stringResult:true, searchOnEnter:false, autosearch: true, defaultSearch: "cn" });
I have a dropdown search list from which I can select what I'm looking for. Works great.
I have a navbutton I click to initiate a reload every 30 seconds. Works great.
$("#status").jqGrid('navButtonAdd','#statuspager', { caption: '', buttonicon: 'ui-icon-play', onClickButton: function ()
{
stint = setInterval (function() {
postfilt = $("#status").jqGrid('getGridParam', 'postData').filter;
$("#status").jqGrid('setGridParam',{
url: './ar_status.cgi?systemtype=' + systype,
datatype: "json",
postData: postfilt,
search: true,
loadtext: "Refreshing grid...",
loadonce: true,
loadui: "block"
});
$("#status").jqGrid().trigger("reloadGrid");
}, 30000);
},
title: 'Start Auto Refresh (every 30 sec.)'
});
Using google chrome I can see the filters that were specified being posted to the server:
systemtype:production
_search:true
nd:1358887757603
rows:1000
page:1
sidx:system
sord:asc
totalrows:700
filters:{"groupOp":"AND","rules":[{"field":"system","op":"eq","data":"ATTDA02"}]}
I can change the filter between reloads and see the new, even multiple filters:
systemtype:production
_search:true
nd:1358887847592
rows:1000
page:1
sidx:system
sord:asc
totalrows:700
filters:{"groupOp":"AND","rules":[{"field":"system","op":"eq","data":"ATTDA02"},{"field":"dow","op":"cn","data":"MO"}]}
I am using multipleSearch: true on the initial load. I'm pretty sure that's retained on reload
On the grid, the filtertoolbar retains my filter criteria, both text and selects, but when the grid reloads, the filters are ignored and the entire dataset is diplayed in the grid.
I've tried many examples posted here on SO. I've tried adding [{current:true}] to the reloadGrid call - no difference. I can't seem to retain and apply the filters on a reload.
I would like the reload to always return the full dataset from the server (which happens fine), and allow the current filter settings to control what is shown after the reload. I do not want to use the postdata to build a new SQL select statement - server side filtering, because at any time the user may want to click the pause button, select a new filter and view something else from the entire dataset without another reload.
$("#status").jqGrid('navButtonAdd','#statuspager', { caption: '', buttonicon: 'ui-icon-pause', onClickButton: function ()
{
clearInterval(stint);
},
title: 'End Auto Refresh'
});
How can this be done without using cookies, as I saw in one post?
I could try using jqGridExport'ing the postfilt var, and then jqGridImport'ing it but was hoping for a more direct approach. I'm not even sure this would help since I already have everything I need right here in the grid via postData.
As a side note, in my setGridParam above, the loadtext I specify is never displayed. Instead, the default "Loading..." is displayed. All of the other parameters are working.
Many thanks in advance,
Mike
Solution. The complete loadComplete to retain filters, sort index and sort order after a [json] reload from the server:
loadComplete: function() {
var $this = $(this);
postfilt = $this.jqGrid('getGridParam','postData').filters;
postsord = $this.jqGrid('getGridParam','postData').sord;
postsort = $this.jqGrid('getGridParam','postData').sidx;
if ($this.jqGrid("getGridParam", "datatype") === "json") {
setTimeout(function () {
$this.jqGrid("setGridParam", {
datatype: "local",
postData: {filters: postfilt, sord: postsord, sidx: postsort},
search: true
});
$this.trigger("reloadGrid");
}, 50);
}
}
Thanks very much!!!!
I only added a bit to your solution to retain the page number as well:
loadComplete: function () {
var $this = $(this);
var postfilt = $this.jqGrid('getGridParam', 'postData').filters;
var postsord = $this.jqGrid('getGridParam', 'postData').sord;
var postsort = $this.jqGrid('getGridParam', 'postData').sidx;
var postpage = $this.jqGrid('getGridParam', 'postData').page;
if ($this.jqGrid("getGridParam", "datatype") === "json") {
setTimeout(function () {
$this.jqGrid("setGridParam", {
datatype: "local",
postData: { filters: postfilt, sord: postsord, sidx: postsort },
search: true
});
$this.trigger("reloadGrid", [{ page: postpage}]);
}, 25);
}
}
I am not sure, but I suppose that the origin of your first problem could be mixing postData.filters and postData and usage filter property instead of filters``. You use
postfilt = $("#status").jqGrid('getGridParam', 'postData').filter;
to get filter property instead of filters. You get undefined value. So the setting postData to postfilt means nothing.
The next problem is that the server response contains non-filtered data. To force filtering the data locally you have to reload the grid once after the loading from the server have finished. You can do this inside of loadComplete. Exactly here you can set postData.filter if required, set search: true and trigger reloadGrid event. It's important only to do this once to have no recursion and you must don't set datatype back to "json" in the case. The datatype will be changed to "local" and the end of loading from the server in case of usage loadonce: true option. If you want apply filtering locally you have to reload grid once with options datatype: "local", search: true and postData having filters specifying the filter which need by applied. See the code from the answer or another one which do another things, but the code which you need will be very close.

Append record and sync when button click based on Autocomplete value selected

I need to append record based on Autocomplete when the button click :
The Autocomplete bind to wcf in remote database. What i need to do is append the record to local database and sync. Please advise what i need proceed. Thank you
$(document).ready(function () {
$("#search").kendoAutoComplete({
minLength: 3,
dataTextField: "SDesc",
dataValueField: "RefID",
template: '${ data.SDesc } ' + '(' + '${ data.SDate }' + ')',
dataSource: {
type: "odata",
serverFiltering: true,
serverPaging: true,
pageSize: 20,
transport: {
read: "http://localhost:54329/HH_WcfDataService.svc/Product"
}
}
});
$('#btnSelect').click(function (e){
var value = $("#search").data("kendoAutoComplete").value();
});
});
Actually only the Autocomplete dataTextField is posted to the server when the AutoComplete is positioned inside of a form element (just like a normal input). For your case the AutoComplete text will be posted using the search name.
If you want to send the underlying dataValueField (which is actually never used by the AutoComplete widget) you should use the ComboBox widget.

MVC 3 Client side validation on jQuery dialog

I am showing lots of form using jquery dialog and I wish to add in client side validation on it. I read through some examples, saying that mvc 3 already somehow support jquery client side validation, but I tried by including the necessary script, and my form like this:
#using (Html.BeginForm("CreateFood", "Home", FormMethod.Post, new { id = "formData" }))
{
#Html.ValidationSummary(false, "Please fix these errors.")
When i try to submit my form without fill in the required field, I still dint get any message. Can anyone give me more idea / explanation / examples on this??
Really needs help here... Thanks...
UPDATE (add in the script for my dialog)
$createdialog.dialog("option", "buttons", {
"Cancel": function () {
//alert('Cancel');
$createdialog.dialog('close');
},
"Submit": function () {
var frm = $('#formData');
$.ajax({
url: '/Food/CreateFood',
type: 'POST',
data: frm.serialize(),
success: $createdialog.dialog('close')
});
}
});
Once dropped, open dialog:
// Once drop, open dialog to create food
options.drop = function (event, ui) {
// Get the ContainerImgName which food dropped at
var cimg = $(this).attr('id');
// Pass in ContainerImgName to retrieve respective ContainerID
// Once success, set the container hidden field value in the FoodForm
$.ajax({
url: '/food/getcontainerid',
type: 'GET',
data: { cImg: cimg },
success: function (result) { $('#containerID').val(result); }
});
clear();
$.validator.unobtrusive.parse($createdialog);
$createdialog.dialog('open');
};
I've faced the same problem, solved with:
$(name).dialog({
autoOpen: true,
width: options.witdth,
heigth: options.height,
resizable: true,
draggable: true,
title: options.title,
modal: true,
open: function (event, ui) {
// Enable validation for unobtrusive stuffs
$(this).load(options.url, function () {
var $jQval = $.validator;
$jQval.unobtrusive.parse($(this));
});
}
});
of course you can add the validation on the close event of the dialog, depends on what you're doing, in my case the popup was just for displaying errors so I've performed validation on load of the content. (this pop up is displaying am Action result)
For every dynamically generated form you need to manually run the validator once you inject this content into the DOM as shown in this blog post using the $.validator.unobtrusive.parse function.

Resources