I use the DataTables Editor plugin (https://editor.datatables.net/) for editing a table with remote data (https://datatables.net/examples/data_sources/server_side.html) in inline mode (https://editor.datatables.net/examples/inline-editing/simple.html)
After some field is edited, submitted and a response from the editor's server handler is returned, the table always completely reloads sending an extra AJAX request to the server even though there's no need to do that since only one field in only one row was changed and all the data required to redraw the table row have already been received in the previous inline edit response.
So the question is whether it's possible to get rid of the extra AJAX call and redraw the edited row only, rather than completely refreshing the whole table.
The piece of code responsible for the reloading is:
// dataTables.editor.js
Editor.prototype._submit = function ( successCallback, errorCallback, formatdata, hide )
{
...
// Submit to the server (or whatever method is defined in the settings)
this._ajax(
submitParams,
function (json) {
...
// the following line forces the table to completely reload
that._dataSource( 'commit', action, modifier, json.data, store );
...
}
)
...
}
Here is an answer from Datatables Forum:
Yes, you can set the drawType option to none in the form-options object (e.g. the second, optional, parameter passed into inline(). That will stop DataTables from doing a redraw (in the case of server-side processing that involves the Ajax request). It does mean that any sorting or filtering changes caused by the change in data won't be immediately shown though.
Allan
try with stateSave: true
https://datatables.net/reference/option/stateSave
$(document).ready(function() {
var table = $('#table_name').DataTable(
{
columnDefs: [{
orderable: false,
targets: [0, 1, 8, 9]
}],
,
stateSave: true,
"lengthMenu": [[10, 50, 100, 500, -1], [10, 50, 100, 500, "all"]]
}
)
});
Related
I'm creating a rates per hour form. I have all the categories in my database rates table. I'd like to be able to grow the categories and it will automatically grow the fields on my form.. loop through it all.
The user needs to select a begin to end rate. I start at this rate and end at this rate.
So right now I have these values in json being loaded onto my page:
rateCategories: [ { "name": "Local", "input1": "Local$0", "input2":
"Local$1" }, { "name": "International", "input1": "International$0",
"input2": "International$1" }, { "name": "Weekdays", "input1":
"Weekdays$0", "input2": "Weekdays$1" }, { "name": "Weekends",
"input1": "Weekends$0", "input2": "Weekends$1" } ]
userRates: { "Local$0": 10, "Local$1": 25, "International$0": 300,
"International$1": 400, "Weekdays$0": 100, "Weekdays$1": 200,
"Weekends$0": 200, "Weekends$1": 300 }
What I'm doing is looping through rateCategories array to create the form. I need to dynamically create the v-model name for all the input fields to match the keys in userRates...
This is where it stops working! It will create the v-model name for me if I write:
:v-model.number="'userRates.'+rateCategories.name+'$0'"
but it won't compute it with the value from the user array. I do get a value into an input field if I write out the v-model name without creating it dynamically like this:
v-model.number="userRates.Weekdays$0"
but then the form needs to be manually updated every time a new category is added.
Is it really impossible to have a dynamic v-model name?? Why??
Also if that's so, how do I go about this so the page can loop through the categories when added to the database and not need a manual update to the page when categories are added or taken away??
Note: I'm also using Vuex store, so I'd rather it not break anything with my getter and setter functions too
Vue.js has full javascript expression support in data bindings, so an object's property can be accessed like you would in plain javascript.
Have you tried using userRates[rateCategories.name$0] ?
Using Javascript Expressions in Vue.js
I was trying to asynchronously update a Select field via Memory and ObjectStore. This doesn't work. Setting the data to the Memory object before creating the Select element works fine. Updating the Memory object after creating the Select element doesn't work anymore.
Example code:
require([
"dojo/ready",
"dijit/form/Select",
"dojo/store/Memory",
"dojo/store/Observable",
"dojo/data/ObjectStore",
'dojo/domReady!'
], function(ready, Select, Memory, Observable, ObjectStore, dom){
ready(function() {
var mymem = new Memory();
var myobs = new Observable(mymem);
var mystore = new ObjectStore({ objectStore: myobs });
/* updating memory here works :) */
//mymem.setData([ { id: 2, label: 'qwertz2' }, { id: 3, label: 'qwertz3' } ]);
var s = new Select({
store: mystore
}, 'appsAdminQueueContainer');
s.startup();
/* updating memory here doesn't work :( */
mymem.setData([ { id: 2, label: 'qwertz2' }, { id: 3, label: 'qwertz3' } ]);
});
}
);
Real working example: https://jsfiddle.net/mirQ/ra0dqb63/5/
Is this a bug or is there a solution to be able to update the content of the Select field after creating it - without having to access the Select field directly?
UPDATE
Thank you for your response.
The use of dojo/ready was just a missed leftover while simplifying my code, sorry.
That the use of the ObjectStore is not necessary was not clear to me. Thanks for clearing up.
Okay, the real problem seems to be indeed the last point. I think I have to extend my description.
Updated/extended problem description:
I'm using a grid. At first I was using dojox/grid/DataGrid, but then I switched to dgrid. Everything works well, but I want to use dijit.form.Select as editor for one column. This works also well if the data is static. But in one column I have to read dynamic data from the server. This data comes in JSON format.
First I tried to solve this with the use of dojo/data/ItemFileReadStore - that worked. But it's deprecated and I need to implement a formatter for that column that has to have access to the same JSON data read from the server. I don't have the code for that solution anymore, but it didn't work. I wasn't able to successfully query the data from within the formatter function.
Then I switched to Memory and xhr. The response from the server comes after the Memory object is created (and, as it seems, after creating the Select), so I had to use setData to bring my loaded data in the store. And because the Select is only an editor of a grid, I don't have access to the object itself to be able to re-set the store after updating the data.
I hope my extended description makes my real problem a bit clearer. Thanks in advance for your help!
Mirko
This works for me:
require([
'dijit/form/Select',
'dojo/store/Memory',
'dojo/store/Observable',
], function (Select, Memory, Observable) {
var mymem = new Memory({
data: [{
id: 2,
label: 'qwertz2'
}, {
id: 3,
label: 'qwertz3'
}]
});
var myobs = new Observable(mymem);
var s = new Select({
labelAttr: 'label',
store: myobs
}, 'appsAdminQueueContainer');
s.startup();
myobs.add({ id: 4, label: 'qwerty' });
});
Notable changes:
There's no reason to use dojo/ready in this code. The require callback already waits for modules to load, and as long as this script is at the bottom of the body, there's no need to wait for the DOM to load, either.
There's no need to use a dojo/data store adapter. dijit/form/Select supports dojo/store as well (as of 1.8 if I recall correctly). This might also have been why observation wasn't working. The only difference is labelAttr must be specified on the Select since dojo/store has no concept of a label property.
(Edit) now that I re-read the question, I notice you are calling setData. setData does not fire observers. setData completely resets the store's data, and to reflect that, you would need to actually reset the store on the select entirely (which requires calling setStore, not set('store', ...), if you are using 1.9 or earlier, because Select was never updated properly to support the set API until 1.10).
(Edit #2) Given that the primary reason you are calling setData is due to creating the store before actually having data for it, your case would probably be greatly simplified by using the RequestMemory store implementation from dojo-smore. It basically re-adds the url support that dojo/data/ItemFileReadStore had but dojo/store/Memory didn't.
I am using jQrid version 3.8.1 with inline editing and each row in the grid has several dropdown lists to populate. When the user edits the row, I need to do an AJAX query to get the values for each of these lists. I've seen this post regarding how to do that. It appears that the dataUrl and buildSelect features are the standard answer here. There are a few issues I can't figure out though:
The row the user is editing has a value that must be passed into the dataUrl value. For example, say each row contains a field called "SpecialValue" and that for row 1, SpecialValue = 100. The dataUrl field for row 1 would be "http://my.services.com?SpecialValue=100". How do I do that?
Each row in the grid has about 10 select boxes that need to be populated. For efficiency reasons, I don't want to make 10 separate AJAX calls. It would be much better to make one call to get all the data, split it up, and fill each select box accordingly. Is that possible? I tried doing this inside onSelectRow but the grid ended up ignoring the values I put in there (I'm guessing do the ordering of the events that fire when you edit a row).
Edit:
After reading Oleg's answers and working on it more, it's clear to me that using dataUrl and buildSelect are not going to work well for me. The version of jqGrid I'm using doesn't support using dataUrl the way I would need. And even if it did I don't want to send multiple separate requests for each dropdown list.
I've decided to do one request when gridComplete fires to pull all the data needed for all dropdown lists into a single JSON structure. Then when the user selects a row to do inline editing, I will populate each list in the row from that JSON structure (the code below uses the getSelectValuesFromJSON() function for that--I don't give its definition but you can imaging it looks through the structure and gets an appropriate list of values to but in the list box).
I have a few candidate solutions but I'm not 100% happy with either one.
Solution 1:
Inside onSelectRow, I call editRow overriding the on oneditfunc to get the data out of the grid that I need. Assume that the value in Field1 is required to get the values to be put into the list in Field2.
onSelectRow: function (index, status, e) {
jQuery('#my_grid').jqGrid('editRow', index, true, function(rowId) {
var f1Val = $('#my_grid').jqGrid('getCell', index, 'Field1');
var selectVals = getSelectValuesFromJSON(f1Val); //gets data out of previously loaded JSON structure
var select = $('#my_grid').find('tr[id="' + index + '"] td[aria-describedby="my_grid_Field2"] select');
_.each(selectVals, function(selectVal) {
$(select).append($("<option></option>").attr("value", selectVal).text(selectVal));
});
});
}
This works but I'm hesitant about the line
var select = $('#my_grid').find('tr[id="' + index + '"] td[aria-describedby="my_grid_Field2"] select');
which relies on this aria-describedby attribute that I don't know much about. Seems hacky and brittle.
Solution 2:
Make use of beforeSelectRow to dynamically change the model of the Field2 column when the user selects a row.
beforeSelectRow: function(index, e) {
var f1Val = getGridCellValue('#my_grid', index, 'Field1');
var values = getSelectValuesFromJSON(f1Val); //gets data out of previously loaded JSON structure
var valStr = "";
_.each(values, function(value) {
valStr += value + ":" + value + ";"
});
jQuery('#grid_pipes').setColProp('Field2', { editoptions: { value: valStr } });
return true;
}
This also works but I'm not sure about whether or not this is really a good idea. Is it valid to dynamically change the model of a column like that? What if the user has several rows selected at the same time? Isn't there only one model for a column? What would that mean?
To answer some of Oleg's questions, the dataType has been set to a function that uses $.ajax to post data to the server. I think I read that's not the recommended approach anymore. I inherited this code so I'm not sure why it was done that way but it probably won't change unless there is a really compelling reason.
The loadonce boolean is not specified so I guess that means it defaults to false.
Here is an abbreviated version of the column model (nothing terribly out of the ordinary):
colModel: [
{ name: 'PK', index: 'PK', hidden: true, editable: true, sortable: true, search: true },
{ name: 'Field1', index: 'Field1', hidden: true, editable: true, sortable: true, search: true },
{ name: 'Field2', index: 'Field2', sortable: false, editable: true, search: false, edittype: "select", editoptions: {} },
{ name: 'Field3', index: 'Field3', sortable: false, editable: true, search: false, edittype: "select", editoptions: {} },
...
]
You don't wrote which version of jqGrid you use currently, but dataUrl can be defined as callback function with (rowid, value, name) parameters, which have to return the URL which you can build dynamically based on the information. The feature exist starting with v4.5.3 (see the line). You can use getCell, getRowData or getLocalRow inside of the callback to get the data from another columns of the row. Thus you can solve your first problem relatively easy.
You second question seems to me absolutely independent from the first one. It's better to separate such questions in different posts to allow the searching engine better to index the information and so to help other people to find it.
There are no simple way how to solve the second problem, but one can sure suggest a solution, but one have to know much more details what you do and how you do. How you start inline editing (do you use inlineNav, formatter: "actions" or you call editRow directly)? Which version of jqGrid (till version 4.7), free jqGrid or Guriddo jqGrid JS you use? How the columns with selects are defined in colModel? Which datatype you use and whether loadonce: true you use? I recommend you to post separate question with the information.
UPDATE: If you have to use old version of jqGrid then you can't generate dataUrl full dynamically, but because you need to add only SpecialValue=100" part to the URL you can follow the trick which I described in many my old answers (the first one was probably here, but the choice on property names which asked the user could be misunderstood). You can use ajaxSelectOptions.data which will define the data parameters of jQuery.ajax request. The problem only that you can define only one ajaxSelectOptions.data property. So you can add the following jqGrid option:
ajaxSelectOptions: {
data: {
SpecialValue: function () {
var rowid = $myGrid.jqGrid("getGridParam", "selrow");
return $myGrid.jqGrid("getCell", rowid, "SpecialValue");
}
}
}
($myGrid is something like $("#grid"))
UPDATED: You used unknown functions getSelectValuesFromJSON, getLookupValuesFromJSON in the updated part of your question. Both of there seems to use synchronous Ajax request which is not good. Moreover you set editoptions.value for only one Field2 instead of setting all selects.
onSelectRow: function (rowid) {
var $myGrid = $(this);
$.ajax({
url: "someUrl",
dataType: "json";
data: {
specialValue: $myGrid.jqGrid("getCell", rowid, "Field1")
},
success: function (data) {
// for example response data have format:
// { "Field2": ["v1", "v2", ...], "Field3": ["v3", "v4", ...] }
var filed, str;
for (filed in data) {
if (data.hasOwnProperty(filed)) {
str = $.map(data[filed], function (item) {
return item + ":" + item
}).join(";");
$myGrid.jqGrid("setColProp", filed, {
editoptions: {
value: str
}
});
}
}
$myGrid.jqGrid("editRow", rowid, true);
}
});
}
Nevertheless the "Solution 2" is more close to what I would recommend you. It's not really important whether to use onSelectRow or beforeSelectRow. You can make asynchronous Ajax request to the server which returns information for all select which you need. After you get the response from the server (inside of success callback) you can set editoptions.value for all selects and only then you can start editRow. In the way you will be sure that editing of the line will use row specific options in all select.
Some additional remarks. I recommend you to verify gridview: true option in the grid. Additionally I suspect that you fill the grid in not full correct way because you have hidden PK column and you use index instead of rowid as the first parameter of beforeSelectRow and onSelectRow. It's very important to understand that the current implementation of jqGrid always assign id attribute on every row (<tr> element) of the grid. So you have to provide id information in every item of input data. If you want to display the id information to the user (and so to have column in colModel with the primary key) then you should just include key: true property in the column definition. For example you can add key: true to the definition of PK column and so you will have rowid (or index in your case) with the same value like PK. It simplify many parts of code. For example jqGrid send id parameter in the editing request to the server. It's practical to have PK in the request. Moreover if you use repeatitems: false format of jsonReader the you can include id: "PK" in the jsonReader instead of having hidden PK column. It informs jqGrid to get rowid from PK. jqGrid will save PK in id attribute of <tr> and you will don't need to have additional <td style="display:none"> with the same information in the grid.
The last remark. I would strictly recommend you to update the retro version jqGrid 3.8.1 to some more recent version, for example to free jqGrid. Even if you would use no features (like Font Awesome for example) you will have performance advantages, and the look of modern web browsers will looks much better. You should understand the jqGrid 3.8.1 was tested with old (and slow jQuery 1.4.2). The version used with Internet Explorer 8 as the latest IE version (IE9 was published later in March 2011) and it's more oriented on IE6/IE7. The look in modern Chrome/Firefox/Safari can be bad. Is it what you want?
I am using dgrid as follows:
query_grid: function(json_query, target, select){
var self = this;
require(["dojo/_base/declare",
"dgrid/Grid",
"dgrid/extensions/ColumnResizer",
"dgrid/Selection",
"dgrid/selector",
"dgrid/extensions/DijitRegistry",
"dgrid/extensions/Pagination"],
function(declare, Grid, ColumnResizer, Selection, selector, DijitRegistry, Pagination){
util.destroy("grid_"+json_query.path);
var columns = {};
if (select){
columns.widget = selector({
id: "widget",
label: " ",
selectorType: "radio",
resizeable: false,
width: 30});
}
var data = json_query.data;
for (var i=0; i<data.keys.length; i++){
columns[data.keys[i]] = {label: util.slice_path(data.keys[i], 2)};
}
var grid = new (declare([Grid, ColumnResizer, Selection, DijitRegistry, Pagination]))({
id: "grid_"+json_query.path,
columns: columns,
store: new Memory({data: data.records}),
selectionMode: select?"single":"none",
pagingLinks: 1,
pagingTextBox: true,
firstLastArrows: true
});
dojo.place(grid.domNode, target, 'last');
grid.refresh();
}
);
return json_query.path;
}
but when i look at the result, it always shows one record less then is present, until i click on a column header (resulting in a sort), and then all records are shown. Can anyone expain or help with a solution/workaround?
Replace grid.refresh() with grid.startup().
dgrid will automatically call startup in cases where an instance is in document flow as soon as it's created. That's not the case here since you're placing it afterwards, so you need to call startup after it's in flow to tell it that it can perform geometry-sensitive operations.
Without calling startup, resize is never initially called. As a result, the grid doesn't properly account for the height of the header/footer, and one of your 10 rows is getting obfuscated. It gets fixed when you sort because dgrid/Grid's _setSort method calls resize in case the size of the header row changes due to the placement of the sort arrow.
The reason you can replace refresh with startup in this case is because startup calls refresh anyway.
I am looking for inline editing a JQGrid.
My JQGrid having column like :
colModel: [
{ name: 'Model_ID', index: 'model_id', width: 100, editable: false, hidden:
false },
{ name: 'Cust_Nm', index: 'cust_nm', width: 100, editable: false},
{ name: 'Model_Nm', index: 'model_nm', width: 140, editable: false, },
{ name: 'Client_Nm1', index: 'client_nm1', width: 120, editable: true},
{ name: 'Client_Nm2', index: 'client_nm2', width: 120, editable: true},
{ name: 'Client_Nm3', index: 'client_nm3', width: 120, editable: true},
{ name: 'Date', index: 'regi_date', width: 130, editable:false, search: false }
],
cellEdit: true,
cellurl: '#Url.Action("UpdateJQGrid", "Config")',
cellsubmit: "remote"
I want to pass value of 'Model_ID' to "UpdateJQGrid" Controller method. UpdateJQGrid is getting called when I edit one cell and move the focus to other cell inside the jggrid. I have created a View Model and passing that ViewModel to the Controller Method. But I am getting only the edited value through ViewModel object not other values of the selected row. If I can get only the value of Model_ID in Controller method my requirement will be solved.
Any help or hint is much appreciated.
It's very important to understand that the implementation of jqGrid require to assign id attribute to every row of the grid (to every <tr> element of the <table> with the main data). The documentation use rowid as the value of id attribute. If you use editing feature of jqGrid it's strictly recommended that you assign the value of id attribute based on the native value which will be get from the database (existing on the backend side). The rowid will be used in the most callbacks of jqGrid and will be post to the server during editing. Here you can read which information will be send to the server during cell editing.
If the values from Model_ID (or model_id) column are unique and the values come from the database than I would recommend you to use the value as the rowid. To inform jqGrid to use the value you can either specify the corresponding value of id property of jsonReader (or xmlReader). The value of id property depends on the exact format of the data returned from the server, which you use to fill the grid. Another way will be to specify key: true property in Model_ID (model_id) column. After the changes you will see that jqGrid will send the value from Model_ID (model_id) column to the server during cell editing. The value will be send as id=rowid (as id parameter). You can change the name of the parameter by usage prmNames: {id: "Model_ID"}, for example, which changes id=rowid to Model_ID=rowid.
One more remark. I recommend you don't use index property if it is not really required. If you miss the property then the value of name property will be used instead. The usage of different values for name and index properties is the origin of many errors and makes impossible to use client side sorting, paging and filtering/searching.