I'm setting the selection of my ngGrid from JavaScript, calling gridOptions.selectItem(). I have multiSelect set to false, so there is only ever one row selected. I'd like the ngGrid to automatically scroll to show the newly selected row, but I don't know how to do this: can anyone help, please?
On a related topic: can I disable row selection by mouse click? If so, how?
Edited to add
I'd also like to disable keyboard navigation of the selected row, if possible.
What worked:
AardVark71's answer worked. I discovered that ngGrid defines a property ngGrid on the gridOptions variable which holds a reference to the grid object itself. The necessary functions are exposed via properties of this object:
$scope.gridOptions.selectItem(itemNumber, true);
$scope.gridOptions.ngGrid.$viewport.scrollTop(Math.max(0, (itemNumber - 6))*$scope.gridOptions.ngGrid.config.rowHeight);
My grid is fixed at 13 rows high, and my logic attempts to make the selected row appear in the middle of the grid.
I'd still like to disable mouse & keyboard changes to the selection, if possible.
What also worked:
This is probably closer to the 'Angular Way' and achieves the same end:
// This $watch scrolls the ngGrid to show a newly-selected row as close to the middle row as possible
$scope.$watch('gridOptions.ngGrid.config.selectedItems', function (newValue, oldValue, scope) {
if (newValue != oldValue && newValue.length > 0) {
var rowIndex = scope.gridOptions.ngGrid.data.indexOf(newValue[0]);
scope.gridOptions.ngGrid.$viewport.scrollTop(Math.max(0, (rowIndex - 6))*scope.gridOptions.ngGrid.config.rowHeight);
}
}, true);
although the effect when a row is selected by clicking on it can be a bit disconcerting.
It sounds like you can make use of the scrollTop method for the scrolling.
See also http://github.com/angular-ui/ng-grid/issues/183 and the following plunker from #bryan-watts http://plnkr.co/edit/oyIlX9?p=preview
An example how this could work would be as follows:
function focusRow(rowToSelect) {
$scope.gridOptions.selectItem(rowToSelect, true);
var grid = $scope.gridOptions.ngGrid;
grid.$viewport.scrollTop(grid.rowMap[rowToSelect] * grid.config.rowHeight);
}
edit:
For the second part of your question "disabling the mouse and keyboard events of the selected rows" it might be best to start a new Question. Sounds like you want to set your enableRowSelection dynamically to false? No idea if that's possible.
I believe I was looking for the same behavior from ng-grid as yourself. The following function added to your gridOptions object will both disallow selection via the arrow keys (but allow it if shift or ctrl is held down) and scroll the window when moving down the list using the arrow keys so that the currently selected row is always visible:
beforeSelectionChange: function(rowItem, event){
if(!event.ctrlKey && !event.shiftKey && event.type != 'click'){
var grid = $scope.gridOptions.ngGrid;
grid.$viewport.scrollTop(rowItem.offsetTop - (grid.config.rowHeight * 2));
angular.forEach($scope.myData, function(data, index){
$scope.gridOptions.selectRow(index, false);
});
}
return true;
},
edit: here is a plunkr:
http://plnkr.co/edit/xsY6W9u7meZsTJn4p1to?p=preview
Hope that helps!
I found the accepted answer above is not working with the latest version of ui-grid (v4.0.4 - 2017-04-04).
Here is the code I use:
$scope.gridApi.core.scrollTo(vm.gridOptions.data[indexToSelect]);
In gripOptions, you need to register the gridApi in onRegisterApi.
onRegisterApi: function (gridApi) {
$scope.gridApi = gridApi;
},
var grid = $scope.gridOptions.ngGrid;
var aggRowOffsetTop = 0;
var containerHeight = $(".gridStyle").height() - 40;
angular.forEach(grid.rowFactory.parsedData, function(row) {
if(row.entity.isAggRow) {
aggRowOffsetTop = row.offsetTop;
}
if(row.entity.id == $scope.selectedId) {
if((row.offsetTop - aggRowOffsetTop) < containerHeight) {
grid.$viewport.scrollTop(aggRowOffsetTop);
} else {
grid.$viewport.scrollTop(row.offsetTop);
}
}
});
Related
I encountered this bug where the column filter is incorrect if the grid has a locked column
Here's the fiddle: sencha fillde
Steps to reproduce:
(Do not apply any filter)
Open the "Email" column menu
Open "Name" column menu (this is the locked column)
Open "Phone" column menu (notice that the filter menu is incorrect, it is showing the filter for "Email" column).
For grid that has no 'locked' columns the filter menu is working fine, thanks for anyone who can help!
Okay, this one was a bit tricky. It turns out that for a locked grid, the Ext.grid.filters.Filters:onMenuCreate gets hit twice... one for each side of the grid's menu that shows. The problem is that in the onMenuCreate, the framework doesn't account for the 2 menus. It only cares about the last menu that gets created and destroys the previous menu's listeners. In onMenuBeforeShow, the framework does account for each side of the grid, so I extended this idea into an override. I would encourage you to create a Sencha Support ticket for this, and if you don't have access, let me know, so I can submit one. Fiddle here.
Ext.override(Ext.grid.filters.Filters, {
onMenuCreate: function (headerCt, menu) {
var me = this;
// TODO: OLD BAD CODE... this would destroy the first menu's listeners
// if (me.headerMenuListeners) {
// Ext.destroy(me.headerMenuListeners);
// me.headerMenuListeners = null;
// }
// me.headerMenuListeners = menu.on({
// beforeshow: me.onMenuBeforeShow,
// destroyable: true,
// scope: me
// });
// Just like in the onMenuBeforeShow, we need to create a hash of our menus
// and their listeners... if we don't, we remove the 1st menu's listeners
// when the 2nd menu is created
if (!me.headerMenuListeners) {
me.headerMenuListeners = {};
}
var parentTableId = headerCt.ownerCt.id;
var menuListener = me.headerMenuListeners[parentTableId];
if (menuListener) {
Ext.destroy(menuListener);
me.headerMenuListeners[parentTableId] = null;
}
me.headerMenuListeners[parentTableId] = menu.on({
beforeshow: me.onMenuBeforeShow,
destroyable: true,
scope: me
});
},
destroy: function () {
var me = this,
filterMenuItem = me.filterMenuItem,
item;
// TODO: ADDING THIS AND REMOVING FROM THE Ext.destroy on the next line
var headerMenuListeners = this.headerMenuListeners;
Ext.destroy(me.headerCtListeners, me.gridListeners);
me.bindStore(null);
me.sep = Ext.destroy(me.sep);
for (item in filterMenuItem) {
filterMenuItem[item].destroy();
}
// TODO: ADDING THIS AND REMOVING FROM THE Ext.destroy on the next line
for (item in headerMenuListeners) {
headerMenuListeners[item].destroy();
}
this.callParent();
}
});
i try to get the the value of number row selected, and print it in HTML using Angularjs, but no issue,
i have the count only when i clic in the grid column header.
The value of " selectedRowsCounter " is 0 in html, when i dosn't clic in the grid header
my code is like
var activeButtons = function() {
var countRowsSelected = $scope.gridOptions.api.getSelectedRows().length;
$scope.selectedRowsCounter = countRowsSelected;
console.log($scope.selectedRowsCounter);
$rootScope.count.selectedRows = countRowsSelected;
};
$scope.gridOptions = {
rowData: null,
angularCompileRows: true,
onSelectionChanged: activeButtons,
}
there is a screenshot
i have open the same subject here
https://github.com/ceolter/ag-grid/issues/1023
i have added this line to activeButtons function and it work fine
$scope.gridOptions.api.refreshView();
i dont knew if there is a good solution, but that work for now
The problem seems to be with Angular being unaware of the $scope property change because ag-grid does not tell Angular that it has modified something in the $scope. Although it is difficult to tell if you don't show your view.
You can use onSelectionChanged the way you are using it to know how many rows have been selected, but you need to tell Angular that something has changed in its $scope by applying it.
Something like this:
var activeButtons = function() {
var countRowsSelected = $scope.gridOptions.api.getSelectedRows().length;
$scope.selectedRowsCounter = countRowsSelected;
console.log($scope.selectedRowsCounter);
$rootScope.count.selectedRows = countRowsSelected;
window.setTimeout(function() {
this.$scope.$apply();
});
};
That way you can apply the $scope and the html view will reflect the changes.
I need to set selection to a newly added row.
When $scope.gridApi.selection.selectRow(newObject) is entered, the grid's row model does not have the new row and thus can not select it.
After method addRow is finished, the grid shows the new row (and the data) but no selection was made.
My test code:
$scope.addRow = function() {
$scope.gridOptions.data.unshift({
// my new data object
});
var newObject = $scope.gridOptions.data[0];
$scope.gridApi.selection.selectRow(newObject);
};
How can I achieve this behavior?
Is there an event like 'rowAdded' in angularjs ui-grid I have to listen to?
Is there anywhere a comprehensive list of events fired by ui-grid?
Thanks for help!
You can event listeners on row, column and so on. The documentation is here http://ui-grid.info/docs/#/api/ui.grid.class:Grid
You can add the data listener in onRegisterApi like below,
onRegisterApi : function(gridApi)
{
if(!$scope.gridApi)
{
$scope.gridApi = gridApi;
$scope.gridApi.grid.registerDataChangeCallback(function(data)
{
$scope.gridApi.selection.selectRow($scope.gridOptions.data[0]);
}, [uiGridConstants.dataChange.ROW]);
}
}
and select any row you want to select.
Here is a working plnkr. http://plnkr.co/edit/NjnMb65w86L0bKmkkJp0?p=preview
How do I reset my ExtJS filters in my grids. More specifically, how do I get the header to honour the changes to the filtering.
ie. This works fine :
grid.store.clearFilter();
But the header rendering is all wrong. I need to get into all the menu objects and unselect the checkboxes.
I am getting pretty lost. I am pretty sure this gives me the filterItems :
var filterItems = grid.filters.filters.items;
And from each of these filter items, i can get to menu items like so :
var menuItems = filter.menu.items;
But that's as far as I can get. I am expecting some kind of checkbox object inside menu items, and then I can uncheck that checkbox, and hopefully the header rendering will then change.
UPDATE :
I now have this code. The grid store has its filter cleared. Next I get the filterItems from grid.filters.filters.items and iterate over them. Then I call a function on each of the menu items.
grid.store.clearFilter();
var filterItems = grid.filters.filters.items;
for (var i = 0; i<filterItems.length; i++){
var filter = filterItems[i];
filter.menu.items.each(function(checkbox) {
if (checkbox.setChecked)
checkbox.setChecked(false, true);
});
}
The checkboxes do get called, but still nothing is happening :(
Try this code:
grid.filters.clearFilters();
This should take care of both the grid and its underlying store.
When you do
grid.store.clearFilter();
it can only clear the filters on the store but the grid's view doesn't get updated with that call. Hence to handle it automatically for both the grid's view as well as the grid's store, just use
grid.filters.clearFilters();
Hope it helps!
Cheers!
Your update help me but you forget the case where you have input text instead of checkbox.
So this is my addition of your solution:
grid.filters.clearFilters();
var filterItems = grid.filters.filters.items;
for (var i = 0; i<filterItems.length; i++){
var filter = filterItems[i];
filter.menu.items.each(function(element) {
if (element.setChecked) {
element.setChecked(false, true);
}
if(typeof element.getValue !== "undefined" && element.getValue() !== "") {
element.setValue("");
}
});
}
When you use grid wiht gridfilters plugin
and inovoke
grid.filters.clearFilters();
it reset applyed filters, but it don't clean value in textfield inside menu.
For clean textfield text you can try this:
grid.filters.clearFilters();
const plugin = grid.getPlugin('gridfilters');
let activeFilter;
if('activeFilterMenuItem' in plugin) {
activeFilter = plugin.activeFilterMenuItem.activeFilter
}
if (activeFilter && activeFilter.type === "string") {
activeFilter.setValue("");
}
I have a table grid in Ext Js with a selection.CheckboxModel
I can multi select items in the grid, but it seems like also right click can select items
The question is is there any way to remove right click so it does not select item/s?
Thanks in advance,
Bob
To prevent selection with rigth button you can use this code (with Ext JS 4)...
var allowSelection=true;
...
grid.on('beforeitemmousedown', function(grid, record, item, index, event, eOpts) {
if (event.button==0) allowStreetSelection=true; else allowSelection=false;
});
grid.on('beforeselect', function(grid, record, index, eOpts) {
return allowSelection;
});
To stop the context menu, you can catch the rowcontextmenu event and stop it.
grid.on('rowcontextmenu', function(grid,index,e) { e.stopEvent() });
This may also solve your row selection issue but right-click doesn't select rows for me. What version of ExtJS are you using and on which browsers do you see this problem? On ExtJS 3.3 and Firefox 4 and IE 8-9 I can't reproduce it.
Edit: For Ext 4, containercontextmenu looks to be the event to catch. Returning false from that handler should stop the context menu from appearing. I don't have much experience with Ext 4, so let me know if it works for you.
This worked like a charm for me (EXTJS 4.1.2):
grid.on('beforeitemmousedown', function(grid, record, item, index, event, eOpts) {
return (event.button == 0);
});
We've also met the same problem while using ExtJS4, our solution for now is to modify the original code in extJS.
Find:
} else if (me.isSelected(record) && !e.shiftKey
&& !e.ctrlKey && me.selected.getCount() > 1)
{
me.doSelect(record, keepExisting, false);
You can find them in ext-all.js or in src/selection/Model.js
And change it to:
} else if (me.isSelected(record) && !e.shiftKey && !e.ctrlKey && me.selected.getCount() > 1) {
if (e.button != 0)
keepExisting = true;
else
keepExisting = false;
me.doSelect(record, keepExisting, false);
This code will prevent clear current item selections except u're clicking the item with mouse button 0 (left button).