Jqgrid Incorrect Select Drop Down Option Values in Edit Box

jqgrid incorrect select drop down option values in edit box

The answer on your question depend a little from the source where you receive the information about displayed under "State for US" and "State for UK". The are two possibilities supported by jqGrid: 1) the usage of value parameter of editoptions 2) the usage of dataUrl and buildSelect parameter of the editoptions. The first way is the best one in case of local editing or in the case if the list of possible options is static. The second choose will be used in the case, that the information about states, countries and the states of some country will be get per AJAX request from the database. I describe the solution on the example the usage of value parameter to have no dependencies to the server components. The most parts on the implementation are the same in case of the usage of dataUrl and buildSelect.

I made the live example which demonstrate what you need.

The main problem is that the value of the editoptions are used only once at the time on the initialization. Inside of dataInit function one can overwrite the value, but after the changing of the value in the first select/drop-down box with countries the second select/drop-down box with states must be rebuild manually. To do so one have to understand, that the select HTML element has id constructed from row id '_' and the column name: rowId + "_State". Moreover it is important, that the the value of the editoptions must be reset to the initial value, so that any state id can be decoded to the state name.

Here is the code from the example:

var countries = { '1': 'US', '2': 'UK' };
var states = { '1': 'Alabama', '2': 'California', '3': 'Florida', '4': 'Hawaii', '5': 'London', '6': 'Oxford' };
var statesOfCountry = {
1: { '1': 'Alabama', '2': 'California', '3': 'Florida', '4': 'Hawaii' },
2: { '5': 'London', '6': 'Oxford' }
};
var mydata = [
{ id: '0', Country: '1', State: '1', Name: "Louise Fletcher" },
{ id: '1', Country: '1', State: '3', Name: "Jim Morrison" },
{ id: '2', Country: '2', State: '5', Name: "Sherlock Holmes" },
{ id: '3', Country: '2', State: '6', Name: "Oscar Wilde" }
];

var lastSel = -1;
var grid = jQuery("#list");
var resetStatesValues = function () {
grid.setColProp('State', { editoptions: { value: states} });
};
grid.jqGrid({
data: mydata,
datatype: 'local',
colModel: [
{ name: 'Name', width: 200 },
{ name: 'Country', width: 100, editable: true, formatter: 'select',
edittype: 'select', editoptions: {
value: countries,
dataInit: function (elem) {
var v = $(elem).val();
// to have short list of options which corresponds to the country
// from the row we have to change temporary the column property
grid.setColProp('State', { editoptions: { value: statesOfCountry[v]} });
},
dataEvents: [
{
type: 'change',
fn: function(e) {
// To be able to save the results of the current selection
// the value of the column property must contain at least
// the current selected 'State'. So we have to reset
// the column property to the following
//grid.setColProp('State', { editoptions:{value: statesOfCountry[v]} });
//grid.setColProp('State', { editoptions: { value: states} });
resetStatesValues();

// build 'State' options based on the selected 'Country' value
var v = parseInt($(e.target).val(), 10);
var sc = statesOfCountry[v];
var newOptions = '';
for (var stateId in sc) {
if (sc.hasOwnProperty(stateId)) {
newOptions += '<option role="option" value="' +
stateId + '">' +
states[stateId] + '</option>';
}
}

// populate the new
if ($(e.target).is('.FormElement')) {
// form editing
var form = $(e.target).closest('form.FormGrid');
$("select#State.FormElement", form[0]).html(newOptions);
} else {
// inline editing
var row = $(e.target).closest('tr.jqgrow');
var rowId = row.attr('id');
$("select#" + rowId + "_State", row[0]).html(newOptions);
}
}
}
]
}
},
{
name: 'State', width: 100, editable: true, formatter: 'select',
edittype: 'select', editoptions: { value: states }
}
],
onSelectRow: function (id) {
if (id && id !== lastSel) {
if (lastSel != -1) {
resetStatesValues();
grid.restoreRow(lastSel);
}
lastSel = id;
}
},
ondblClickRow: function (id, ri, ci) {
if (id && id !== lastSel) {
grid.restoreRow(lastSel);
lastSel = id;
}
resetStatesValues();
grid.editRow(id, true, null, null, 'clientArray', null,
function (rowid, response) { // aftersavefunc
grid.setColProp('State', { editoptions: { value: states} });
});
return;
},
editurl: 'clientArray',
sortname: 'Name',
height: '100%',
viewrecords: true,
rownumbers: true,
sortorder: "desc",
pager: '#pager',
caption: "Demonstrate dependend select/dropdown lists (edit on double-click)"
}).jqGrid('navGrid','#pager',
{ edit: true, add: true, del: false, search: false, refresh: false },
{ // edit options
recreateForm:true,
onClose:function() {
resetStatesValues();
}
},
{ // add options
recreateForm:true,
onClose:function() {
resetStatesValues();
}
});

UPDATED: I updated the code above to make it working with in case of form editing too. You can see it live here. Because jqGrid not support local editing for form editing I could not tested the code. Nevertheless I hope that I made the most of required changes.

UPDATED 2: I extended the above code to support

  1. Inline editing, Form editing, Searching Toolbar and Advanced Searching
  2. The previous or next navigation buttons in the editing form
  3. Improving keyboard support in selects (problem with refreshing dependent select in some browsers are fixed)

The new version of the demo is here. The modified code of the demo you find below:

var countries = { '1': 'US', '2': 'UK' },
//allCountries = {'': 'All', '1': 'US', '2': 'UK'},
// we use string form of allCountries to have control on the order of items
allCountries = ':All;1:US;2:UK',
states = { '1': 'Alabama', '2': 'California', '3': 'Florida', '4': 'Hawaii', '5': 'London', '6': 'Oxford' },
allStates = ':All;1:Alabama;2:California;3:Florida;4:Hawaii;5:London;6:Oxford',
statesOfUS = { '1': 'Alabama', '2': 'California', '3': 'Florida', '4': 'Hawaii' },
statesOfUK = { '5': 'London', '6': 'Oxford' },
// the next maps contries by ids to states
statesOfCountry = { '': states, '1': statesOfUS, '2': statesOfUK },
mydata = [
{ id: '0', country: '1', state: '1', name: "Louise Fletcher" },
{ id: '1', country: '1', state: '3', name: "Jim Morrison" },
{ id: '2', country: '2', state: '5', name: "Sherlock Holmes" },
{ id: '3', country: '2', state: '6', name: "Oscar Wilde" }
],
lastSel = -1,
grid = $("#list"),
removeAllOption = function (elem) {
if (typeof elem === "object" && typeof elem.id === "string" && elem.id.substr(0, 3) !== "gs_") {
// in the searching bar
$(elem).find('option[value=""]').remove();
}
},
resetStatesValues = function () {
// set 'value' property of the editoptions to initial state
grid.jqGrid('setColProp', 'state', { editoptions: { value: states} });
},
setStateValues = function (countryId) {
// to have short list of options which corresponds to the country
// from the row we have to change temporary the column property
grid.jqGrid('setColProp', 'state', { editoptions: { value: statesOfCountry[countryId]} });
},
changeStateSelect = function (countryId, countryElem) {
// build 'state' options based on the selected 'country' value
var stateId, stateSelect, parentWidth, $row,
$countryElem = $(countryElem),
sc = statesOfCountry[countryId],
isInSearchToolbar = $countryElem.parent().parent().parent().hasClass('ui-search-toolbar'),
//$(countryElem).parent().parent().hasClass('ui-th-column')
newOptions = isInSearchToolbar ? '<option value="">All</option>' : '';

for (stateId in sc) {
if (sc.hasOwnProperty(stateId)) {
newOptions += '<option role="option" value="' + stateId + '">' +
states[stateId] + '</option>';
}
}

setStateValues(countryId);

// populate the subset of contries
if (isInSearchToolbar) {
// searching toolbar
$row = $countryElem.closest('tr.ui-search-toolbar');
stateSelect = $row.find(">th.ui-th-column select#gs_state");
parentWidth = stateSelect.parent().width();
stateSelect.html(newOptions).css({width: parentWidth});
} else if ($countryElem.is('.FormElement')) {
// form editing
$countryElem.closest('form.FormGrid').find("select#state.FormElement").html(newOptions);
} else {
// inline editing
$row = $countryElem.closest('tr.jqgrow');
$("select#" + $.jgrid.jqID($row.attr('id')) + "_state").html(newOptions);
}
},
editGridRowOptions = {
recreateForm: true,
onclickPgButtons: function (whichButton, $form, rowid) {
var $row = $('#' + $.jgrid.jqID(rowid)), countryId;
if (whichButton === 'next') {
$row = $row.next();
} else if (whichButton === 'prev') {
$row = $row.prev();
}
if ($row.length > 0) {
countryId = grid.jqGrid('getCell', $row.attr('id'), 'country');
changeStateSelect(countryId, $("#country")[0]);
}
},
onClose: function () {
resetStatesValues();
}
};

grid.jqGrid({
data: mydata,
datatype: 'local',
colModel: [
{ name: 'name', width: 200, editable: true },
{ name: 'country', width: 100, editable: true, formatter: 'select', stype: 'select', edittype: 'select',
searchoptions: {
value: allCountries,
dataInit: function (elem) { removeAllOption(elem); },
dataEvents: [
{ type: 'change', fn: function (e) { changeStateSelect($(e.target).val(), e.target); } },
{ type: 'keyup', fn: function (e) { $(e.target).trigger('change'); } }
]
},
editoptions: {
value: countries,
dataInit: function (elem) { setStateValues($(elem).val()); },
dataEvents: [
{ type: 'change', fn: function (e) { changeStateSelect($(e.target).val(), e.target); } },
{ type: 'keyup', fn: function (e) { $(e.target).trigger('change'); } }
]
}},
{ name: 'state', width: 100, formatter: 'select', stype: 'select',
editable: true, edittype: 'select', editoptions: { value: states },
searchoptions: { value: allStates, dataInit: function (elem) { removeAllOption(elem); } } }
],
onSelectRow: function (id) {
if (id && id !== lastSel) {
if (lastSel !== -1) {
$(this).jqGrid('restoreRow', lastSel);
resetStatesValues();
}
lastSel = id;
}
},
ondblClickRow: function (id) {
if (id && id !== lastSel) {
$(this).jqGrid('restoreRow', lastSel);
lastSel = id;
}
resetStatesValues();
$(this).jqGrid('editRow', id, {
keys: true,
aftersavefunc: function () {
resetStatesValues();
},
afterrestorefunc: function () {
resetStatesValues();
}
});
return;
},
editurl: 'clientArray',
sortname: 'name',
ignoreCase: true,
height: '100%',
viewrecords: true,
rownumbers: true,
sortorder: "desc",
pager: '#pager',
caption: "Demonstrate dependend select/dropdown lists (inline editing on double-click)"
});
grid.jqGrid('navGrid', '#pager', { del: false }, editGridRowOptions, editGridRowOptions);
grid.jqGrid('filterToolbar', {stringResult: true, searchOnEnter: true, defaultSearch : "cn"});

UPDATED 3: The last version of the code of the demo you will find here.

JQGrid - Drop down value not set correctly when edittype = 'select'

The demo which you use don't reproduce the problem because both jqGrid 4.6 and the old version 4.4.4 don't supports local data editing. It's important that you use

formatter:'select'

Only in the case jqGrid should save values of the drop-down/combo-box. In any way you can verify that free jqGrid 4.9.1 don't have the described problem (I used just URLs described in the wiki article): http://jsfiddle.net/OlegKi/ehj0nyLu/5/. I can imagine that some bugs exist in the old version 4.4.4, but it's clear that nobody will fix the bugs. So I would recommend you to update to free jqGrid. It's the fork of jqGrid which I continue to develop after Tony have changed the licence agreement for jqGrid in 4.7.1 version. His fork have the name Guriddo jqGrid JS. If you will find some bugs in free jqGrid then you can post the issue to GitHub or post the description of the problem on stackoverflow. The latest version can be easy fixed, but not the retro version 4.4.4.

UPDATED: The bug is fixed in the latest version of free jqGrid on GitHub: http://jsfiddle.net/OlegKi/ehj0nyLu/6/. The fixed code will be included in free jqGrid 4.9.2 which I will publish today.

Just for information I repeat what I wrote before in comment: the line of code jqGrid 4.4.4, which you use, like all later versions of jqGrid and free jqGrid (less then 4.9.2) tests for either the value or the text during selection of option of <select> during editing. It's correct to test for the value only and the select the option by text only if no option were found by value. The fix implements the changes.

jqgrid cascading dropdown lists in pop up edit mode

The old answer shows how one can implement the dependent selects. You use form editing. Thus the <select> element of PriceCode column of the form editing will have the id="PriceCode". You can use $("#PriceCode").html(/*new options*/); to change the options of <select> editing field of PriceCode column inside of change event handler of CurrCd column.

How to load Values into the edit-form of jqGrid when user select from select box

To bind event (like change event in your case) to the edit field you should use dataEvents of the editoptions. See here, here or here examples. Moreover I recommend you to use recreateForm:true option additionally.

jqGrid cascading drop down change event does not fire

OK, the issue was that in the ondblClickRow event handler I was setting the editoptions / dataUrl property. As I was not also specifying the editoptions / dataEvents property at this point it was basically overwriting the static event handler with nothing.

in the ondblClickRow event handler I was only overwriting Project and Tasks drop down, which explains why the Project handler was being removed and not the Customer one.

Apologies to Oleg: I did not post the full code at the start, so I did not include the double click event.

Anyway Oleg if you can suggest how I can preserve the event handler I can award you the answer. Otherwise I will award this as the answer, even though your help has been invaluable. I'm guessing I might need to move the event handler definition down to the dblclick event handler rather than in the column definition?

Jqgrid cascading dropdown

In case of usage free jqGrid you can use a little simplified code

$(function () {
"use strict";
var countries = "usId:US;ukId:UK",
allStates = "alabamaId:Alabama;californiaId:California;floridaId:Florida;hawaiiId:Hawaii;londonId:London;oxfordId:Oxford",
// the next maps provide the states by ids to the countries
statesOfCountry = {
"": allStates,
usId: "alabamaId:Alabama;californiaId:California;floridaId:Florida;hawaiiId:Hawaii",
ukId: "londonId:London;oxfordId:Oxford"
},
mydata = [
{ id: "10", country: "usId", state: "alabamaId", name: "Louise Fletcher" },
{ id: "20", country: "usId", state: "floridaId", name: "Jim Morrison" },
{ id: "30", country: "ukId", state: "londonId", name: "Sherlock Holmes" },
{ id: "40", country: "ukId", state: "oxfordId", name: "Oscar Wilde" }
],
$grid = $("#list"),
changeStateSelect = function (countryId, countryElem) {
// build "state" options based on the selected "country" value
var $select, selectedValues,
$countryElem = $(countryElem),
isInSearchToolbar = $countryElem.parent().parent().parent().parent().hasClass("ui-search-table");

// populate the subset of countries
if (isInSearchToolbar) {
// searching toolbar
$select = $countryElem.closest("tr.ui-search-toolbar")
.find(">th.ui-th-column select#gs_list_state");
} else if ($countryElem.is(".FormElement")) {
// form editing
$select = $countryElem.closest("form.FormGrid")
.find("select#state.FormElement");
} else {
// inline editing
$select = $("select#" + $.jgrid.jqID($countryElem.closest("tr.jqgrow").attr("id")) + "_state");
}

if ($select.length > 0) {
selectedValues = $select.val();
if (isInSearchToolbar) {
$select.html("<option value=\"\">All</option>");
} else {
$select.empty();
}
$.jgrid.fillSelectOptions($select[0], statesOfCountry[countryId], ":", ";", false, selectedValues);
}
},
dataInitCountry = function (elem) {
setTimeout(function () {
$(elem).change();
}, 0);
},
dataEventsCountry = [
{ type: "change", fn: function (e) { changeStateSelect($(e.target).val(), e.target); } },
{ type: "keyup", fn: function (e) { $(e.target).trigger("change"); } }
],
cancelInlineEditingOfOtherRows = function (rowid) {
var $self = $(this), savedRows = $self.jqGrid("getGridParam", "savedRow");
if (savedRows.length > 0 && rowid !== savedRows[0].id) {
$self.jqGrid("restoreRow", savedRows[0].id);
}
};

$grid.jqGrid({
data: mydata,
datatype: "local",
colNames: [ "Name", "Country", "State" ],
colModel: [
{ name: "name", width: 180 },
{ name: "country", formatter: "select", stype: "select", edittype: "select",
searchoptions: {
noFilterText: "Any",
dataInit: dataInitCountry,
dataEvents: dataEventsCountry
},
editoptions: {
value: countries,
dataInit: dataInitCountry,
dataEvents: dataEventsCountry
}},
{ name: "state", formatter: "select", stype: "select", edittype: "select",
editoptions: { value: allStates }, searchoptions: { noFilterText: "Any" } }
],
cmTemplate: { width: 100, editable: true },
onSelectRow: cancelInlineEditingOfOtherRows,
ondblClickRow: function (rowid) {
cancelInlineEditingOfOtherRows.call(this, rowid);
$(this).jqGrid("editRow", rowid);
},
inlineEditing: {
keys: true
},
formEditing: {
onclickPgButtons: function (whichButton, $form, rowid) {
var $self = $(this), $row = $($self.jqGrid("getGridRowById", rowid)), countryId;
if (whichButton === "next") {
$row = $row.next();
} else if (whichButton === "prev") {
$row = $row.prev();
}
if ($row.length > 0) {
countryId = $self.jqGrid("getCell", $row.attr("id"), "country");
changeStateSelect(countryId, $form.find("#country")[0]);
}
},
closeOnEscape: true
},
searching: {
searchOnEnter: true,
defaultSearch: "cn"
},
navOptions: {
del: false,
search: false
},
iconSet: "fontAwesome",
sortname: "name",
sortorder: "desc",
viewrecords: true,
rownumbers: true,
pager: true,
pagerRightWidth: 85, // fix wrapping or right part of the pager
caption: "Demonstrate dependent selects (inline editing on double-click)"
})
.jqGrid("navGrid")
.jqGrid("filterToolbar");
});

see https://jsfiddle.net/OlegKi/svnL4Lsv/3/

How to update Second Dropdown based on Value of First's in Form Editing of jQgrid

It will work like below

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> New Document </TITLE>
<META NAME="Generator" CONTENT="EditPlus">
<META NAME="Author" CONTENT="">
<META NAME="Keywords" CONTENT="">
<META NAME="Description" CONTENT="">
</HEAD>

<script>

grid.jqGrid({
data: mydata,
datatype: 'local',
ondblClickRow: function(rowid) {
jQuery(this).jqGrid('editGridRow', rowid,
{recreateForm:true,closeAfterEdit:true,
closeOnEscape:true,reloadAfterSubmit:false});
},
colModel: [
{ name: 'Name', w 200 },
{ name: 'Country', width: 100, editable: true, formatter: 'select',
edittype: 'select', editoptions: {
value: <someStaticOrDynamicValues>,
},
dataEvents: [
{
type: 'change',
fn: function(e) {
changeStateSelect(e);
}
}
]
}
},
{
name: 'State', width: 100, editable: true, formatter: 'select',
edittype: 'select', editoptions: { value: states }
}
],

});

function changeStateSelect(e){
var countryId = $(e.target).val();
$.ajax({
url:"getStateList.html?countryId="+countryId,
type: "post",
success:function(newOptions){
var form = $(e.target).closest("form.FormGrid");
$("select#State.FormElement",form[0]).html(newOptions);
}
});
}
</script>
<BODY>

</BODY>
</HTML>

Some where in JAVA

@RequestMapping(value = "/getStateList.html", method = RequestMethod.POST)
public @ResponseBody
String getSuperVisorList(@RequestParam("countryId") String countryId) throws Exception {

StringBuffer select = new StringBuffer("<select>");
select.append("<option value=''> </option>");
for (int i =0; i<10; i++) {
select.append("<option value='"
+ i
+ "'>" + "youValues" + "</option>");
}
select.append("</select>");
return select.toString();
}

JQGrid: How can I refresh a dropdown after edit?

I think it will be better if you would use dataUrl property of the editoptions instead of usage value property. In the case you will don't need to use synchronous Ajax call inside of onSelectRow to get the select data manually. If the data will be needed the corresponding call will do jqGrid for you.

The URL from dataUrl should return HTML fragment for <select> element including all <options>. So you can convert any other response from dataUrl to the required format implementing the corresponding buildSelect callback function.

On your place I would prefer to return JSON data from the 'MyWebService.asmx/GetOwners' URL instead of XML data which you currently do. In the simplest case it could be web method like

[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public List<string> GetSelectData() {
return new List<string> {
"User1", "User2", "User3", "User4"
};
}

If you would use HTTP GET instead of HTTP POST you should prevent usage of data from the cache by setting Cache-Control: private, max-age=0 in the HTTP header. the corresponding code will be

[WebMethod]
[ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
public List<string> GetSelectData() {
HttpContext.Current.Response.Cache.SetMaxAge (new TimeSpan(0));
return new List<string> {
"User1", "User2", "User3", "User4"
};
}

Per default jqGrid use dataType: "html" in the corresponding Ajax call (see the source code). To change the behavior to dataType: "json", contentType: "application/json" you should use additionally the ajaxSelectOptions parameter of jqGrid as

ajaxSelectOptions: { contentType: "application/json", dataType: 'json' },

or as

ajaxSelectOptions: {
contentType: "application/json",
dataType: 'json',
type: "POST"
},

if you will use HTTP POST which is default for ASMX web services.

The corresponding setting for the column in the colModel will be

edittype: 'select', editable: true,
editoptions: {
dataUrl: '/MyWebService.asmx/GetSelectData',
buildSelect: buildSelectFromJson
}

where

var buildSelectFromJson = function (data) {
var html = '<select>', d = data.d, length = d.length, i = 0, item;
for (; i < length; i++) {
item = d[i];
html += '<option value=' + item + '>' + item + '</option>';
}
html += '</select>';
return html;
};

Be careful that the above code use data.d which is required in case of ASMX web services. If you would migrate to ASP.NET MVC or to WCF you will need remove the usage of d property and use data directly.

UPDATED: Here you can download the VS2010 demo project which implements what I wrote above.



Related Topics



Leave a reply



Submit