dojox.grid.DataGrid sort order bug on mixed case strings? - dojo

I know Dojo is getting quite old now but we still have apps that are using it.
One thing that was pointed out was the sort facility on the dojox.grid.DataGrid table of users. Our users table has grown over time so it's useful to order by the name column. However, we find that, while most names were entered with a Capital first letter, some names were entered all in lowercase and when I click on the name column header for sorting, I find that the Capitalised names appear in alphabetical order BUT followed by lowercase name in the same order at the bottom.
e.g. The raw data:
Tom
Dick
harry
After "sorting" displays as :
Dick
Tom
harry
Code example, using Dojo 1.8.3, as follows:
require(["dojox/grid/EnhancedGrid",
"dojo/data/ItemFileWriteStore",
"dojo/parser",
"dojo/on",
'dojo/domReady!'
],
function(EnhancedGrid, ItemFileWriteStore, Filter, parser, on) {
var data = {
items: [
{ name: 'Tom', age: 29 },
{ name: 'Dick', age: 9 },
{ name: 'harry', age: 19 }
]
};
var gridStore = new ItemFileWriteStore({
data: data
});
var gridStructure = [
[
{ 'name': 'Name', 'field': 'name' },
{ 'name': 'Age' , 'field': 'age' }
]
];
var mygrid = new EnhancedGrid({
id: "grid",
store: gridStore,
structure: gridStructure,
autoHeight: true,
autoWidth: true
}, "mydatagrid");
mygrid.startup();
}
);
<link href="https://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojox/grid/enhanced/resources/claro/EnhancedGrid.css" rel="stylesheet" />
<link href="https://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dijit/themes/claro/claro.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojo/dojo.js"></script>
<div id="container" class="claro">
<div id="mydatagrid"></div>
</div>
How do I sort a column of mixed case names correctly?
i.e. to display sorted grid as:
Dick
harry
Tom
Thanks

I managed to get a solution through a suggestion on a related DataGrid post: dojox.grid.DataGrid custom sort method?
Basically, you can use the "comparatorMap" of the ItemFileWriteStore (or ItemFileReadStore)
require(["dojox/grid/EnhancedGrid",
"dojo/data/ItemFileWriteStore",
"dojo/parser",
"dojo/on",
'dojo/domReady!'
],
function(EnhancedGrid, ItemFileWriteStore, Filter, parser, on) {
var data = {
items: [
{ name: 'Tom', age: 29 },
{ name: 'Dick', age: 9 },
{ name: 'harry', age: 19 }
]
};
var gridStore = new ItemFileWriteStore({
data: data
});
var gridStructure = [
[
{ 'name': 'Name', 'field': 'name' },
{ 'name': 'Age' , 'field': 'age' }
]
];
//====================================================================================
//= Define the comparator function for "Name" ========================================
//====================================================================================
gridStore.comparatorMap = {};
gridStore.comparatorMap["name"] = function(a,b) {
var nameA = a.toLowerCase().trim(), nameB = b.toLowerCase().trim();
if (nameA < nameB) //sort string ascending
return -1;
if (nameA > nameB)
return 1;
return 0; //default return value (no sorting)
}
//====================================================================================
//====================================================================================
//====================================================================================
var mygrid = new EnhancedGrid({
id: "grid",
store: gridStore,
structure: gridStructure,
autoHeight: true,
autoWidth: true
}, "mydatagrid");
mygrid.startup();
}
);
<link href="https://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojox/grid/enhanced/resources/claro/EnhancedGrid.css" rel="stylesheet" />
<link href="https://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dijit/themes/claro/claro.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojo/dojo.js"></script>
<div id="container" class="claro">
<div id="mydatagrid"></div>
</div>

Related

Dojo Select onchange not firing on creating Select box programmatically

I have two dojo select dropdowns. First dropdown is populated on page load and on selecting a value from first drop down, second select box should be populated.
I create the second select box programatically and i destroy it for every on change event of the first dropdown box.( this is to avoid widget already registered error).
But when i select any of the option from second drop down select, it does not fire onchange event.
Pls help on this.
My code is
require(["dojo/parser","dijit/form/RadioButton","dojo/ready","dojo/data/ItemFileReadStore","dijit/registry","dijit/form/Select","dojo/ready","dojo/dom-form", "dojo/dom", "dojo/on", "dojo/request","dojo/domReady"],
function(parser,RadioButton,ready,ItemFileReadStore,registry,Select,ready,Form,dom,on,request){
parser.parse();
var manuData;
var modelData;
var shaftType;
var modelId;
var clubMfr;
var clubType;
var manufacturerList;
dojo.connect(dijit.byId("clubtype"),"onChange",function(event){
clubType=registry.byId("clubtype").get('value');
console.log(clubType);
var id= registry.byId("clubtype");
var option1= registry.byId("manufacturer");
request("/tradeIn/"+clubType).then(function(list){
manuData=list;
var data1 = dojo.fromJson(manuData);
var readstore=new ItemFileReadStore({ data:{
identifier : "manufacturer",
label: "manufacturer",
items : data1,
}});
if(typeof registry.byId("manufacturerId") != "undefined"){
registry.byId("manufacturerId").destroyRecursive();
}
manufacturerList=new Select({
name:"manufacturerId",
id:"manufacturerId",
store:readstore,
onSetStore: function() {
this.options.unshift({selected:'true',label:'Choose One', value:'NULL'});
this._loadChildren();
}
}).placeAt("manuList");
manufacturerList.startup();
});
}
);
dojo.connect(
dijit.byId("manufacturerId"),"onChange",function(event){
var manufacturerId=registry.byId("manufacturerId").get('value');
clubMfr=manufacturerId;
var model= registry.byId("model");
model.removeOption(dijit.byId("model").getOptions());
request("/tradeIn/"+manufacturerId+"/"+clubType).then(function(list){
modelData=list;
var data1 = dojo.fromJson(modelData);
var readstore=new ItemFileReadStore({ data:{
identifier : "model",
label: "model",
items : data1
}});
if(typeof registry.byId("modelId") != "undefined"){
registry.byId("modelId").destroyRecursive();
}
var modelList=new Select({
name:"modelId",
id:"modelId",
store:readstore,
onSetStore: function() {
this.options.unshift({selected:'true',label:'Choose One', value:'NULL'});
this._loadChildren();
}
}).placeAt("modelList");
modelList.startup();
});
}
);
dojo.connect(
dijit.byId("model"),"onChange",function(event){
modelId=registry.byId("model").get('value');
console.log("model "+modelId);
}
);
});
You need to disconnect the onChange event before destroying the select and to reconnect it after creating the select. To achieve the disconnection, you can use own() method.
Here is how it should look like:
if(typeof registry.byId("manufacturerId") != "undefined"){
registry.byId("manufacturerId").destroyRecursive();
}
manufacturerList=new Select({/* ... */});
manufacturerList.own(dojo.connect(
dijit.byId("manufacturerId"),"onChange",function(event){ /* ... */ }
));
Note: This is extremely dirty. The proper approach would be to NOT destroy the second select and instead to update its data.
See the snippets for updating it:
require(['dijit/form/Select', 'dojo/data/ItemFileReadStore', 'dojo/domReady!'], function(Select, ItemFileReadStore) {
var initialStoreData = [
{value: "AL", label: "Alabama"},
{value: "AK", label: "Alaska"},
{value: "AZ", label: "Arizona"}
];
var changedStoreData = [
{value: "CA", label: "California"},
{value: "CO", label: "Colorado"},
{value: "CT", label: "Connecticut"}
];
var prepareData = function(storeData) {
//because the store return sorted data, I have added a space before the word 'Choose'. So it comes first
return [{value: '', label: ' Choose one'}].concat(storeData);
}
var readStore=new ItemFileReadStore({
data:{
identifier: "value",
label: "label",
items: prepareData(initialStoreData)
}
});
var selectWidget = new Select({
store: readStore
});
selectWidget.placeAt(document.getElementById('test'));
selectWidget.startup();
btn.onclick = function() {
var newReadStore=new ItemFileReadStore({
data:{
identifier: "value",
label: "label",
items: prepareData(changedStoreData)
}
});
selectWidget.set('store', newReadStore);
}
});
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojo/dojo.js"></script>
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojo/resources/dojo.css">
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.10.4/dijit/themes/tundra/tundra.css">
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojox/form/resources/CheckedMultiSelect.css">
<div id="test" class="tundra">
<button id="btn">change data in select</button>
</div>

Datatables Single Column Filter

I read api doc and find individual column searching to filter data by column row, great but i just need add one dropdown filter by name on top (beside number filter)
Current setup (use tabletool and bootstrap)
$('table').DataTable({
'aLengthMenu': [[25, 50, 75, -1], [25, 50, 75, 'All']],
'iDisplayLength': 25,
'stateSave': true,
'oLanguage': {
'sLengthMenu': 'Show : _MENU_',
'sSearch': 'Search : _INPUT_',
},
'oTableTools': {
'sSwfPath': 'media/swf/copy_csv_xls_pdf.swf'
},
/*
'order': [[ 1, 'asc' ]],
'aoColumnDefs': [
{
'bSortable': false,
'aTargets': [ -1, 0 ]
}
]
*/
});
If you are using Datatables Version 1.10 and upwards you want to use the DOM option to position a div in the header where you want to add your filter and add your select to it.
var table;
$(document).ready(function () {
table = $('#example').dataTable({
"dom": "l<'#myFilter'>frtip"
});
var myFilter = '<select id="mySelect">'
+ '<option value="1">Searchval 1</option>'
+ '<option value="2">Searchval 2</option>'
+ '<option value="3">Searchval 3</option>'
+ '</select>';
$("#myFilter").html(myFilter);
table.fnDraw();
});
Then add a custom filter function.
$.fn.dataTable.ext.search.push(
function (settings, data) {
//your filter stuff belongs here
return true;
});
And redraw the table everytime you change your filter.
$("body").on("change", "#mySelect", function () {
table.fnDraw();
});
See this JSFiddle for an example of what more or less should fit your requirements.
That idea is implemented in this DataTables plug-in, you may check out working DEMO:
$(document).ready(function () {
//Source data definition
var tableData = [
{item: 'banana', category: 'fruit', color: 'yellow'},
{item: 'pear', category: 'fruit', color: 'green'},
{item: 'cabbage', category: 'vegie', color: 'green'},
{item: 'carrot', category: 'vegie', color: 'red'},
{item: 'apple', category: 'fruit', color: 'red'},
{item: 'kiwi', category: 'fruit', color: 'brown'}
];
//DataTable definition
window.dataTable = $('#mytable').DataTable({
sDom: 'tF',
data: tableData,
columns: [{
data: 'item',
title: 'Item'
}, {
data: 'category',
title: 'Category'
}, {
data: 'color',
title: 'Color'
}]
});
});
<!doctype html>
<html>
<head>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.mfilter.tk/js/mfilter.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css">
<link rel="stylesheet" type="text/css" href="https://cdn.mfilter.tk/css/mfilter.min.css">
</head>
<body>
<table id="mytable"></table>
</body>
</html>

Use dgrid/Grid by Dojo CDN

i tried to use dgrid by the including dojo 1.10 by CDN but it does not work.
<script
src="http://ajax.googleapis.com/ajax/libs/dojo/1.10.0/dojo/dojo.js"
data-dojo-config="async: true, parseOnLoad:true"></script>
<script>
require([ "dgrid/Grid", "dojo/domReady!" ], function(Grid) {
var grid = new Grid({
columns : {
serverName : "Server Name",
serviceName : "Service Name",
available : "Verfügbar"
}
}, "grid");
});
Where is the problem? By loading the site i get an Err: scriptErr.
Here's a really complete example.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Tutorial: Hello dgrid!</title>
<script
src='//ajax.googleapis.com/ajax/libs/dojo/1.10.1/dojo/dojo.js'
data-dojo-config="async: true, parseOnLoad: true">
</script>
<script>
require({
packages: [{
name: 'dgrid',
location: '//cdn.rawgit.com/SitePen/dgrid/v0.3.15'
}, {
name: 'xstyle',
location:'//cdn.rawgit.com/kriszyp/xstyle/v0.2.1'
}, {
name: 'put-selector',
location: '//cdn.rawgit.com/kriszyp/put-selector/v0.3.5'
}]
},[
'dgrid/Grid',
'dojo/domReady!'
], function (Grid) {
var data = [
{ first: 'Bob', last: 'Barker', age: 89 },
{ first: 'Vanna', last: 'White', age: 55 },
{ first: 'Pat', last: 'Sajak', age: 65 }
];
var grid = new Grid({
columns: {
first: 'First Name',
last: 'Last Name',
age: 'Age'
}
}, 'grid');
grid.renderArray(data);
});
</script>
</head>
<body>
<div id="grid"></div>
</body>
</html>
dgrid and its dependencies are not hosted on the Google CDN, let alone as a sibling of Dojo, and you don't seem to have any packages configuration to pick up dgrid, xstyle, and put-selector elsewhere.
While dgrid is not published to any CDN, RawGit now has a feature they're testing out which is capable of caching github resources on MaxCDN. You can take advantage of this for dgrid with a configuration like the following:
var dojoConfig = {
async: true,
packages: [{
name: 'dgrid',
location: '//cdn.rawgit.com/SitePen/dgrid/v0.3.15'
}, {
name: 'xstyle',
location:'//cdn.rawgit.com/kriszyp/xstyle/v0.2.1'
}, {
name: 'put-selector',
location: '//cdn.rawgit.com/kriszyp/put-selector/v0.3.5'
}]
};
Of course, remember that RawGit's CDN service has no guarantee of 100% uptime and thus should be used only for prototyping, not production, but you should ideally be rolling a custom build for production anyway.
You need to put a div tag in the body.
<body>
<div id="grid"></div>
</body>
have you tried calling grid.renderArray(data)?
Here is a complete example
require(["dgrid/Grid", "dojo/domReady!"], function(Grid){
    var data = [
        { first: "Bob", last: "Barker", age: 89 },
        { first: "Vanna", last: "White", age: 55 },
        { first: "Pat", last: "Sajak", age: 65 }
    ];
 
    var grid = new Grid({
        columns: {
            first: "First Name",
            last: "Last Name",
            age: "Age"
        }
    }, "grid");
    grid.renderArray(data);
});
more examples here

Store option not working dgrid, works perfect with ondemandgrid

I want to use store attribute of Dgrid, i am using below code to make dgrid table but somehow table doesn't get populated with rows.
<script src="dojo/dojo.js"
data-dojo-config="async: true"></script>
<script>
require(["dojo/_base/declare","dgrid/Grid","dgrid/Keyboard","dgrid/Selection","dgrid/editor","dgrid/extensions/DnD","dojo/dnd/Source", "dojo/store/Memory", "dojo/_base/lang"],
function (declare,Grid,Keyboard,Selection,editor,DnD, DnDSource, Memory, lang){
var store = new Memory({
data: [
{ id: 1, firstName: "Jeffrey", lastName: "Andrews", email: "jeffrey#madeupdomain.com" },
{ id: 2, firstName: "Jenny", lastName: "Saunders", email: "jenny#madeupdomain.com" },
]
});
var structure = [
{field: "lastName", label: "Last Name"},
{field: "firstName", label: "First Name"},
{field: "email", label: "EMail Address"}
];
var grid = new (declare([Grid, Selection, DnD]))({
store: store,
columns: structure
},
"gridtable");
grid.startup();
});
</script>
</head>
<div id="gridtable"></div>
The base List and Grid modules are not designed to be store-aware. Store awareness is usually inherited from _StoreMixin, which OnDemandList and the Pagination extension inherit.
It's also feasible to make your own extension of _StoreMixin; for example, one of the tutorials on dgrid.io walks through a very simple extension to render all data from a store at once.

Returning JSON Data to JQGrid is prompting to save a file

I'm new to ASP.Net MVC. I'm trying a sample program to bind a JQGrid with data. When I return the JSON data from the Controller , the system is prompting me with a pop up "Do you want to Save the file ..".I beleive my browser is not able to understand JSON data. I went through the other post in StackOverFlow and none of them seem to help me. I'm running this on IE8 set to Compatibility mode. Please see the code below:
Index.cshtml
#{
ViewBag.Title = "Home Page";
}
<link href="~/Content/Site.css" rel="stylesheet" type="text/css" />
<link href="~/Content/jquery.jqGrid/ui.jqgrid.css" rel="stylesheet" type="text/css" />
<link href="~/Content/themes/base/jquery.ui.all.css" rel="stylesheet" type="text/css" />
<script src="~/Scripts/jquery-1.9.1.min.js" type="text/javascript"></script>
<script src="~/Scripts/i18n/grid.locale-en.js" type="text/javascript"></script>
<script src="~/Scripts/jquery.jqGrid.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
$("#myGrid").jqGrid({
url: '../../Home/About/GetJQGridData',
datatype: 'json',
contentType: 'application/json',
myType: 'GET',
colNames: ['Id', 'Name'],
colModel: [
{ name: 'Id', index: 'Id' },
{ name: 'Name', index: 'Name' }
],
jsonReader: {
root: 'Data',
id: 'id',
repeatitems: false
},
pager: $('#myPager'),
rowNum: 5,
rowList: [2, 5, 10],
width: 600,
viewrecords: true,
caption: 'Jqgrid MVC Tutorial'
});
});
</script>
<table id="myGrid"></table>
<div id="myPager"></div>`
My Controller code is as follows:
HomeController.cs
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult GetJQGridData()
{
var jqGridData = new JQGridObject()
{
Data = GetSomeSampleData(),
Page = "1",
PageSize = 3, // u can change this !
SortColumn = "Name",
SortOrder = "asc"
};
return Json(jqGridData, JsonRequestBehavior.AllowGet);
}
public List<Fruit> GetSomeSampleData()
{
return new List<Fruit>
{
new Fruit{Id = 1, Name = "Apple" },
new Fruit{Id = 2, Name = "Melon" },
new Fruit{Id = 3, Name = "Orange" },
new Fruit{Id = 4, Name = "Grapes" },
new Fruit{Id = 5, Name = "Pineapple" },
new Fruit{Id = 6, Name = "Mango" },
new Fruit{Id = 7, Name = "Bannana" },
new Fruit{Id = 8, Name = "Cherry" }
};
}
Any help would be highly appreciated.
Thanks
First thing that jumps out at me is that your Controller/View is being referenced incorrectly
url: '../../Home/About/GetJQGridData',
should be
url: '/Home/GetJQGridData',
You shouldn't need to set a jsonReader as well on the client.