How to configure the Kendo UI grid, so it would issue requests only for specific (displayed) fields?
In my instance, a Kendo UI grid is bound to a OData service. The service exposes a table with many (200+) fields. The app allows users to configure displayed field set of the Grid, set initial filters and sort parameters. The app configures the Grid, which then goes off and queries OData service.
The grid kendo.Data.DataSource is defined as:
var gridDataSource = new kendo.data.DataSource({
type: "odata",
transport: {
read: {
url: "#Url.Content(dynDataSource.Url)",
contentType: "application/json; charset=utf-8",
type: "GET",
dataType: "json"
}
},
pageSize: #Model.MaxPageSize,
serverPaging: true,
serverFiltering: true,
serverSorting: true,
filter: ...
}
Here's a sample request issued by the Grid (captured by Firebug):
http://localhost:22411/Data/Comp?%24inlinecount=allpages&%24top=1000&%24filter=DistrictCode+eq+%27460800%27
This returns all the fields of the table, which is a problem. The fields need to be limited by selecting only the required fields, the request for which would look like:
http://localhost:22411/Data/Comp?%24inlinecount=allpages&%24top=1000&%24filter=DistrictCode+eq+%27460800%27&%24select=DistrictCode,DistrictName,DistrictNumber
Again, how to configure the grid for this to happen?
I realize the source is available for Kendo UI, but I'm currently still on a trial version which doesn't include the source.
I think I've got a workable solution for this myself. I used an idea from this blog post:
http://community.dynamics.com/product/crm/crmtechnical/b/zhongchenzhoustipstricksandportaldevelopment/archive/2012/05/20/how-to-use-kendo-ui-datasource-kendo-ui-grid-with-dynamics-crm-2011-rest-endpoint.aspx
I attach an event handler the ajaxSend event, watch for my OData Service URL, and once such a request is detected, append the select column list to the URL. Here's the code:
$(document).ajaxSend(function (e, jqxhr, settings) {
if (settings.url.toLowerCase().indexOf("#Url.Content(dynDataSource.Url)".toLowerCase()) >= 0) {
settings.url += "&%24select=#requestColumnList";
}
});
Hope this helps. Still, if someone has got a better solution, I'd like to hear it.
I've also posted this question to Telerik forums: http://www.kendoui.com/forums/framework/data-source/configure-the-kendo-ui-datasource-so-it-would-issue-requests-only-for-specific-displayed-fields.aspx#2131604
I ran into a similar issue and implemented an approach that constructs an array of included columns in the transport's read data callback:
dataSource.transport.read.data = function(options) {
var data = {};
data["$select"] = columns.map(function(c) {
return c.field;
});
return data;
}
If you are using column menu and have hidden columns, you can also filter based on which columns are visible and force a grid refresh as columns are enabled.
columnShow: function (e) {
e.sender.dataSource.read();
}
Related
I'm adding a new item to a select2. When this happens I'm triggers an onChange AJAX request. The AJAX request adds the new item to a DB and returns the id of the row that has been inserted.
ATM, the value of the added option in the select2 contains the original string value that I entered. I want to update the value of that specific option in the select2, so that it becomes the id of the database row that was returned from the AJAX call.
Here's the JS:
$('.my-select2').on('change', function() {
$.ajax({
type: 'POST',
url: '/ajax/groups/saveGroup',
data: {
"_token": "{{ csrf_token() }}",
"value": this.value
},
dataType: 'json',
success: function(data){
console.log(data); // this equals the id of the row in the db,
// and it's what I want to make into the value of
// the option that's been added.
// I've tried many more than the following and none have worked.
// $(this).attr("value", data);
// $(this).val(data).change();
// $(this).select2("val", data);
// $('.my-select2').select2('data', {id: data, text: 'original value'});
}
});
Please help, I'm out of ideas, and out of Google searches.
I solved this by having a separate AJAX function outside of this, which retrieved all of the records from the db and re-painted the entire select2 control. It's a little more expensive, but does the job.
I have 3 different components with buttons to navigate across them. All of the default form values are pulled from the DOM and set into the data beforeMount. The reason I'm doing it this way is that the values are coming from my Rails database.
When I edit a form and save it successfully (via ajax), everything is good but once I switch components using the navigation, those values in the inputs are reset back to the original/old values since the beforeMount is running again and the DOM was not updated with the new value (due to no refresh yet).
I tried changing the original values in the DOM with jQuery upon every update but that didn't work. It would work once but further updates didn't change.
Here is how I'm setting the data inside of the beforeMount:
const element = document.getElementById('setting');
const setting = JSON.parse(element.dataset.setting)
this.discountType = setting.discount_type;
Then, upon every ajax request I tried to edit those original values in the DOM which didn't work:
outerThis = this;
Rails.ajax({
url: '/update-settings',
type: 'POST',
data: data,
dataType: 'json',
success: (data) => {
ShopifyApp.flashNotice('Successfully updated')
var settings = $('#setting').data('setting')
settings.discount_type = outerThis.discountType
},
error: (err) => {
ShopifyApp.flashError('There was an error')
}
})
What's the recommended way to go about this issue?
I use select2 for specifying recipients for the website's inner messaging system. There are users and they can send messages to each other. They can search other users by the user name.
I use the following config:
this.$select2.select2({
multiple: true,
ajax: {
url: "/userSearch",
dataType: "json",
},
templateResult: function(data) {
var user = new SomeComplexUserModel(data);
var $div = $(<div></div>");
$div.append("<img src='"+user.image.readPaths().crop+"'>");
$div.append("<span>"+user.fullName()+"</span>");
return $div;
},
templateSelection: ..the same as templateResult..
Now I want to set initial value for this. How to do that? I have the list of ids of the users that have to be selected on page load. I make the separate request to /userSearch and receive the data. Then I'm trying to push this data to the select2 somehow.
I can't create native var opt = new Option(text,value); select.append(opt) because this case templateSelection gets only id and text from the option, it can't construct the user model based on this data only. It does not show users with avatars.
I tried to trigger select2:select event with {originalEvent:null,data:$.extend(ajaxResult,{selected:true,disabled:false,element:null},_type:"select")}, but it seems it does not work this direction. It emits events but is not subscribed for them.
I also tried to set this.$select2.val(ajaxData); this.$select2.trigger('change'), after select2 initialization, but it does not work either.
I am building an application using MVC & Web Api. On a View I am using JqGrid. Previously we used to assign local data to JqGrid which was working fine. Now due to some changes in logic, we are using WebApi to bring data from Server, this is a Json data, we store it in variable then we assign this data object to JqGrid but data does not get displayed.
When instead of data option i give "url" of web api then everything works fine, but as soon we use "data" option then jqgrid does not work.What could be the possible reason? Reason for doing this is that I want to add, edit, update data locally and then when final save button is pressed, data goes back to Server.
$().ready(function () {
//{"total":1,"page":1,"records":3,"rows":[{"id":"1","cell":["1","Tomato
//Soup","db#db.com","db#db.com","Groceries"]},{"id":"2","cell":["2","Yo-
//yo","db#db.com","db#db.com","Toys"]},{"id":"3","cell":
//["3","Hammer","db#db.com","db#db.com","Hardware"]}]}
//
$.getJSON("api/userwebapi/",
function (data) {
//userDataFromApi = jQuery.parseJSON(data);
userDataFromApi =data;
//alert(userDataFromApi[0].ID);
ConfigureUserGrid(userDataFromApi);
});
});
function ConfigureUserGrid(userDataFromApi) {
var grdUsers = $("#grdUsers");
var lastsel = 0;
$("#grdUsers").jqGrid({
datatype: "json"
, data: userDataFromApi
//, url: "api/userwebapi"
,colNames: ['ID', 'Name', 'User Role', 'Email', 'Address']
,colModel: [
{ name: 'ID', index: 'ID', width: 80, hidden: true }
, { name: 'Name', index: 'Name', width: 150 }
, { name: 'UserRole', index: 'UserRole', width: 150 }
, { name: 'Email', index: 'Email', width: 200, sortable: true }
, { name: 'Address', index: 'Address', width: 200, sortable: true }]
, viewrecords: true
, pager: '#pager1'
, mtype: 'GET'
,rowNum:true
,caption: 'My first grid'
}); //close of jQuery("#grdUsers").jqGrid({
$("#grdUsers").jqGrid('navGrid', '#pager1',
{ add: false, del: false, edit: false, search: false, refresh: false });
}
The reason of the problem is wrong usage of jqGrid parameters (options). To be exactly you use wrong combination of jqGrid options. Tony Tomov (the developer of jqGrid) added many features in jqGrid during every new version. He wanted to hold backwards compatibility if it's possible. As the result there are a lot of options without clear name conversion. Many options work only if some other options are set. Exactly like in case of jQuery or jQuery UI there are no validation of input parameters. It makes many problems who people who starts to use jqGrid.
The problem in your case is the usage of data parameter together with datatype: "json". It's wrong combination of parameters. The problem is that jqGrid supports two remote datatypes and some local datatypes.
If you use datatype: "json" or datatype: "xml" then jqGrid get for you AJAX request for initial filling of grid and on every sorting, paging and (optionally) filtering. In any way the request to the url will be send. One uses HTTP command specified by mtype parameter. The paging and sorting of data have to be implemented on the server side. The request contain the requested page number, the length of the page, the index of the column used for the sorting and the direction of sorting. The data returned from the server should in the format described here. If you have non-standard data format you can use jsonReader options of jqGrid and jsonmap (xmlmap) in colModel to specify how the server response should be used to fill the grid.
If you don't want to implement server side paging, sorting and filtering of data you can use loadonce: true option. In the case the server should return all data at once. The data should be sorted once based on the initial sorting column (based of sortname and sortorder which you use). jqGrid will change datatype automatically to "local" after the first loading of data.
All other datatypes will be interpreted as local datatypes. The data parameter will be used only in case of datatype: "local". One should use another format of data in the case. One can use localReader (see here) to change the way how the data should be read from data parameter.
There are special case datatype: "jsonstring" where you can fill the grid in the way close with datatype: "json", but to use an object or JSON string as the input. In the case one should use datastr (not data !!!) as the input of data. After the first filling the datatype will be changed by jqGrid from datatype: "jsonstring" to datatype: "local".
So you have some options to fix the problem:
to use url and loadonce: true options if you don't want to implement paging of data.
to use datatype: "jsonstring" and datastr instead of data.
to use datatype: "local" and data filled as array of named items (properties of items should be the same as the value of name property of the columns).
I have an ASP.NET MVC 3 Web Application (Razor), and a particular View with the jQuery UI AutoComplete plugin (v1.8).
Here's the setup i currently have:
$('#query').autocomplete({
source: function (request, response) {
$.ajax({
url: "/Search/FindLocations",
type: "POST",
dataType: "json",
data: { searchText: request.term },
success: function (data) {
response($.map(data, function (item) {
return { name: item.id, value: item.name, type: item.type }
}))
},
error: function (xmlHttpRequest, textStatus, errorThrown) {
// don't know what i should do here...
}
})
},
select: function (event, ui) {
$.get('/Search/RenderLocation', { id: ui.item.name }, function (data) {
$('#location-info').html(data);
});
},
delay: 300, minLength: 3
});
The AutoComplete returns locations in the world, basically identical to Google Maps auto complete.
Here are my questions:
1) What are the recommended settings for delay and minLength? Leave as default?
2) I thought about putting [OutputCache] on the Controller action, but i looks as though the plugin automatically does caching? How does this work? Does it store the results in a cookie? If so when does it expire? Is any additional caching recommended?
3) I've noticed if i type something, and whilst the AJAX request is fired off, if i type something else, the dialog shows the first result momentarily, then the second result. I can understand why, but it's confusing to the user (given the AJAX request can take 1-2 seconds) but i'm thinking about using async: false in the $.ajax options to prevent multiple requests - is this bad design/UX?
4) Can you recommend any other changes on my above settings for improving performance/usability?
1) It really depends on your usage and your data.
2) You should use [OutputCache]. If there's any caching happening on the plugin, it's only going to be for each user, if you use caching at the controller action level, it'll cache one for all users. (again, this might actually be bad depending on your usage, but usually this is good to do)
3) This questions kind of hard too because of the lack of context. If ajax requests are 1-2 seconds and there's no way to make this shorter, you really should be a pretty big delay in so that users aren't sending off many requests while typing out a long word (if they type slow).
4) sounds like you need to look at your /search/FindLocations method and see where you can do caching or pref improvements. Give us a look at your code in here and I can try to suggest more.