jQuery datatables customizable columns (asp.net usercontrol) - asp.net

net webforms application.
In my .aspx page Im using jQuery datatables and its gets data using ajax.
In my jQuery datatables I have some configuration for setting up my columns:
'columnDefs': [{
'targets': 0,
'searchable': false,
'orderable': false,
'className': 'dt-body-center',
'render': function(data, type, full, meta) {
//return '<input type="checkbox">';
if (data == "false") {
return '<input type="checkbox" class="styled green">';
} else {
return '<input type="checkbox" class="styled green" checked="' + data + '">';
}
}
}],
I have a requirement to move this jQuery datatable to an usercontrol so it can be reusable on other parts of the web application but I should be able to let the control know what columns to hide.
I was thinking on sending from server other property in my json, an array maybe named HideCols that has the index of the columns that I want to hide and then apply with jQuery some code to hide them.
Im getting the table data like this:
"fnServerData": function(sSource, aoData, fnCallback) {
aoData.push(
{ name: "filter", value: filterVal }
);
$.ajax({
"dataType": 'json',
"contentType": "application/json; charset=utf-8",
"type": "GET",
"url": sSource,
"data": aoData,
"success": function(msg) {
// here I get my json table data from server
var json = jQuery.parseJSON(msg.d);
fnCallback(json);
// here I can do my jQuery code to hide columns
if(json.HideCols != null)
{
}
}
});
}
Other way would be great if I can send from server the columnDefs configuration but I guess its going to be more tricky.
Any clue?

I have implemented the dynamic columnDefs (colModel) functionality with jqGrid. You may read the post here jqgrid-dynamic-reading-of-colmodel-and-colnames-from-codebehind-of-aspx
You may get the basic idea of generating dynamic columnDefs (xxx_colModel in above post) and ajaxData (xxx_Data in above post) from code-behind and implement it in your way. Set properties of columns to hide in the dynamically generated columnDefs.
As regard to your approach of hiding the columns:
I was thinking on sending from server other property in my json, an array maybe named HideCols that has the index of the columns that I want to hide and then apply with jQuery some code to hide them.
You may add another property to top level of JSON along with xxx_colModel and xxx_Data say xxx_HiddenCols and store csv column IDs e.g. 2,8,9
Then on the client side, after the grid is initialized, you may use for loop to process each column to hide e.g.
var colArray = xxx_HiddenCols.split(',');
for (var i = 0; i < colArray.length; i++) {
table.column( colArray[i] ).visible( false );
}

Related

KendoUI Grid Custom Toolbar Action to delete selected items

I'm trying to add a new Custom Toolbar Action to my Kendo UI Grid but am lost on how to get the desired behaviour.
I need a button that I can click that will invoke an action method and pass in the collection of selected items in the grid so I can do a bulk delete (or some other action against all of the records)
Can anyone help ?
Currently I have: -
.ToolBar(toolbar =>
{
toolbar.Custom().Action("Users_DeleteSelected", "Users").Text("Delete Selected");
})
This invokes my method thus: -
public ActionResult Users_DeleteSelected([DataSourceRequest] DataSourceRequest request)
{
// We need the list of selected UI items *here* so we can delete them - but how
...???
// Just redirect for now, we need to test getting the list of selected items here...
RedirectToAction("Index");
}
So if I have several items "selected" in the grid, I somehow want to invoke a method like the one above (Users_DeleteSelected) and have it get passed in the list of items to delete, then redirect to the Index once the delete is complete.
** This may not just be linked to deleting - there may in future be several other functions that will be required that fit the same method - i.e. "Mark As Complete" on a list of jobs for example.
I'm guessing maybe the DataSourceRequest isn't the way to go and that maybe I need to add some client side code to somehow assemble the list of selected items.
KendoUI is great but I need more examples.
Thanks for your kind replies. We've figured it out with a bit of searching and the like.
Firstly "kudos" to "this post" on the kendoui site as it pointed me in the right direction.
It turns out that this is what we need: -
In the. cshtml file for the grid...
// .... Other grid stuff
.ToolBar(toolbar =>
{
toolbar.Custom().Text("Test Button").Url("#").HtmlAttributes(new { #class = "test-button" });
})
// And then also...
$(document).ready(function () {
$(".test-button").click(testFunction)
})
// And finally
function testFunction(e) {
kendoConsole.log("Items Selected");
e.preventDefault();
var grid = $("#Grid").data("kendoGrid");
var selection = [];
grid.select().each(
function () {
var dataItem = grid.dataItem($(this));
selection.push(dataItem);
}
);
$.ajax({
type: "POST",
url: "Users/Users_DeleteSelected",
data: JSON.stringify({ items: selection }),
dataType: "html",
contentType: "application/json; charset=utf-8",
success: function (form) {
document.open();
document.write(form);
document.close();
}
});
};
Then in the controller we simply have: -
[HttpPost]
public ActionResult Users_DeleteSelected(List<UserViewModel> items)
{
// Stub to redirect for now
return RedirectToAction("Index");
}
And that's it. All of the items currently selected in the grid will be posted back to the correct action method and the jobs done.
Thanks.
Sounds like you are looking for batch editing capability. Take a look at this Kendo batch editing example. You can control whether to batch or not on the DataSource.

How to call a serverside method using jquery?

I'm trying to call a server side method, using jquery, on the textchange event of a textbox which is generated dynamically on the clientside (I dont know how to fetch the id of this). Can somebody help me to do this stuff? The script im using is as follows:
<script type="text/javascript">
$(init);
function init() {
$('#test').droppable( //Div Control where i'll be dropping items
{
drop: handleDropEvent
});
$('a').each(function(idx, item) {
$(item).draggable({ cursor: 'move', helper: 'clone' })
});
}
function handleDropEvent(event, ui) {
var draggable = ui.draggable;
document.getElementById('test').innerHTML += addColumn(draggable.attr('text')) + '<br>';
}
$('.textChangeClass').live('change', function() {
/* Evokes on the text change event for the entire textboxes of class .textChangeClass. Is it possible to specify the dynamic textbox generated # clientside here? (like for e.g. : $('#mytextbox').click(function () ) */
$.ajax({
type: "POST",
url: "Webtop.aspx/ServerSideMethod", //This is not getting called at all.
data: "{'param1': AssignedToID}",
contentType: "application/json; charset=utf-8",
dataType: "json",
async: true,
cache: false,
success: function(msg) {
alert("From Server");
}
})
});
});
function addColumn(column) {
var iHtml;
//This is how i'm generating the textboxes along with a checkbox bound by a div.
iHtml = '<div id="dv' + column + '" width="100px;" height="20px;" padding: "0.5em;"> ' + '<span title="ToolTipText">' + '<input type="checkbox" id="cb' + column + '" value="' + column + '" /> <label for="cb' + column + '">' + column + '</label></span><input class="textChangeClass" type="text" id="aln' + column + '"> </div>';
return iHtml
}
</script>
I think you have an extra "});" although this probably isn't the problem.
What is "AssignedToID"? Try adding single quotes around that. I seem to remember having a weird problem a couple years ago related to quoting in the json.
Can you see the request in Fiddler/firebug/etc? Is the content correct?
You should be careful of your use of inferred semi-colons too. If you ever minify your javascript (yeah, I know this is embedded, but I'd like to hope that one day it will be moved to a seperate js file) you're eventually going to have a problem. Imagine some other developer comes along, does some refactoring and needs to add a return value after the ajax call.
$.ajax({...})return foo}
EDIT
Fiddler/Firebug Net panel are your friends... They will allow you to inspect the request and the response from the server. This way you don't have to add the error handler (although you may want to for other reasons eventually)
EDIT
To answer the other part of your question, you can access the textbox for which the change event was triggered through the use of the 'this' keyword inside of the event handler.
$('.textChangeClass').live('change', function(event) {
//Note that the 'event' parameter has interesting things in it too.
var changedText = $(this).val();
alert("The value in the textbox is: '" + changedText + "'");
var data = {
param1: changedText
};
$.ajax({
...
//Using json2 library here to create json string
data: JSON.stringify(data),
...
});
});
Note that I added the optional 'event' parameter to the event handler. It has interesting things in it and it's something that is often overlooked by people who are new to jQuery. Read about it here.
You need to write you code of adding the event to textbox after generation of textbox otherwise it's not get fire.
add text box
After that write code to add event to text box or bind event to text box
just follow the above step will do your work
EDIT
Add the error function to your ajax call you will get the error ... will allow you to proceed further
$.ajax({
type: "post", url: "/SomeController/SomeAction",
success: function (data, text) {
//...
},
error: function (request, status, error) {
alert(request.responseText);
}
});

YUI Data Table Issues / Questions

I am using the data table with my ASP.NET MVC 3 web application and so far it is going quite well. I connect to a SQL Server 2008 database, and I return data by using a stored procedure. I am using IE 8 and the latest version of Firefox. The version of YUI is 2.8.2r1. I have a couple of questions regarding the data table :)
Here is my data table's code:
<script type="text/javascript">
YAHOO.util.Event.onDOMReady(function () {
var grdNewsColumnDefs, grdNewsDataSource, grdNewsConfigs, grdNewsDataTable;
// News list data table
var formatActionLinks = function (oCell, oRecord, oColumn, oData) {
var newsId = oRecord.getData('NewsId');
oCell.innerHTML = 'Edit | ' +
'Details';
};
var formatActive = function (oCell, oRecord, oColumn, oData) {
if (oData) {
oCell.innerHTML = "Yes";
}
else {
oCell.innerHTML = "No";
}
};
grdNewsColumnDefs = [
{ key: 'Title', label: 'Title', className: 'align_left' },
{ key: 'Active', label: 'Active', className: 'align_left', formatter: formatActive },
{ key: 'Action', label: 'Actions', className: 'align_left', formatter: formatActionLinks }
];
grdNewsDataSource = YAHOO.util.DataSource('#Url.RouteUrl(Url.NewsJsonList())');
grdNewsDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
grdNewsDataSource.responseSchema = {
resultsList: 'DataResultSet',
fields: [
{ key: 'NewsId' },
{ key: 'Title' },
{ key: 'Active' },
{ key: 'Action' }
]
};
grdNewsConfigs = {
paginator: new YAHOO.widget.Paginator({
rowsPerPage: 20
})
};
grdNewsDataTable = new YAHOO.widget.DataTable('grdNews', grdNewsColumnDefs, grdNewsDataSource, grdNewsConfigs);
grdNewsDataTable.on('initEvent', function () {
YAHOO.util.Dom.setStyle(grdNewsDataTable.getTableEl(), 'width', '100%');
});
});
</script>
Not sure what I am doing wrong, but here is my action method that returns my data:
public ActionResult JsonList()
{
JsonEncapsulatorDto<News> data = new JsonEncapsulatorDto<News>
{
DataResultSet = newsService.FindAll()
};
return Json(data, JsonRequestBehavior.AllowGet);
}
I put a breakpoint on the return Json... line to see if this action method is hit. When the page loads the first time it goes to the break, I hit F5 then it runs and displays the view with the populated grid. When I refresh my browser by pressing F5 then my breakpoint is not hit again, I'm not sure why, it never goes in here again.
How is data loaded into the grid? If I have 100 records in the table and I have set my rowsPerPage to 20 then I will have 5 pages. Given my code above, is data loaded all at once, meaning is all 100 rows loaded at once? I would preferably like to have it loaded in "chunks" instead of having it all loaded at once. In another table I have much more records and this will not be a wise design approach to load everything at once. How would I implement something like this?
I am trying to style certain table headers and cells in the data table. I worked through this article explaining how to style a data table: http://www.satyam.com.ar/yui/widgetstyles.html. When I set the td to right align then the th for that column is also right aligned, why is this? You can see above how I set the className property. Here is my stylesheet code:
.yui-skin-sam .yui-dt td.align_left{text-align:left}
Given the above scenario, I want the column header to be left aligned and the corresponding column rows to right aligned? I probably won’t use it like this, but just want to know how to set a style to different elements?
I set the data table's width to be 100%, but when I page to the next page then it seems to loose this width of 100%. Why is this? What I need to do to have my data table to keep my width of 100%?
If I were to update data then it does not display as updated. Why is this and what do I need to do get the updated data to display in the data table?
You have configured your YUI grid to use an AJAX request to fetch the remote data:
grdNewsDataSource = YAHOO.util.DataSource('#Url.RouteUrl(Url.NewsJsonList())');
GET AJAX requests could be cached by the browser which explains why your controller action is hit only once (the first time you load the page). In order to avoid this caching you could either configure YUI to use a POST request or append a random number to the URL each time the page is loaded.
How is data loaded into the grid? If I have 100 records in the table and I have set my rowsPerPage to 20 then I will have 5 pages.
No matter what you set on the client side the following:
DataResultSet = newsService.FindAll()
is a clear indication that the server fetches all records from the database and sends all records back to the client and it is the client that retrieves only the necessary records to show which is inefficient.
Ideally the pagination should be done on the server. Here's an example from the documentation. The client sends the startIndex and results parameters to the server so that it could paginate the data set on the server and return only the necessary rows that will be shown on the screen.

Problem binding jqGrid in ASP.NET

I am new to using jqGrid and jquery.I am not able to bind my json data which I retrive from the webmethod onto the jqGrid.
I have also used firebug to cross verify and i am receiving data from it. Some help regarding this will be great. I would aslo like to know if any other references needs to be added.
following is the code that I have implemented.
PAGE METHOD
[WebMethod]
public static string GetData()
{
Customer Cone = new Customer();
Customer Ctwo = new Customer();
Cone.CustomerID = "100";
Cone.CustomerName = "abc";
Ctwo.CustomerID = "101";
Ctwo.CustomerName = "xyz";
List<Customer> lstCustomer = new List<Customer>();
lstCustomer.Add(Ctwo);
lstCustomer.Add(Cone);
JavaScriptSerializer jsonSerz = new JavaScriptSerializer();
string serializedData = jsonSerz.Serialize(lstCustomer);
return serializedData;
}
client side coding
<script type="text/javascript" src="jquery-1.4.4.min.js"></script>
<script type="text/javascript" src="jquery.jqGrid.min.js"></script>
<script type="text/javascript">
function GetData() {
alert('Inside GetData');
var data = PageMethods.GetData(OnSuccess, OnFailed);
}
function OnFailed(error) {
alert('Failed');
alert(error.get_message());
}
function OnSuccess(data) {
alert(data);
}
$(document).ready(function() {
$('#submit').click(function() {
alert('Button Clicked');
$('#list').jqGrid({
url: 'http://localhost:1405/WebSite1/Default.aspx/GetData',
data: '{}', // For empty input data use "{}",
dataType: 'local',
type: 'POST',
contentType: "application/json; charset=utf-8",
colNames: ['CustomerID', 'CustomerName'],
colModel: [
{ name: 'CustomerID', index: 'CustomerID', width: 80,
align: 'left', editable: false },
{ name: 'CustomerName', index: 'CustomerName', width: 120,
align: 'left', editable: true}],
pager: $('#pager'),
rowNum: 5,
rowList: [10],
sortname: 'CustomerID',
sortorder: 'desc',
viewrecords: true,
width: 300
});
});
});
</script>
AND HTML code
<asp:ScriptManager ID="ScriptManager1" EnablePageMethods="true" runat="server">
</asp:ScriptManager>
<input type="button" id="submit" value="Fetch" title="Fetch"
onclick="javascript:GetData()" />
<table id="list">
</table>
<div id="pager">
</div>
First of all I recommend you to play a little with another working code which you can download here (see more information here). More links to another examples you can find here.
I try to describe some problems in your current code.
You use 'http://localhost:1405/WebSite1/Default.aspx/GetData' as the url. You shold better use only pathes like '/WebSite1/Default.aspx/GetData' or 'WebSite1/Default.aspx/GetData' or you can easy receive same origin policy problem.
You should use ASMX service instead of placing the code inside of ASPX page (Default.aspx/GetData). You should just add new item to your ASP.NET solution and choose Web Serice template. The corresponding code template will be added for you and web.config will be modified. In the same way you can place WCF service inside your ASP.NET project. The step is independ on the technology which you use (WebForms, ASP.NET MVC and so on).
Instead of manual JSON serialisation with respect of JavaScriptSerializer you should define [ScriptMethod(ResponseFormat = ResponseFormat.Json)] attriute to your method and return an object from the web method (like List<Customer> in your case). The JSON serialization will be done automatically for you.
You use dataType: 'local' which is wrong parameter for jqGrid. Correct parameter will be datatype:'json' (datatype instead of dataType and 'json' to make the request to the server).
Instead of type: 'POST' you should use mtype: 'POST'.
Instead of contentType: "application/json; charset=utf-8" you should use ajaxGridOptions: { contentType: "application/json" }.
The usage of data: '{}' is also wrong. Probably you try to use data parameter of jQuery.ajax like with dataType parameter. In jqGrid you should use pastData instead of data and the data parameter must be an array and has another meaning. I recommand you to look at the code of the example (see reference at the begin of my answer).
You should not place $('#list').jqGrid({...}); inside of click handle. The problem is that the code make some initializations of jqgrid and then fill the grid. What you probaly want is creating the grid only once and then refreshing it with another input data probaby (I am not sure that it is so). So you should move $('#list').jqGrid({...}); inside of $(document).ready(function() {...};. If needed you can use $('#list').trigger("reloadGrid") inside of the click event handle. Alternatively you can use GridUnload to destroy the existing grid before creating it new.
I can continue, but my main recommendation is to examine another examples and use ASMX or WCF service which provide the data for jqGrid.
Entire grid binding event is called before your page method.
You have put it under document.Ready event. Try calling it from the button click event.
I am not sure but there should be some way to bind json data to Jquery grid on client side without using the URL part.
try mapping "data:" to some Json value.

How to add a row hyperlink for an extJS Grid?

Can someone please throw some light on how to go about rendering an hyperlink in the cells of a particular column in ExtJS?
I have tried binding the column to a render function in my JS, from which I send back the html:
SELECT
However, with this, the problem is that, once I hit the controller through the link, the navigation is successful, but subsequent navigations to the data-grid show up only empty records.
The records get fetched from the DB successfully through the Spring MVC controller, I have checked.
Please note that this happens only once I use the row hyperlink in the extJS grid to navigate away from the grid. If I come to the grid, and navigate elsewhere and again come back to the grid, the data is displayed fine.
The problem only occurs in case of navigating away from the grid, using the hyperlink rendered in one/any of the cells.
Thanks for your help!
This is for ExtJS 4 and 5.
Use a renderer to make the contents look like a link:
renderer: function (value) {
return ''+value+'';
}
Then use the undocumented, dynamically generated View event cellclick to process the click:
viewConfig: {
listeners: {
cellclick: function (view, cell, cellIndex, record, row, rowIndex, e) {
var linkClicked = (e.target.tagName == 'A');
var clickedDataIndex =
view.panel.headerCt.getHeaderAtIndex(cellIndex).dataIndex;
if (linkClicked && clickedDataIndex == '...') {
alert(record.get('id'));
}
}
}
}
Try something like this:
Ext.define('Names', {
extend: 'Ext.data.Model',
fields: [
{ type: 'string', name: 'Id' },
{ type: 'string', name: 'Link' },
{ type: 'string', name: 'Name' }
]
});
var grid = Ext.create('Ext.grid.Panel', {
store: store,
columns: [
{
text: 'Id',
dataIndex: 'Id'
},
{
text: 'Name',
dataIndex: 'Name',
renderer: function (val, meta, record) {
return '' + val + '';
}
}
...
...
...
However my thanks to - ExtJS Data Grid Column renderer to have multiple values
Instead of using an anchor tag, I would probably use plain cell content styled to look like an anchor (using basic CSS) and handle the cellclick event of the GridPanel to handle the action. This avoids dealing with the anchor's default click behavior reloading the page (which is what I'm assuming is happening).
I created a renderer so it looked like you were clicking on it.
aRenderer: function (val, metaData, record, rowIndex, colIndex, store){
// Using CellClick to invoke
return "<a>View</a>";
},
But I used a cell event to manage the click.
cellclick: {
fn: function (o, idx, column, e) {
if (column == 1) // Doesn't prevent the user from moving the column
{
var store = o.getStore();
var record = store.getAt(idx);
// Do work
}
}
}
For these purposes I use CellActions or RowActions plugin depending on what I actually need and handle cell click through it.
If you want something that looks like an anchor, use <span> instead and do what #bmoeskau suggested.
You can use 'renderer' function to include any HTML you want into cell.
Thanks guys for your response.
AFter debugging the extJS-all.js script, I found the issue to be on the server side.
In my Spring MVC controller, I was setting the model to the session, which in the use-case I mentioned earlier, used to reset the "totalProperty" of Ext.data.XmlStore to 0, and hence subsequent hits to the grid, used to display empty records.
This is because, ext-JS grid, checks the "totalProperty" value, before it even iterates through the records from the dataStore. In my case, the dataStore had data, but the size was reset to null, and hence the issue showed up.
Thanks to all again for your inputs!

Resources