AG-Grid Master Detail Can not See Detail Rows - javascript

In my code, I am using AG-Grid with the master detail property to display some data. The code doesn't get any errors and the master row has records, but when I expand the detail, not 1 row is present even though in the network, params.data has values. My code is below. What am I doing wrong, and how should I fix it?
constructor(
private _reportService: ReportService,
) {
this._reportService
.getAllSupplierProductList()
.subscribe((response: any) => {
this.rowData = response;
});
}
public detailCellRendererParams: any = {
detailGridOptions: {
columnDefs: [
{ headerName: 'Ürün Kodu', field: 'StockIntegrationCode' },
{ headerName: 'Ürün Adı', field: 'ProductName' },
{ headerName: 'Ürün Kategorisi', field: 'CategoryName' },
],
defaultColDef: {
flex: 1,
filter: 'agTextColumnFilter',
resizable: true,
sortable: true,
floatingFilter: true,
},
},
getDetailRowData: (params) => {
params.successCallback(params.data.StockIntegrationCode && params.data.ProductName && params.data.CategoryName);
},
} as IDetailCellRendererParams;
rowData: Observable<IReportRow[]>;
onFirstDataRendered(params: FirstDataRenderedEvent) {
// arbitrarily expand a row for presentational purposes
setTimeout(function () {
params.api.getDisplayedRowAtIndex(1)!.setExpanded(true);
}, 0);
}
onGridReady(params: GridReadyEvent) {
}

In the getDetailRowData function, you're given params.data, which is the data of the master row. You should obtain details and pass it to the params.successCallback function like this:
getDetailRowData: (params) => {
this._reportService
.getProductList(params.data.SupplierId)
.subscribe(products => {
params.successCallback(products);
});
}

Related

VueGoodTable filter dropdown options vue2

I'm trying to populate possible dropdown options on vue good table. The idea is that I conduct an API call to the server to bring back what values can possibly go into the drop down and I'm trying to assign it to the column filter. However, I can't seem to get it to work.
<vue-good-table
:paginationOptions="paginationOptions"
:sort-options="sortOptions"
:isLoading.sync="isTableLoading"
:rows="rows"
:columns="columns"
:lineNumbers="true"
mode="remote"
:totalRows="totalRecords"
#on-row-click="onRowClick"
#on-page-change="onPageChange"
#on-sort-change="onSortChange"
#on-column-filter="onColumnFilter"
#on-per-page-change="onPerPageChange"
#on-search="onSearch"
:search-options="{
enabled: true
}"
styleClass="vgt-table striped bordered"
ref="table"
>
Fairly standard vgt set up.
columns: [
{
label: 'some column',
field: 'column1'
},
{
label: 'Customer',
field: 'customerName',
filterOptions: {
enabled: true,
placeholder: 'All',
filterDropdownItems: Object.values(this.customers)
}
},
{
label: 'other columns',
field: 'column234'
}
]
and the API call
methods: {
async load () {
await this.getTableOptions()
},
async getTableOptions () {
try {
var response = await axios.get(APICallUrl)
this.customers= []
for (var i = 0; i < response.data.customers.length; i++) {
this.customers.push({ value: response.data.customers[i].customerId, text: response.data.customers[i].customerName})
}
} catch (e) {
console.log('e', e)
}
}
The only thing that I thought of is that the table has finished rendering before the load method is complete. However just creating a static object in my data and assigning it to a filterDropDownItems yielded no better results. The result whenever I try to set it to an object is that the box is a type-in box rather than a dropdown.
You can make the table update after it's rendered by making columns a computed property. The other problem you have is this.customers is an Array but Object.values() expects an Object. You could use the Array.map function instead
this.customers.map(c => c.value)
Although according to the VueGoodTable docs an array of objects like you have should work just fine
computed: {
columns() {
return [
{
label: 'some column',
field: 'column1'
},
{
label: 'Customer',
field: 'customerName',
filterOptions: {
enabled: true,
placeholder: 'All',
filterDropdownItems: this.customers
}
},
{
label: 'other columns',
field: 'column234'
}
];
}
}

Datatable without action buttons (javascript)

I'm having problems putting some actions buttons in mdbootstrap datatable
I'm following their example but without fetching data and i need to fetch data from my database
The records are present but the buttons no and i need them to get the results i need
This is my javascript code
$(document).ready(function () {
const customDatatable = document.getElementById('datatable-custom');
const columns = [
{ label: 'ID', field: 'idAtividade', width: 25 },
{ label: 'Atividade', field: 'atividade', width: 175 },
{ label: 'Projeto', field: 'nome', width: 150 },
{ label: 'Aulas', field: 'haveClasses', width: 25 },
{ label: 'Orçamento', field: 'orcamento', width: 25 },
{ label: 'Data', field: 'dataAtividade', width: 100 },
{ label: 'Hora', field: 'hora', width: 50 },
{ label: 'Local', field: 'local', width: 150 },
{ label:'Opções', field: '',sort: false }
];
const rows = [
fetch('./controllers/Atividades.php?type=listar')
.then((data) => data.json())
.then((data) => {
const parser = new DataParser('datatable', {
rows: {start: 30, end: 100},
keys: columns.map((column) => column.field),
});
const { rows } = parser.parse(data);
datatableInstance.update({ rows }, { loading: false });
}),
];
const setActions = () => {
document.getElementsByClassName('call-btn').forEach(btn => {
btn.addEventListener('click', () => {
console.log(`call ${btn.attributes['data-mdb-number'].value}`)
})
})
document.getElementsByClassName('message-btn').forEach(btn => {
btn.addEventListener('click', () => {
console.log(`send a message to ${btn.attributes['data-mdb-email'].value}`)
})
})
};
customDatatable.addEventListener('render.mdb.datatable', setActions);
const datatableInstance = new mdb.Datatable(customDatatable,
{ columns },{
rows: [
rows
].map((row) => {
console.log("aqui");
return {
...row,
contact: `<button class="call-btn btn btn-outline-primary btn-floating btn-sm" data-mdb-number="${row.phone}"><i class="fa fa-phone"></i></button>
<button class="message-btn btn ms-2 btn-primary btn-floating btn-sm" data-mdb-email="${row.email}"><i class="fa fa-envelope"></i></button>`,
};
}),
},
{ hover: true });
});
And this is what i get
Image of my datatable
i think you're doing this with wrong way, you basically can use datatable feature to solve your problem. you want to fetch data from database and draw the data to the table with custom button in it, isnt it?
alright here is how i do it
1.Lets make your table, i prefer to define my initial table directly by html
<table id="datatable-custom" class="table">
<thead>
<th>ID</th>
<th>Atividade</th>
<th>Projeto</th>
<th>Aulas</>
<th>Orçamento</th>
<th>Data</th>
<th>Hora</th>
<th>Local</th>
<th>Opções</th>
</thead>
<tbody></tbody>
</table>
just leave blank
2.initialize the table
const customDatatable = document.getElementById('datatable-custom')
customDatatable.DataTable({
ordering: false,
responsive: true,
autoWidth: false,
rowId: 'key',
ajax: {
url:'http://yourapi.com'
dataSrc: ''
},
columns: [
{data:'your_object_data_key'}
...,
{
data: function(row){
return `<button data-id="${row.your_key_id}">your custom button</button>`
}
}
columnDefs: [{
targets: 8,
data: null,
defaultContent: `<button class="btn btn-info"><i class="fas fa-edit"></i></button>`
}],
})
Note :
if you want to pass your data to the button for each row data, then the data: function(row){...} can be used for that, the data will be passed through the ${row.key},
but if you don't pass any data to the button you can use the columnDefs and delete the part of data: function(row){...}. the targets: 8 that i assume that you will put the button at the column "Opções" since the column index is 8. you can define yourself where this button will be put
The dataSrc is defining the object that will be used to the table, if your object data cantains ex.
Example response data from your database api
{
msg_status:true,
msg_body:[{
key1:"data",
key2:"data"
}]
}
So you can use dataSrc: "msg_body"
Let me know if this works for you

CellValueChanged event in master detail of ag-grid

I am developing an ag-grid with master-detail set to true, the first row of master-detail has a editable cell i.e. "contractID", I want to populate other cells of the master-detail depending upon the fetched contractID.
I tried adding cellValueChanged in the columnDef and also tried to set params.api.rowModel.gridApi.cellValueChanged explicitly in onFirstDataRendered method for the detailGrid, but found no luck.
Master detail grid code:
detailCellRendererParams = {
detailGridOptions: {
columnDefs: [
{ headerName: "Contact ID", field: "contractId", editable: true, [cellValueChanged]: "cellValueChanged()" },
{ headerName: "Contact Name", field: "contractName" },
{ headerName: "Category", field: "category" }]
}
}
onFirstDataRendered(params) {
params.api.rowModel.gridApi.cellValueChanged = function (params) {
console.log("cellChanged");
}
}
In case someone still wonders, in detailGridOptions add:
onCellValueChanged: function ($event) {
// your code here
},
This will be triggered every time you change cell value.
Fixed the problem using custom cellRenderer and added an eventListener for change event. I just wanted to have this functionality on the first row of the grid, so added a condition to the rowIndex.
detailCellRendererParams = {
detailGridOptions: {
columnDefs: [{headerName: "Contact ID",field: "contractId",editable: true,
cellRenderer: (params) => {
params.eGridCell.addEventListener('change', (e) => {
this.getDetails(e.target.value);
})
},
{headerName: "Contact Name", field: "contractName"},
{headerName: "Category",field: "category"}]
}
}
getDetails(id): void {
this.apiService.getDetails(id)
.subscribe(result => {
this.gridApi.detailGridInfoMap.detail_0.api.forEachNode(node=> {
if(node.rowIndex == 0){
node.data = result;
node.gridApi.refreshCells();
}}
);
})}

Why ui-grid reset to default state, after set filter, after restore state?

I'll created ui-grid and make functionality to save grid state to cookies via localStorageService. Then I change column width and save this state. After I restore state via 'gridApi.saveState.restore' and this do is perfect, but when I set filter, grid reset column to default width.
Please tell Me if I do something wrong.
$scope.enableFiltering = function () {
var isEnabledFiltering = localStorageService.get('enableFiltering');
if (!_.isNull(isEnabledFiltering) && !_.isUndefined(isEnabledFiltering)) {
return JSON.parse(isEnabledFiltering);
}
return false;
};
$scope.colDefs = [
{
displayName: locMsg['id'],
field: 'id',
enableHiding: true,
visible: false,
headerCellClass: 'header-filtered',
filters: [{
condition: uiGridConstants.filter.CONTAINS
}]
},
{
displayName: locMsg['name'],
field: 'name',
enableHiding: true,
headerCellClass: 'header-filtered',
filters: [{
condition: uiGridConstants.filter.CONTAINS
}],
},];
$scope.regularGridStateName = "grid";
$scope.defaultGridStateName = "defaultGrid";
$scope.gridOptions = {
enableFiltering: $scope.enableFiltering(),
enableGridMenu: true,
columnDefs : $scope.colDefs
};
$scope.toggleFiltering = function () {
$scope.gridOptions.enableFiltering = !$scope.gridOptions.enableFiltering;
localStorageService.set('enableFiltering', $scope.gridOptions.enableFiltering);
$scope.gridApi.core.notifyDataChange(uiGridConstants.dataChange.COLUMN);
var gridState = localStorageService.get($scope.regularGridStateName);
if (gridState) {
gridApi.saveState.restore($scope, gridState);
}
};
$scope.gridOptions.onRegisterApi = function (gridApi) {
$scope.gridApi = gridApi;
$scope.gridOptions.gridMenuCustomItems.push({
title: 'Reset table',
action: function () {
var defaultState = localStorageService.get($scope.defaultGridStateName);
localStorageService.set($scope.regularGridStateName, defaultState);
if (defaultState) {
gridApi.saveState.restore($scope, defaultState);
}
},
order: 220
});
$scope.gridOptions.gridMenuCustomItems.push({
title: 'Save table state',
action: function () {
localStorageService.set($scope.regularGridStateName, $scope.gridApi.saveState.save());
},
order: 221
});
$timeout(function () {
gridStateService.saveDefaultStateIfNotExist($scope.defaultGridStateName, $scope.gridApi.saveState.save());
var defaultState = localStorageService.get($scope.defaultGridStateName);
if (!defaultState) {
localStorageService.set($scope.regularGridStateName, $scope.gridApi.saveState.save());
}
var gridState = localStorageService.get($scope.regularGridStateName);
if (gridState) {
gridApi.saveState.restore($scope, gridState);
}
}, 10);
This problem has been solved, just need to update to new version.
I had similar issue and this is due to the caching of column order. Try the following
gridApi.saveState.restore(this.scope, this.scope.tableState);
var columnDefsColMov = gridApi.grid.moveColumns.orderCache;
columnDefsColMov.length = 0;
columnDefsColMov.push.apply(columnDefsColMov, gridApi.grid.columns.slice());
gridApi.core.notifyDataChange(this.uiGridConstants.dataChange.COLUMN);

ExtJS TaskRunner

I'm still in the learning process with EXTJS and any help would be much appreciated.
The goal for me is to load data into a grid where one cell needs to have the value incremented every minute. From my research using the TaskRunner function is the way to go but can't figure out where to put it and how to use it. My assumption is that it needs to go into the model or the controller but I'm not sure. In my simple project I'm using the MVC architecture.
Currently my gird works as expected. It reads in a file does a date conversion that produces a minute value. It's that minute value that I need to increment.
The code below is a sample TaskRunner snippit that I'm working with, right or wrong I don't know yet.
var runner = new Ext.util.TaskRunner();
var task = runner.newTask({
run: store.each(function (item)
{
var incReq = item.get('request') + 1;
item.set('request', incReq);
}),
interval: 60000 // 1-minute interval
});
task.start();
Model:
Ext.define("myApp.model.ActionItem", {
extend : "Ext.data.Model",
fields : [
{
name: 'pri',
type: 'int'
},
{
name: 'request',
type: 'int',
defaultValue: 0,
convert : function(v, model) {
return Math.round((new Date() - new Date(v)) / 60000);
}
}
]
});
Controller:
Ext.define("myApp.controller.HomeController", {
extend: "Ext.app.Controller",
id: "HomeController",
refs: [
{ ref: "ActionItemsGrid", selector: "[xtype=actionitemgrid]" },
{ ref: "DetailsPanel", selector: "[xtype=actionitemdetails]" }
],
pri: "",
models: ["ActionItem"],
stores: ["myActionStore"],
views:
[
"home.ActionItemDetailsPanel",
"home.ActionItemGrid",
"home.HomeScreen"
],
init: function () {
this.control({
"#homescreen": {
beforerender: this.loadActionItems
},
"ActionItemsGrid": {
itemclick: this.displayDetails
}
});
},
displayDetails: function (model, record) {
this.getDetailsPanel().loadRecord(record);
},
loadActionItems: function () {
var store = Ext.getStore("myActionStore");
store.load();
this.getActionItemsGrid().reconfigure(store);
}
});
View:
Ext.define("myApp.view.home.ActionItemGrid", {
extend: "Ext.grid.Panel",
xtype: "actionitemgrid",
resizable: true,
multiSelect: false,
enableDragDrop : false,
store: null,
columns:
[
{ header: "Pri", dataIndex: "pri", sortable: false, autoSizeColumn: true},
{ header: "Req", dataIndex: "request", sortable: false, autoSizeColumn: true}
],
viewConfig:
{
listeners: {
refresh: function(dataview) {
Ext.each(dataview.panel.columns, function(column) {
if (column.autoSizeColumn === true)
column.autoSize();
})
}
}
}
});
Sample JSON File:
{
"actionitems" : [
{
"pri": 1,
"request": "2014-12-30T03:52:48.516Z"
},
{
"pri": 2,
"request": "2014-12-29T05:02:48.516Z"
}
]
}
You have error in code which creates task - you should provide function to run configuration property, not result of invocation. Try this:
var runner = new Ext.util.TaskRunner();
var task = runner.newTask({
run: function() {
store.each(function (item)
{
var incReq = item.get('request') + 1;
item.set('request', incReq);
})
},
interval: 60000 // 1-minute interval
});
task.start();
You can put that code in loadActionItems method.

Categories

Resources