Suppose I know which row index to target (with this.rowToBeDeleted having a value of 2, say), how can I hide this row only from the grid but not the store (I have a flag in the store, which signifies what rows should be deleted from the db later in my PHP webservice code).
You can either use one of the store.filter() methods or you can hide the row element.
grid.getView().getRow(rowIndex).style.display = 'none';
I think it's much better though to just remove the record from the store and let the store update the view since you are deleting the record and not just hiding it. With the store in batch mode (the default: batch: true, restful: false), it will remember which rows you've removed and won't fire a request to the server until you call store.save().
I suggest using store.FilterBy() and pass a function to test the value of the value in rowToBedeleted:
store.filterBy(function(record) {
return record.get("rowToBeDeleted") != 2;
});
I wrote a basic blogpost about gridfiltering a while ago, you can read it here: http://aboutfrontend.com/extjs/extjs-grid-filter/
In ExtJS 4.1, there is no view.getRow(..). Instead you can use:
this.view.addRowCls(index, 'hidden');
to hide the row at the specified index, and
this.view.removeRowCls(index, 'hidden');
to show it (where 'this' is the grid).
CSS class hidden is defined as
.hidden,
{
display: none;
}
This is useful for peculiar scenarious where store.filterBy() is not appropriate.
In the grid js file write following code to apply a CSS to those rows which you want to hide.
<pre><code>
Ext.define('MyGrid',{
extend : 'Ext.grid.Panel',
xtype : ''mygrid',
viewConfig : {
getRowClass : function(record,id){
if(record.get('rowToBeDeleted') == 2){
return 'hide-row';
}
}
},
.................
.................
});
</code></pre>
Now define a custom CSS in custom.css file:
.hide-row{display:none}
This will hide rows in grid without removing or filtering from store.
You can use the store.filter() or store.filterBy() methods for that.
Set a "hidden" property on your records and the filter all records that have hidden set to true for example. This way they'll still be present in the store but not visible in the grid.
Related
I'm wondering if there's a way to select the "Grouping" row in ag-grid.
For example, in the example shown on the website:
http://www.ag-grid.com/angular-grid-grouping/index.php
You can set the "rowSelection" parameter to "single" in order to highlight an entire row at the lowest node. However, that does not allow you to highlight the "Country" row.
In the example, the only way to do this is to "select all" the elements below that row.
Thanks!
According to the documentation, setting the grid option groupSelectsChildren to false will make the grouping row selectable, independently from its children.
groupSelectsChildren: When true, selecting a group will have the
impact of selecting all it's children. The group will then display
'selected' when all children are selected, 'unselected' when none are
selected and 'intermediate' when children have a mix of selected and
unselected. When the node is selecting children, it will never appear
in the selected set when calling api.getSelectedNodes(). When false,
then the group is selectable independently of the child nodes. When
selecting the group node independently of the children, it will appear
in the set when calling api.getSelectedNodes().
I had the same problem so I worked around it by emulating the look-and-feel of selecting rows.
In your columnDefs object, add the cellClassRules attribute to EVERY column definition (so every cell will be highlighted, making it appear that the row itself is highlighted when you click on it):
var columnDefs = [
{ headerName: "#1", cellClassRules: { rowSelected: CustomRowStyle }, field: "Col1" },
{ headerName: "#2", cellClassRules: { rowSelected: CustomRowStyle }, field: "Col2" },
{ headerName: "#3", cellClassRules: { rowSelected: CustomRowStyle }, field: "Col3" }
]
Then add an event listener for onCellClicked in your gridOptions object:
onCellClicked: function(cell) {
SelectedRowIndex = cell.rowIndex;
$scope.gridOptions.api.refreshView();
}
In your controller, define a variable called SelectedRowIndex:
var SelectedRowIndex; // this will contain the currently selected row number
Now create a function called CustomRowStyle which is called by ag-grid each time it is about to render a cell on-screen. This function will check if the cell is in the same row as the SelectedRowIndex (based on which row the user last clicked on) to determine if the cell should appear with the rowSelected class.
function CustomRowStyle(params) {
return params.rowIndex === SelectedRowIndex
}
Finally, define a rowSelected class with your selected row CSS:
.rowSelected {
background-color: silver !important;
}
Whichever row you click on (whether it's a group item or a child item) will appear with the rowSelected CSS. Your controller can always know which row is currently selected by checking the SelectedRowIndex variable.
This probably won't work for all cases but I found that as of version 20.2.0 RowNode's have a 'parent' property (Note: I'm not saying that feature was added in 20.2.0, just that I haven't gone and checked previous versions). So I do this:
api.getRowNode('child-row-id').parent.setSelected(true)
Obviously depending on how many levels of grouping you have and how dynamic that is (i.e. can the user change the grouping configuration, can you have n levels of grouping, etc.) you'll need to detect and adjust, but this works well for my particular use case of remembering what was selected and reselecting it on page refresh because my grid always starts out in the same grouping state on page load.
set groupSelectsChildren={false} and use this code onRowClicked={this.onRowClicked}
use any unique data identifier for selecting the node.
onRowClicked = (row) =>{
let that = this;
this.gridApi.forEachNode(node =>{
if(node.data.id === row.data.id) { that.gridApi.selectNode(node,true);}
});
}
ui-grid's expandable row feature works great if every parent row has the same number of subrows in its subGrid, and therefore the same height. Not so great if the number of subrows in the subGrid varies from row-to-row of the parent.
I've been able to get the subGrid ITSELF to have a dynamic height by passing in the array length and using that to generate a subGrid-height:
lengthOfList: data[i].friends.length
style="height:{{row.entity.subGridOptions.lengthOfList * 30}}px;
But since that subGrid has to live WITHIN the parent grid, the parent grid needs to push its rows down to make room. And it needs to do so by a different amonut for each row. Unfortunately the parent grid has a single, fixed expandableRowHeight for ALL rows. I can't specify the expandableRowHeight for EACH row.
Best I can hope for is to alter the expandableRowHeight on-the-fly, as I click on a row to open it.
Trying to figure out how to listen for the open expandable row event.
ui-grid is a shrink-wrapped plugin that writes it own DOM elements, so I have no way of adding anything to the elements that might help me capture events on them.
How can I configure the expandableRowHeight on-the-fly?
Plunker:
http://plnkr.co/edit/1IeEsXZAf9pRgKmy5jfO?p=preview
(The plunker is misbehaving. 1] A font that ui-grid is using is now blocked due to cross-domain issues, 2] sometimes the html template goes AWOL for no discernible reason.)
Ah. I found the gridApi. So this solution works!
$scope.gridOptions = {
onRegisterApi: function(gridApi) {
gridApi.expandable.on.rowExpandedStateChanged($scope,function(row){
$scope.gridOptions.expandableRowHeight = row.entity.mySubRowItems.length * 30;
});
}
}
I'm sure there's a way of referring to the row's parent grid directly. Instead of $scope.gridOptions, there's surely some row $parent reference, I just haven't found it yet.
As an update for 3.0.0 stable there is a rowExpandedBeforeStateChanged event. If you use rowExpandedStateChanged then your grid won't update w/ the new expandableRowHeight you're trying to set.
$scope.gridOptions.onRegisterApi = function(gridApi) {
// dynamic expandable rows
gridApi.expandable.on.rowExpandedBeforeStateChanged($scope, function(row) {
$scope.gridOptions.expandableRowHeight = 30 + row.entity.valueArray.length * 30;
});
};
Finally got this sorted, the important thing to know is that the expandable row has a row height, and a sub (expandable) grid size height inside that row, so if you need to display the grid to fit exactly inside the row, you need to set both heights to the same dynamic size.
Inside your top level grid api you need to specify :
$scope.gridOptions = {
onRegisterApi: function(gridApi) {
gridApi.expandable.on.rowExpandedStateChanged($scope, function (row) {
row.expandedRowHeight = (row.entity.subGridOptions.data.length * rowHeight) + headerHeight;
});
});
}
}
but now u use the expandedRowHeight variable from ui-grid version 3.0.0+, not available in 2+, the expandableRowHeight does not seem to have any affect, but might be used to set the global value for expandedRowHeight. (Note the different naming of these 2 variables on the grid)
Now this will size your top Grid row to display your sub grid correctly.
In the expandableRowTemplate.html for the sub grid u need to specify the height dynamically of the sub grid using the css style:
<div ui-grid="row.entity.subGridOptions" style="height:{{(row.entity.subGridOptions.data.length * rowHeight) + headerHeight}}px" ui-grid-auto-resize></div>
this works very well for me currently, and might help someone out there.
Note that it could also help to investigate the ui-grid-autoresize directive now in ui-grid 3+, apparently this helps in accomplishing this, not 100% sure if I used it correctly, but it works
This is how it works, I checked other people's solution, they all not working
Let's assume that the headerRowHeight is 39px.
The template should be something like this :
'<div ui-grid="row.entity.subGridOptions" ng-style="{height: (row.entity.youList.length * row.entity.subGridOptions.rowHeight) + 39 + \'px\'}" ui-grid-selection ui-grid-edit ui-grid-cellnav ui-grid-validate ui-grid-auto-resize ui-grid-resize-columns></div>'
The rowExpandedStateChanged should be this:
gridApi.expandable.on.rowExpandedStateChanged($scope, function (row) {
$timeout(function() {
row.expandedRowHeight = row.entity.youList.length * row.entity.subGridOptions.rowHeight + 39;
}, 150);
});
I tried a different approach to the solution using CSS alone instead of leveraging the "expandableRowHeight" property. And this worked for me.
The parent grid data is rendered inside a div with class name "ui-grid-canvas". Add the following style -
.ui-grid-canvas{
height: auto !important;
overflow: auto !important;
}
For expanded child table, add a style to div with class name "expandableRow"
.expandableRow{
height: auto !important;
}
Also, do not set the "expandableRowHeight" property in gridOptions.
I have a following grid defined in my View
<div class="gridStyle hide" ng-grid="resultsOptions" id="resultsGrid"></div>
And I want to allow multiSelect only if a ctrl key is pressed. So I define multiSelect attribute as false in the Controller.
$scope.resultsOptions = {
data: 'searchData',
selectedItems: $scope.mySelections,
multiSelect: false,
enableHighlighting: true,
enableRowSelection: true
};
In the same controller I have the following code that sets multiSelect to true.
$("#resultsGrid").keydown(function (e) {
if (e.ctrlKey) {
$scope.resultsOptions.multiSelect = true;
$scope.$apply();
}
});
When I launch the application multiSelect value changes after pressing ctrl. But I am still can not make a multiple selection.
I tried to use variable for multiSelect, but it doe not change a thing.
The following example also does not change multiSelect attribute. But it changes the grid header.
http://plnkr.co/edit/RwYSG4?p=preview
Is there any simple solution? Or what do I miss in my code?
The approved "hacky" answer wasn't clean enough for us so we built a slightly more robust version relying on the event parameter on beforeSelectionChange instead of doing nasty key bindings.
This also works for any grid you add this event callback to as it does not need to reference any specific custom CSS classes or IDs, but just uses reliable ng-grid classes.
beforeSelectionChange: function(rowItem, event){
if(!event.ctrlKey && !event.shiftKey && $scope.multiSelect &&
!$(event.srcElement).is(".ngSelectionCheckbox"))
{
angular.forEach($scope.myData, function(data, index){
$scope.gridOptions.selectRow(index, false);
});
}
return true;
}
What this does is simply checking if we are doing a multiselect operation (holding ctrl key, shift key or using the multiselect checkbox), if yes, let multiselect happen.
If the user is just clicking anywhere else on a row, and multiselect is active we remove any current selection so just the one target row will be selected afterwards.
Since it is impossible to change some grid options on the fly
(https://github.com/angular-ui/ng-grid/issues/386). I decided to manually deselect every element if ctrl is not pressed in beforeSelectionChange attribute of the grid.
The solution is durty, but it works.
Based of mabi's comment...
Without support for Shift key
With support for Shift key
I have an extjs combobox used for auto-complete having following configuration:
xtype:'combo',
displayField: 'name',
valueField:'id',
store: storeVar,
queryMode: 'remote',
minChars:2,
hideTrigger:true,
forceSelection:true,
typeAhead:true
There are two issues being faced by me:
a. If a user chooses a value from the list returned from server, but later wants to remove that value and keep combo-box empty, then also the old values re-appears on blur, not allowing combo-box to remain empty. How can I allow empty value in this combo-box in such a case? I understand it could be due to forceSelection:true, but then I need to keep it true as otherwise user can type any random value.
b. When the server returns an empty list, I want to display a message - No Values Found. I tried doing this, by putting this value in the displayField entity, i.e., {id:'', name:'No Value Found'}. But then in this case, the user is able to choose this value and send it to server which is not what is expected. Thus, how can I display the message for empty list?
Could someone please throw light on this?
For the issue related to forceSelection in the question above, following is the hack created which can serve the expected purpose:
Ext.override(Ext.form.field.ComboBox,{
assertValue: function() {
var me = this,
value = me.getRawValue(),
rec;
if (me.multiSelect) {
// For multiselect, check that the current displayed value matches the current
// selection, if it does not then revert to the most recent selection.
if (value !== me.getDisplayValue()) {
me.setValue(me.lastSelection);
}
} else {
// For single-select, match the displayed value to a record and select it,
// if it does not match a record then revert to the most recent selection.
rec = me.findRecordByDisplay(value);
if (rec) {
me.select(rec);
} else {
if(!value){
me.setValue('');
}else{
me.setValue(me.lastSelection);
}
}
}
me.collapse();
}
});
This needs to be included after library files of extjs have been included.
For the other issue of message to be shown at No Values Found - emptyText - works fine as suggested by Varun.
Hope this helps somone looking for something similar.
I've done this for Ext JS 3.3.1. I don't know if they apply to Ext JS 4, though I guess they should.
For the first problem, set autoSelect : false. autoSelect is by default set to true. This will work only if allowBlank : true is set. From the docs
true to select the first result gathered by the data store (defaults
to true). A false value would require a manual selection from the
dropdown list to set the components value unless the value of
(typeAheadDelay) were true.
For the second problem, use listEmptyText. From the docs
The empty text to display in the data view if no items are found.
(defaults to '')
Cheers.
I have a two questions:
How to set first row in ExtJs gridpanel as selected and
How to write separate JS file for custom validations for phone nos and datefields and etc
Thanks in advance
Assuming you have an instance of your grid, you can select the row using selectFirstRow(). Here is the sample code:
grid.getSelectionModel().selectFirstRow();
You can move your custom validations to another file. All you need to move your
Ext.apply(Ext.form.VTypes, {
daterange : function(val, field) {
var date = field.parseDate(val);
...
}
});
to separate file. and ensure that the js file is included.
try this to select first row in grid :
Ext.getCmp('grid').getSelectionModel().selectRow(0);