Assigning JSon data in JqGrid using WebApi - asp.net-mvc

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).

Related

Changing the value attribute of an item in a select2 following an AJAX db insert

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.

How can I persist newly saved values across components? Pulling original values from DOM

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?

Setting initial value for select2 with ajax data source

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.

.ajax() appends 'data' key values to URL even in POST mode

This is my code for the .ajax() call:
$.ajax({
type: "POST",
url: "http://ws.geonames.org/searchJSON",
dataType: "jsonp",
data: {
featureClass: "P",
style: "full",
maxRows: 12,
name_startsWith: request.term
}
In addition to using type:"POST" as above, I also tried using $.ajaxSetup({type: "post"}); above this code block.
In both cases, the values in the data key are being appended to the URL. I want a clean URL with no parameters. This code is actually a part of an autocomplete field, it's wrapped into an anonymous function and given a key source like the main jQueryUI examples.
Note The actual URL is immaterial, I don't know if geonames supports POST requests but that's going to change later, this is just an example.
Simply add your parameters like this :
url: "http://ws.geonames.org/searchJSON/" + param,
If you want to force POST, you can try jQuery.post()
It is not possible to make a POST request with the JSONP datatype.
JSONP works by creating a <script> tag that executes Javascript from a different domain, it is not possible to send a POST request using a <script> tag.
If you specify dataType: "jsonp" and type: "POST", the "jsonp" takes precedent and it gets sent as a "GET" request (the "POST" gets ignored).

Limiting requested field set of Kendo UI Grid bound to OData service

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

Resources