How to make Angular ui grid expand all rows initially? - angularjs

I am using ui grid to show a list of data and I am trying to initially expand all rows.
I am trying to do this in the onRegisterApi event:
scope.GridOptions =
{
data: properties,
columnDefs:
[
{ name: "Full Address", field: "FullAddress" },
{ name: "Suburb", field: "Suburb" },
{ name: "Property Type", field: "PropertyType" },
{ name: "Price", field: "Price", cellFilter: 'currency'},
{ name: "Status", field: "Status" },
{ name: "Sale Type", field: "SaleType" },
{ name: "Date Created", field: "CreateDate", cellFilter: "date:'dd/MM/yyyy HH:mma'"}
],
expandableRowTemplate: 'template.html',
expandableRowHeight: 200,
onRegisterApi: (gridApi) =>
{
scope.gridApi = gridApi;
gridApi.expandable.on.rowExpandedStateChanged(scope,(row) =>
{
if (row.isExpanded) {
this.scope.GridOptions.expandableRowScope = row.entity;
}
});
gridApi.expandable.expandAllRows();
}
};
But the code above does not work. It looks like when I call expandAllRows() the rows are not rendered yet.

In my case, the following worked:
$scope.gridOptions = {
...
onRegisterApi: function(gridApi) {
$scope.gridApi = gridApi;
$scope.gridApi.grid.registerDataChangeCallback(function() {
$scope.gridApi.treeBase.expandAllRows();
});
}
};

I find I can expand all rows by using rowsRendered event:
gridApi.core.on.rowsRendered(scope,() => {
if (!gridApi.grid.expandable.expandedAll && !initialized)
{
gridApi.expandable.expandAllRows();
initialized = true;
}
});
I have used a variable initialized to identify if this is the first time rows are rendered as I only want to expand all rows initially.

None of the above worked for me for all of my grid use cases.
$scope.gridApi.grid.registerDataChangeCallback(function() {
if($scope.gridApi.grid.treeBase.tree instanceof Array){
$scope.gridApi.treeBase.expandAllRows();
}
});
The following works in every case I have tested. DataChangeCallback is called twice (for some unknown reason) on initial page load. The first time, gridApi.grid.treeBase.tree is an object which causes the issue with gridApi.grid.treeBase.tree.forEach above:

None of these answers worked for me, the following did:
scope.gridApi.core.on.rowsRendered(null, () => {
scope.gridApi.treeBase.expandAllRows();
});

The following worked for me, but no guarantee that it won't break anything... (looks good in my tests):
You need to change the source code, for example in ui-grid.js, i.e. the one your are deploying with your app:
In the addOrUseNode: function(...) inside the createTree: function(...) simply change COLLAPSED to EXPANDED for newNodes:
addOrUseNode: function (grid, row, parents, aggregationBase) {
...
var newNode = { state: uiGridTreeBaseConstants.EXPANDED, row: row, parentRow: null, aggregations: newAggregations, children: [] };
...
}
In module.service('uiGridTreeBaseService'... initializeGrid: function(grid) set grid.treeBase.expandAll from false to true (to let the tree know that all rows are expanded on initialitation)
[looks this is optional for the treeView]: Do the same In module.service('uiGridExpandableService', ['gridUtil', function (gridUtil) {...} in initializeGrid: function (grid). Change grid.expandable.expandedAll from false to true

Related

Ag-grid how to update a specific cell style after click

I use refreshCells to update a specific cell style after clicking on it. However, this does not work, and when I set refreshCells({ force: true }), the whole column updates new style that I don't want. Any suggestions please?
vm.gridOptions = {
columnDefs: vm.columnDefs,
rowData: vm.rows,
angularCompileRows: true,
defaultColDef: {
sortable: true,
resizable: true,
},
onCellClicked: onCellClicked,
onGridReady: function (params) {
}
}
function onCellClicked(params) {
const focusedCell = params.api.getFocusedCell();
focusedCell.column.colDef.cellStyle = { 'background-color': '#b7e4ff' };
params.api.refreshCells({
force: true // this updates the whole column, not only the clicked cell
});
}
I solved this by setting the specific rowNodes and columns.
function onCellClicked(params) {
const focusedCell = params.api.getFocusedCell();
const rowNode = params.api.getRowNode(focusedCell.rowIndex);
const column = focusedCell.column.colDef.field;
focusedCell.column.colDef.cellStyle = { 'background-color': '#b7e4ff' };
params.api.refreshCells({
force: true,
columns: [column],
rowNodes: [rowNode]
});
}

ExtJS 6 - Bind disabled property to new records in a store

I'm trying to enable/disable a button when the store getNewRecords() function return the length, but not work!
bind: {
disabled: "{!grid.getStore().getNewRecords().length}"
}
Fiddle: https://fiddle.sencha.com/fiddle/1sj5
Someone have idea to how resolve this?
You need to create a formula in your viewmodel:
viewModel: {
formulas: {
hasNewRecords: function (r) {
return this.getView().down("treepanel").getStore().getNewRecords().length > 0;
}
}
}
then you can use it for your bindings:
bind: {
disabled: "{hasNewRecords}"
}
(probably not the best way to get the data you want).
You can read about it here, here and here .
What you're wanting to do here is currently not possible in the framework. Instead, you should create a ViewModel data value and modify that where need be, like this:
var form = Ext.create("Ext.form.Panel", {
viewModel: {
data: {
newRecords: false
}
},
items: [{
xtype: "textfield",
labelField: "Add Child",
name: "col1",
value: "Teste 123"
}],
tbar: {
xtype: "button",
text: "Add new record",
handler: function () {
var data = this.up("form").getForm().getFieldValues();
var rec = grid.getStore().getAt(0);
data["treeCol"] = rec.childNodes.length + 1;
// setting value, so binding updates
this.lookupViewModel().set('newRecords', true);
rec.appendChild(data);
}
},
bbar: {
xtype: "button",
text: "button to disabled when new records",
bind: {
disabled: "{newRecords}"
}
},
renderTo: Ext.getBody()
});
Or by simply doing this.
In your controller:
me.getView().getViewModel().set('storeLen', store.getNewRecords().length);
In your ViewModel, simply do this:
formulas : {
hasNewRecords : {
get : function(get){
var length = get('storeLen') // --> gets the one you set at your controller
return length > 0 ? true : false;
}
}
}
In your View:
bind : {
disabled : '{hasNewRecords}'
}

Altering the class values or styles of cells in ui-grid

I have several unique cases inside ui-grid where the cells of certain table contents need additional class, or even style rules assigned, so the appearance for these cells stands out compared to others. Looking through the official ui-grid documentation I found that it could be done with cellTemplate, but I couldn't get any consistent results. What is the best approach here?
Below are the code changes I have attempted before, with the intent being to change the class name based on the returned value from a filter call made
//Define Grid Headings
$scope.scheduledPatientAppointments = [
{
field: 'appointment_date',
displayName: 'Appointment Date'
},
{
field: 'doctor_name',
displayName: 'Doctor Name'
},
{
field: 'procedure_type_eng',
displayName: 'Medical Procedure Type'
},
{
field: 'appointment_status_eng',
displayName: 'Appointment Status'
},
{
field: 'docs_received',
displayName: 'Related Documents',
cellTemplate: '<div class="ui-grid-cell-contents" ng-click="grid.appScope.loadDocumentsModal(\'{{row.entity.id}}\')">{{grid.getCellValue(row, col) | hasDocuments}}</div>',
cellFilter: 'hasDocuments',
cellClass: function(grid, row, col, rowRenderIndex, colRenderIndex) {
if (grid.getCellValue(row, col).toLowerCase() === 'missing') {
return 'missing';
} else if (grid.getCellValue(row, col).toLowerCase() === 'received') {
return 'received';
} else {
return 'undefined';
}
}
}
];
// Define Grid Options
$scope.PatientAppointmentsGrid = {
selectionRowHeaderWidth: 25,
enableHorizontalScrollbar: false,
rowHeight: 35,
enableSorting: true,
columnDefs: $scope.columnsPatient,
data: [],
onRegisterApi: function (gridApi) {
$scope.gridApi = gridApi;
}
};
//Behavior for patient page load
$scope.appointmentsProvider = patientsService.patientFactory.getAppointmentsForPatient($stateParams.id).then(
function successCallback(response) {
var preFetchData = response.data.data;
angular.forEach(preFetchData, function (value, key) {documentsService.documentsFactory.getDocumentsByAppointmentId(value.id).then(
function successCallback(response2) {
if (response2.data.length >= 1) {
//Append value state to the preFetchData object (count size)
var totalFiles = response2.data.length;
preFetchData[key].docs_received = totalFiles;
} else {
preFetchData[key].docs_received = 0;
}
}, function errorCallback(response2) {
console.debug("Error", response2);
});
});
$scope.PatientAppointmentsGrid.data = preFetchData;
},
function errorCallback(response) {
console.debug("Error", response);
});
The contents from the "Related Documents" are initally set to Missing (the original rest call returns nothing, and the filter call sets it to that. However, a later call actually loads associated documents per row, and I believe the inactivity of the grid on this particular call is what is causing no class to get set here.
Thoughts on the best approach here?
adding custom class with cellTemplate:
columnDefs: [
{
name:'firstName',
field: 'first-name',
// adding custom class
cellTemplate: "<div class=\"ui-grid-cell-contents custom-class\" title=\"TOOLTIP\">{{COL_FIELD CUSTOM_FILTERS}}</div>"
},
{ name:'1stFriend', field: 'friends[0]' },
{ name:'city', field: 'address.city'},
{ name:'getZip', field: 'getZip()', enableCellEdit:false}
],
.......
there are plenty of predefined customizable templates defined with $templateCache at the bottom of https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/3.2.9/ui-grid.js
adding custom style:
.......
onRegisterApi: function(gridApi){
//set gridApi on scope
$scope.gridApi = gridApi;
// adding custom style
gridApi.grid.registerStyleComputation({
func: function () {
return [
'.custom-class { ',
' color: red; ',
' font-weight: bold; ',
'} ',
'.ui-grid-row:nth-child(1) .custom-class { ',
' color: blue; ',
'} '
].join('\n');
}
});
}
plunker: http://plnkr.co/edit/YbnYoWLlEYzwmjuKOFa0?p=preview

Populate Kendo Grid with Angular model list

I have an Angular app that retrieves my data from the server and would like to use the results to populate a kendo grid. I have tried to create a kendo.data.DataSource but can not get the grid to populate. Below is what I am trying.
$scope.surchargeGridOptions = {
dataSource: {
pageSize: 15,
autoSync: true,
autoBind: false,
data: $scope.model.dataSource,
}
$scope.getWaivers = function () {
waiverService.getCustomers($scope.model.customer.CustomerID).then(function (result) {
$scope.model.waivers = result.data;
$scope.model.dataSource = new kendo.data.DataSource({
data: $scope.model.waivers,
});
$scope.model.dataSource.read();
});
};
Is it possible to do this and how should I go about it?
The data source object in your options has a data property that only requires a reference to a plain array, not an entire kendo data source.
You should use k-data-source to reference your data...
<kendo-grid k-data-source="myData"></kendo-grid>
... and you don't strictly need a kendo data source to get it working...
$scope.myData = [
{ name: 'a', number: 1 },
{ name: 'b', number: 1 },
{ name: 'c', number: 1 },
{ name: 'd', number: 1 }
];
.. If you have dynamic data then a kendo observable array would be best practice.
Here is a code pen example.
Front Html Page having Grid option
<div kendo-grid="ListGrid" options="ListOptions" k-rebind="ListOptions" class="k-grid-content-border"></div>
function GridColumn() {
return [{
field: 'name',
template: "<a ng-click='ToList(this.dataItem)' class='cursor-pointer'>{{this.dataItem.name}}</a>",
title: "",
footerTemplate: "Total",
width: 200,
locked: true,
}]}
$scope.ToGeo = function (item) {
$scope.dataLoded = false;
GetResults(function (res) {
$scope.ListOptions.dataSource = new kendo.data.DataSource({
data: res,
});
$scope.ListOptions.columns = GridColumn();
$scope.ListGrid.refresh();
$scope.dataLoded = true;
})
}
where GetResults is for API call and fetching data

angular-ui ng-grid How to make the aggregate row be an editable row

I think that what I'm trying to achieve is having a tree-like inside the ng-grid. I didn't found such an implementation but I'm wondering if I can use the grouping mechanism
I need to have the group header be editable in the same manner as the rows below it (see image above), with exactly the same editable cells, acting as a master row. When updating one cell from the header group should update all the cells beneath that group.
From ng-grid docs http://angular-ui.github.io/ng-grid/ :
default value for aggregateTemplate:
<div ng-click="row.toggleExpand()" ng-style="{'left': row.offsetleft}" class="ngAggregate">
<span class="ngAggregateText">{{row.label CUSTOM_FILTERS}} ({{row.totalChildren()}} {{AggItemsLabel}})</span>
<div class="{{row.aggClass()}}"></div>
</div>
Is it possible to use this option in order to render the aggregate row as I described?
The below answer/comment is related to tree like structure and not related to making aggregate row editable...
If you are looking for tree-like structure in ng-grid, then you could achieve that with the combination of ng-if, ng-click and API(s) that updates the ng-grid data option on click of a particular row. Here is a sample plnkr.
On click of a parent row, a toggle function is called to add/remove child rows in to the ng-grid data. (Refer to my plunker code for complete details)
$scope.toggleDisplay = function(iType) {
$scope.displayItemDetails[iType] = $scope.displayItemDetails[iType] ? 0 : 1;
$scope.selItems = $scope.updateTable();
};
$scope.updateTable = function() {
var selItems = [];
for (var i in $scope.allItems) {
var iType = $scope.allItems[i]["Type"];
if (angular.isUndefined($scope.displayItemDetails[iType])) {
$scope.displayItemDetails[iType] = 0;
}
if (1 == $scope.displayItemDetails[iType]) {
$scope.allItems[i]["Summary"] = '-';
} else {
$scope.allItems[i]["Summary"] = '+';
}
selItems.push($scope.allItems[i]);
if ($scope.displayItemDetails[iType]) {
for (var j in $scope.allItems[i]["Details"]) {
$scope.allItems[i]["Details"][j]["Summary"] = "";
selItems.push($scope.allItems[i]["Details"][j]);
}
}
}
return selItems;
};
$scope.gridOptions = {
data: 'selItems',
columnDefs: [{
field: 'Summary',
displayName: '',
cellTemplate: summaryCellTemplate,
width: 30
}, {
field: 'Name',
displayName: 'Name',
}, {
field: 'Type',
displayName: 'Type',
}, {
field: 'Cost',
displayName: 'Cost',
}, {
field: 'Quantity',
displayName: 'Quantity',
}],
enableCellSelection: false,
enableColumnResize: true
};

Resources