asp.net jqGrid dropdown multiselect - c#-4.0

i'm trying to use jQuery multiselect plugin in a form editing jqGrid (add form).
This is the code (colModel extract) I'm using to build the dropdown:
{
name: 'CaratteristicheCamera',
index: 'CaratteristicheCamera',
width: 50,
hidden: true,
edittype: 'select',
editable: true,
editrules: { edithidden: true, required: true },
editoptions: {
multiselect: true,
dataUrl: '<%# ResolveUrl("~/Service/Domain/ServiceRoom.asmx/GetRoomFeatureList") %>',
buildSelect: function (data) {
var retValue = $.parseJSON(data);
var response = $.parseJSON(retValue.d);
var s = '<select id="CaratteristicheCamera" name="CaratteristicheCamera">';
if (response && response.length) {
for (var i = 0, l = response.length; i < l; i++) {
s += '<option value="' + response[i]["Id"] + '">' +
response[i]["Descrizione"] + '</option>';
}
}
return s + "</select>";
},
dataInit: function() {
$("#CaratteristicheCamera").multiselect();
}
}
},
As you guys can see, jqGrid call webmethod placed in asmx file. Everything seems to work ok, but I can't receive all the values user select from the dropdown. It seems that the system send to the server the last selection.
Do u have any tips on it?
EDIT: this is the asmx webservice declaration
[WebMethod]
public string SaveRoom(string id, string codice, string Numero, string NumeroPiano,
string Nome, string TipoCamera, string StatoCamera,
string CaratteristicheCamera, string TipoSdoppiabilita)
{}

I tried Eric Hynds jQuery UI MultiSelect Widget together with jqGrid 3.4.1 and couldn't see any problem which you described. I recommend you compare your demo with my to find the differences.
One bad thing which I see in your code is that you set id="CaratteristicheCamera" attribute on the <select> which you generate in buildSelect. You should just use <select> without any additional attributes. The jqGrid will set itself all attributes like id or multiple="multiple".
In the demo I used editurl: 'test.asmx/dummy' which not exist on the server. So one sees the error message like
after choosing and submitting the selected items
Nevertheless one can see with respect of tools like Fiddler, Firebug or Developer Tools of IE or Chrome (see HTTP traffic in "Network" tab) that the demo post the data like
{"name":"test8","closed":"No","ship_via":"FE,TN","oper":"edit","id":"8"}
to the http://www.ok-soft-gmbh.com/jqGrid/test.asmx/dummy. So the values "FE,TN" of selected items FedEx, TNT will be send as expected. In your case the CaratteristicheCamera parameter of SaveRoom should be initialized to the comma separated list of selected values. I hope you will find the problem in your code if you compare my demo with youth.
Another small problem in the code which you posted is that you make serialization to JSON manually in the WebMethod GetRoomFeatureList and returns string. So the string will be serialized to JSON twice. So you use
var retValue = $.parseJSON(data);
var response = $.parseJSON(retValue.d);
Correct will be to return something like List<Room>. ASP.NET will serialize it automatically. If you would use the jqGrid option
ajaxSelectOptions: {
contentType: 'application/json; charset=utf-8',
dataType: "json"
}
the data in buildSelect will be not needed to parsed at all. You can directly use data.d[i].Id and data.d[i].Descrizione in the loop. I wrone you about the same problem in another answer on your old question.

Related

How to clear tabulator persistence data?

I have movable columns, hideable columns etc in my tabulator application. I would like a button to reset the view but I don't see anything that clears the persistence data in the documentation.
I'm very new to Tabulator but I have just recently done something similar. I wanted to reset col widths and positions.
The general idea is: In my grid setup code I have a function called getGridColumns. This gets the initial column definitions which then get added into the grid options that get passed to the new Tabulator(...) call.
ie something like
const options = {
data: this.data,
columns: getGridColumns(),
// ...other options
};
this.table = new Tabulator("#myGridId", options);
I have a header menu on one of the columns:
function getGridColumns() {
return [
{
title: "",
field: "dummy",
width: 80,
resizable: false,
// etc...
headerMenu: specialTableFuncsMenu,
},
{ title: "Col 1", field: "myField", /* etc */ },
];
}
and the header menu has a call to set the column layout using the getGridColumns function as parameter.
function specialTableFuncsMenu(e, col) {
const menu = [
{
label: "Reset columns",
action: col.getTable().setColumnLayout(getGridColumns()),
},
];
return menu;
}
The original is in Typescript so this might not be entirely accurate Javascript. And I have wrapped the action call in a setTimeout() just to prevent a console error when the grid tries to close the popup after it has redrawn itself.
I did, originally, clear the persistent storage too but removed the code as I don't think it's really needed. Something like:
localStorage.removeItem('tabulator-myGridId-columns');
Which assumes we're using localStorage and ignores the cookie option.
This all does an acceptable job of resetting my column layout. You could add in calls to clear filters etc as required.

jquery jtable deleteConfirmation function not working

I am trying to use the deleteConfimation function option but I find that the default confirmation box pops up before I even get into the deleteConfimation function - what am I missing?
In the code below I can set break points and watch the data object being set up correctly with its new defaultConfirmMessage, but the basic jtable default delete confirmation box has already appeared and I never see an altered one.
$(container).jtable({
title: tablename,
paging: true,
pageSize: 100,
sorting: true,
defaultSorting: sortvar + ' ASC',
selecting: false,
deleteConfirmation: function(data) {
var defaultMessage = 'This record will be deleted - along with all its assignments!<br>Are you sure?';
if(data.record.Item) { // deleting an item
// Check whether item is in any preset lists
var url = 'CampingTablesData.php?action=CheckPresets&Table=items';
$.when(
ReturnAjax(url, {'ID':data.record.ID}, MyError)
).done(
function(retdata, status) {
if(status=='success') {
if(retdata.PresetList) {
data.deleteConfirmMessage = 'Item is in the following lists: ' + retdata.PresetList + 'Do you still want to delete it?';
}
} else {
data.cancel = true;
data.cancelMessage = retdata.Message;
}
}
);
} else {
data.deleteConfirmMessage = defaultMessage;
}
},
messages: {
addNewRecord: 'Add new',
deleteText: deleteTxt
},
actions: {
listAction: function(postData, jtParams) {
<list action code>
},
createAction: function(postData) {
<create action code>
},
updateAction: 'CampingTablesData.php?action=update&Table=' + tablename,
deleteAction: 'CampingTablesData.php?action=delete&Table=' + tablename
},
fields: tableFields --- preset variable
});
==========
After further testing the problem is only when deleting an item and it goes through the $.when().done() section of code. The Ajax call to the deletion url does not wait for this to complete - how do I overcome this?
i don't think you can get your design to work. What does the A in ajax stand for? Asynchronous! Synchronous Ajax has been deprecated for all sorts of good design and performance reasons.
You need to design you application to function asynchronously. Looking at your code, it feels you are misusing the deleteConfirmation event.
Consider changing the default deleteConfirmation message to inform the user, that the delete might not succeed if certain condition are met. Say
messages: {
deleteConfirmation: "This record will be deleted - along with all its assignments, unless in a preset list. Do you wish to try to delete this record?"
},
Then on the server, check the preset lists, and if not deletable, return an error message for jTable to display.
Depending on how dynamic your preset lists are, another approach might be to let the list function return an additional flag or code indicating which, if any, preset lists the item is already in, then your confirmation function can check this flag / indicator without further access to the server.
Thanks to MisterP for his observation and suggestions. I also considered his last approach but ended up setting deleteConfirmation to false (so as not to generate a system prompt) then writing a delete function that did not actually delete, but returned the information I needed to construct my own deleteConfimation message. Then a simple if confirm(myMessage) go ahead and delete with another Ajax call.

Dynamically refresh a div without a straightful DOM manipulation

I have to update for example a table, a list if some values. I can insert new values and try to reload a entire page to show table or list values again.
If I give a try on Ajax updates I have to manipulate DOM, creating a bunch of new tags, concatenate and inject the new HTML on old one. This not a painful way, you even must re-type the code created before to exhibit new entries.
E.g: this is a fictitious example and illustrates what I mean:
$.ajax({
url: '/post/addComment/',
type: 'POST',
data: 'comment=' + comment,
beforeSend : function() {
//waiting message
$('#some_information_div').html('<strong>Updating...</strong>');
}
}).done(function(data) {
//new data comes here (by JSON, plain text, whatever...)
if (data.status == 'OK') {
//OHHH MAN WE HAVE TO POPULATE MANUALLY IT AGAIN
var c = '';
c = '<table>'
data.content.forEach(function(e) {
c += '<tr><td>' + e.name + '</td></tr>';
});
c += '</table>'
//update with new values
$('#some_information_div').html('');
$('#destination_table').html(c);
}
});
Unfortunately I have to do all the time with my lists and tables and somehow I have to re-type codes and manipulate it all by the javascript. I figured out something might be useful like does jQuery.load(), maybe it can fit what I want to, I have not tried it.
Some other languages and frameworks like JSF do it easily with "render technique", you directly update content without have to create and manipulate DOM in manually way.
Please, any kind of suggestion, any clue to this approach will be very helpful.
P.S.: The code sample tag doesn't work well here.
This can be done by using .load() jquery function. I have illustrated for some page 1.php and some table having id mytable
$('table#mytable').load('./1.php #mytable');
for constant refreshing --
setInterval(function() {
$('tablev#mytable').load('./1.php #mytable');
}, 5000);

Add a MediaPicker to the General Site Settings

The current project I'm on is utilizing tenant sites. With each site, we want the ability to change the logo through out the tenant site by modifying the its settings (on the admin page, settings > general).
I've added two text fields to the site settings by following this well documented tutorial. However, I'd like the user to be able to pick the logos using the media picker instead of typing in the path.
Currently I have a LogoBarSettings part with its record, driver and handler. I'm not sure how to add the media picker to the my LogoBarSettings and even if I did, must I also create another handler, driver, and record for it? I can't imagine I would but I'm pretty stuck at this point.
Can someone provide some direction on this?
Here is my LogoBarSettings
public class LogoBarSettings : ContentPart<LogoBarSettingsPartRecord>
{
public string ImageUrl
{
get { return Record.ImageUrl; }
set { Record.ImageUrl = value; }
}
public string ImageAltText
{
get { return Record.ImageAltText; }
set { Record.ImageAltText = value; }
}
}
The MediaPicker is invoked through Javascript, so you shouldn't need to change any of your model classes. When the MediaPicker is loaded for a page, it sets up a jQuery event handler for all form elements on the page. Triggering the event orchard-admin-pickimage-open will open the MediaPicker. Supply a callback function to capture the picked media.
Here is a quick example that you can run in Firebug or Chrome Developer Tools from a page which has the MediaPicker loaded, such as a Page editor:
$('form').trigger("orchard-admin-pickimage-open", {
callback: function(data) {
console.log(data);
}})
This should print something similar to this:
Object {img: Object}
img: Object
align: ""
alt: ""
class: ""
height: "64"
html: "<img src="/Media/Default/images/test.jpg" alt="" width="64" height="64"/>"
src: "/Media/Default/images/test.jpg"
style: ""
width: "64"
__proto__: Object
__proto__: Object
The BodyPart editor integrates Orchard's MediaPicker with TinyMce, so you can start looking at that module for a more complete example, specifically Modules\TinyMce\Scripts\plugins\mediapicker\editor_plugin_src.js.

Subclass QueryReadStore or ItemFileWriteStore to include write api and server side paging and sorting.

I am using Struts 2 and want to include an editable server side paging and sorting grid.
I need to sublclass the QueryReadStore to implement the write and notification APIs. I do not want to inlcude server side REST services so i do not want to use JsonRest store. Any idea how this can be done.? What methods do i have to override and exactly how. I have gone through many examples but i am not getting how this can be done exactly.
Also is it possible to just extend the ItemFileWriteStore and just override its methods to include server side pagination? If so then which methods do i need to override. Can i get an example about how this can be done?
Answer is ofc yes :)
But do you really need to subclass ItemFileWriteStore, does it not fit your needs? A short explaination of the .save() follows.
Clientside does modify / new / delete in the store and in turn those items are marked as dirty. While having dirty items, the store will keep references to those in a has, like so:
store._pending = { _deletedItems: [], _modifiedItems: [], _newItems: [] };
On call save() each of these should be looped, sending requests to server BUT, this does not happen if neither _saveEverything or _saveCustom is defined. WriteStore simply resets its client-side revert feature and saves in client-memory.
See source search "save: function"
Here is my implementation of a simple writeAPI, must be modified to use without its inbuilt validation:
OoCmS._storeAPI
In short, follow this boiler, given that you would have a CRUD pattern on server:
new ItemFileWriteStore( {
url: 'path/to/c**R**ud',
_saveCustom: function() {
for(var i in this._pending._newItems) if(this._pending._deletedItems.hasOwnProperty(i)) {
item = this._getItemByIdentity(i);
dxhr.post({ url: 'path/to/**C**rud', contents: { id:i }});
}
for(i in this._pending._modifiedItems) if(this._pending._deletedItems.hasOwnProperty(i)) {
item = this._getItemByIdentity(i);
dxhr.post({ url: 'path/to/cr**U**d', contents: { id:i }});
}
for(i in this._pending._deletedItems) if(this._pending._deletedItems.hasOwnProperty(i)) {
item = this._getItemByIdentity(i);
dxhr.post({ url: 'path/to/cru**D**', contents: { id:i }});
}
});
Now; as for paging, ItemFileWriteStore has the pagination in it from its superclass mixins.. You just need to call it with two setups, one being directly on store meaning server should only return a subset - or on a model with query capeabilities where server returns a full set.
var pageSize = 5, // lets say 5 items pr request
currentPage = 2; // note, starting on second page (with *one* being offset)
store.fetch({
onComplete: function(itemsReceived) { },
query: { foo: 'bar*' }, // optional filtering, server gets json urlencoded
count: pageSize, // server gets &count=pageSize
start: currentPage*pageSize-pageSize // server gets &start=offsetCalculation
});
quod erat demonstrandum

Resources