I am trying to create an Enhanced Grid with nested sorting functionality in Dojo but when I go to add the nested sorting functionality via the plugins the grid no longer works (shows up) in the page. My enhanced grid creation code is as follows:
dojo.require("dojox.grid.EnhancedGrid");
dojo.require("dojox.grid.enhanced.plugins.NestedSorting");
grid = new dojox.grid.EnhancedGrid({
canSort: function(colIndex) {
//colIndex = -colIndex; //make columns decend
if ((colIndex == colA) || (colIndex == colB)) {
return false;
}
return true;
},
onHeaderCellMouseOver:function(event{onGridHeaderCellMouseOver(event,layout[0]);},
onHeaderCellMouseOut: function(event){onGridHeaderCellMouseOut(event,layout[0]);},
store: msgStore,
structure: layout,
plugins: {nestedSorting: true}
},document.createElement("div"));
dojo.byId("TableHolder").appendChild(grid.domNode);
grid.startup();
grid.setSortInfo(-1);
If I comment out the plugins line then it will work perfectly w/o nested sort. Does anyone know how I would be able to get nested sorting functionality?
I am using Dojo 1.4.
Thanks
Seems like I have solved this issue .... I figured out that a file that must be included 'required' is: "dojox.grid.cells.dijit". Weird thing is that I found no indication that this was necessary from the documentation, but did happen to find it in the examples. Once this was added to my required statements I had nested sorting. Could someone explain this specific require and its seemingly crucial importance?
Thanks
Just had a quick try with 1.4.3, seems the same code works for me:
dojo.addOnLoad(function(){
var grid = new dojox.grid.EnhancedGrid({
id:'grid',
canSort: function(colIndex) {
if ((colIndex == 0) || (colIndex == 1)) {
return false;
}
return true;
},
onHeaderCellMouseOver:function(event)onGridHeaderCellMouseOver(event,layout[0]);},
onHeaderCellMouseOut: function(event)onGridHeaderCellMouseOut(event,layout[0]);},
store: csvStore1,
structure: layout,
plugins : {nestedSorting: true}
}, document.createElement("div"));
dojo.byId("gridDiv").appendChild(grid.domNode);
grid.startup();
grid.setSortInfo(-1); });
it's malformed in your onHeaderCellMouseOver:function(event{, but don't think that's the cause since single sort works for you.
BTW, setting default nested sorting order by grid.setSortInfo(-1) aren't supported in 1.4(it's in plan for 1.6)
Should be a defect in earlier version, it's working for me in 1.5, also a related thread at dojo forum
Related
I'm using ExtJS 6.7 Modern toolkit and Ext.grid.Tree.selectOnExpander = false does not work properly when data for expandable node is loading from a remote server, i.e. node is selected when I click on the expander.
I expect that in this case the node will NOT be selected as in the case when the data is already loaded.
Check this fiddle as an illustration - try to expand node when it is loaded and when it is not loaded yet using expander.
So far I've tried to check fired events with Ext.util.Observable.capture and it seems like extra childtap event is triggired. I don't yet understand why. Seems like a bug for me.
Seems they forgot to implement the logic.
From the code I would sugget to use this snippet.
It extens the logic from Ext.dataview.List using the same style.
Sencha Fiddle: Fiddle
Ext.define('Portal.grid.Tree', {
override: 'Ext.grid.Tree',
shouldSelectItem: function(e) {
var me = this,
no = !me.callParent([e]),
cmp;
if (!no && !me.selectOnExpander) {
cmp = e.getTarget();
no = cmp.classList.contains('x-expander-el');
}
return !no;
}
});
The best solution I have found so far is to override Ext.grid.Tree onChildTap method (inherited from Ext.dataview.Abstract) like this:
Ext.define('Portal.grid.Tree', {
override: 'Ext.grid.Tree',
/** Override Ext.dataview.Abstract onChildTap method for correct processing selectOnExpander property **/
onChildTap: function(location) {
if (this.getSelectOnExpander() || location.event.target !== location.cell.expanderElement.dom) {
this.callParent(arguments);
}
},
});
I've been combining Twitter Typeahead and Bloodhound into a Knockout custom binding as a bit of an experiment, and so far I have it working quite well. However I have a use case where I wanted to have a selectable entry in the list if a user types in a search term which finds no results. This isn't something that is available by default in typeahead but I did find this issue on Github which demonstrates a workaround that seems to fit the bill. Trouble is I can't get it to work at all and my fairly limited Javascript smarts have all but run out.
The gist of this workaround is that rather than creating a Bloodhound instance and then setting the source property of the typeahead to engine.ttAdaptor() you do the following:
var engine = new Bloodhound(/* ... */);
engine.initialize();
var emptyDatum = { val: 'i am suggestion shown when there are none!' };
var sourceWithEmptySelectable = function(q, cb) {
engine.get(q, injectEmptySelectable);
function injectEmptySelectable(suggestions) {
if (suggestions.length === 0) {
cb([emptyDatum]);
}
else {
cb(suggestions);
}
}
};
$('.typeahead').typeahead(null, {
// ...
source: sourceWithEmptySelectable
});
Using the latest versions of typeahead (v0.11.1) I get an error which simply says missing source. Looking at the source code for Bloodhound it looks to me like the engine.get(q, injectEmptySelectable) call no longer works as there is no method of get on the Bloodhound class with a signature that accepts a query and a callback. There is one on the Transport class but I'm not seeing how that would be the one being used in this example. Am I correct in this or am I missing something, or is there another way to accomplish this?
I am using sigma.js along with angular js to build my visualization web app.
Problem statement: I have written code in such a way that when filter criteria changes, filter module will be triggered to filter out nodes based on user selection(see code below).But, Initially for the first time filter works fine without any issue, but later on it doesn't seem to be working. It looks like it is not executing the filter predicate at all.
I tried below possible ways, but couldn't resolve the issue.
1) Destroyed and recreated the filter object for every data change trigger.
2) Unregistered and registered filter predicate.
code snippet:
scope.$watch('filtersettingdata',function(){
s = new sigma({
graph: scope.data['mdata'],
container: element.elementid,
renderer: {
container: document.getElementById(element.elementid),
type: 'canvas'
},
settings: filtersettingdata
});
var filter = new sigma.plugins.filter(s);
filter.nodesBy(
function(n) {
//predicate with new filter values
},'filter_name').apply();
s.refresh();
}
any help/suggestions will be really appreciated.
Thanks in advance.
I'm the author of this plugin.
It is out-dated in the official sigma repository and I don't think it will work with Angular as it is.
It is now released under dual license GNU GPLv3 + commercial here: https://github.com/Linkurious/linkurious.js/tree/linkurious-version/plugins/sigma.plugins.filter
This version works with Angular and I've successfully used it in the projects of my company.
Disclaimer: I work at Linkurious SAS.
I'm trying to render some data in the rowbody in a grid (with the RowExpander plugin).
My problem is that the ol' rowBodyTpl isn't enough for me as this data is from Records on Stores from the record being rendered (hmmm...).
Putting it simply: Every record of the grid has a store in it (lets call it Items). So, I want to render the record data and some data of the Items records aswell.
What would be the best(ish) way of doing so?
Override the renderer function of the rowexpander plugin, override the getAdditionalData, or none of these?
Thank you.
I know this question is a few years old, but here's a trick I currently use to handle this kind of situation. It takes advantage of "verbatim" blocks that XTemplates allow. These allow you to execute arbitrary code inside an XTemplate by wrapping it with {% ... %}. Inside those code blocks, this is set to the XTemplate itself. The XTemplate has an owner property that, in our case, references the RowExpander plugin itself, which, in turn, has a grid property to reference the grid. So, something like this allows you to add arbitrary data to the values passed into rowBodyTpl.
Ext.create('Ext.grid.Panel', {
...
injectRowBodyData: function(values) {
values.MyInjectedContent = "Here's some extra data!";
},
plugins: [
{
ptype: 'rowexpander',
rowBodyTpl: [
'{% this.owner.grid.injectRowBodyData(value); %}',
'<div>',
'<h1>{Title}</h1>',
'<p>{Content}</p>,
'<p>{MyInjectedContent}</p>',
'</div>'
]
}
]
});
Hhopefully Sencha will fix the plugin to provide a way to handle this in the future. But for now this works well. I tested this with v4.2.1.883, but this should work with any previous version of Ext 4. The only thing I can think of that may prevent it from working in the future is the XTemplate's owner property no longer being pointed to the plugin, or the plugin not having a reference to the grid with it's grid property.
How I "solve" this problem, it might help somebody else:
I overrode the getRowBodyFeatureData of the rowexpander plugin, as this function not only receives the data to be applied on the template, but also the record itself, so I just data added the extra stores/arrays from the record.
Not sure if its the best way, but hey... at least it works.
You can also use if else statements in rowBodyTpl:
Check for ":"
"<tpl if='phone == \":\"'>",
"<tpl else>",
"</tpl>"
Check for empty string
"<tpl if='phone == \"\"'>",
"</tpl>"
this sample is taken from here: link
This is how I usually do:
Ext.create('Ext.grid.Panel',{
border: true,
store: 'ds',
columns: []
plugins: [{
ptype: 'rowexpander',
rowBodyTpl : ['<p><b>Title:</b>{name}<br/><b>Description:</b> {description}<br/><b>Experiment Design:</b> {experimentdesign}</p>']
}],
renderTo:
});
jQuery's plugin TableSorter doesn't seem to handle a situation where it is attached to an empty table. Is there a neat way around this?
In my application the user can filter and search the data and eventually he or she will come up with a search criteria which doesn't return any values. In these situations it would be nice to "detach" the TableSorter or somehow fix it's code so that it works with an empty table.
I'm currently using the plugin like this:
$("#transactionsTable")
.tablesorter({ widthFixed: true, widgets: ['zebra'] })
.tablesorterPager({ container: $("#pager"), positionFixed: false });
This works well, until the table is empty. Then I get the following error:
Line: 3
Error: '0.length' is null or not an object
Any ideas? Is it possible to change the script so that the tablesorter is only added to the table if it has rows?
I think you can do it for your self.
if ($("#transactionsTable").find("tr").size() > 1)
{
//> 1 for the case your table got a headline row
$("#transactionsTable")
.tablesorter({ widthFixed: true, widgets: ['zebra'] })
.tablesorterPager({ container: $("#pager"), positionFixed: false });
}
If your table got a tbody tag it is easier:
if ($("#transactionsTable").find("tbody").find("tr").size() > 0)
This way is maybe not the most professional one, but it should work under this circumstatances.
The issue is related to the fact that several parts of the codebase use rows[0] to determine 1) total number of columns, 2) the parser type to use per column (eg "text" vs "digit").
Until this bug gets fixed, here is an easy workaround:
Create a fake row in each table with contents like ("fake", 123, 123, 123, "fake"). Note how my fake contents match the "type" of the column to avoid confusing the column type detector. <tr class="fake_row"><td>fake</td><td>123</td></tr>
Add CSS styling to make the fake row not render:
tr.fake_row {
display: none;
}
This seems to work effectively, allowing tablesorter to initialize and run error-free and has no impact on the rendered output.
A more generic approach would be to override the tablesorter plugin itself to check for empty tables (until they fix the issue). See this post on overriding jquery core methods: http://www.bennadel.com/blog/1624-Ask-Ben-Overriding-Core-jQuery-Methods.htm
(function () {
// Store a reference to the original tablesorter plugin.
var originalTableSorter = jQuery.fn.tablesorter;
// Define overriding method.
jQuery.fn.tablesorter = function () {
if (this.find('tbody tr').size() == 0) {
if (typeof console != "undefined" && console.log) {
console.log('skipping tablesorter initialization - table is empty');
}
return;
}
// Execute the original method.
originalTableSorter.apply(this, arguments);
}
})();
This has been fixed in the lastest tablesorter (see issue 95).
Since overwriting plugins is always a bad idea, here's a different approach: If you just want to make sure your data table contains actual data rows, the jQuery selector :has() gets the job done, too.
$('table.tablesorter:has(tbody tr)').tablesorter({
// your tablesorter config here
});