maybe the title of my question is not proper, please feel free to update my title.
my json data is like
[
{ "AutoId": 2, "CustomerId": "1000AIRLIESST", "customerLastName": "John", "locationId": "2", "Address": "1000 AIRLIES ST Winnipeg " },
{ "AutoId": 2, "CustomerId": "1000AIRLIESST", "customerLastName": "John", "locationId": "186471", "Address": "1000 Airlies ST Winnipeg " },
{ "AutoId": 2, "CustomerId": "1000AIRLIESST", "customerLastName": "John", "locationId": "186752", "Address": "111 pineview rd ST Winnipeg " }
];
as you can see the autoId, customerId and lastname are same. I want to demonstrate this data in ui-grid like following picture. I want to common part of my data comes in main columns.
It is impossible to group two column with same grouping priority
groupPriorities should generally be sequential, if they're not then the next time getGrouping is called we'll renumber them to be sequential.
Defaults to undefined.
so my solution is like a cheat. first I use the aggregation function (max) for second column (customerLastname). then I used a custom directive to manipulate data.
you can see the result in plunker
The column definition of ui-grid
$scope.gridOptions = {
enableFiltering: true,
treeRowHeaderAlwaysVisible: false,
columnDefs: [
{
name: 'customerLastName',
displayName: 'Customer LastName',
width: 200,
treeAggregationType: uiGridGroupingConstants.aggregation.MAX,
cellTemplate: '<div class="ui-grid-cell-contents" > <fakemax val="{{COL_FIELD}}" /></div>'
},
{
name: 'Address',
width: 200,
},
{
name: 'CustomerId',
grouping: { groupPriority: 0 },
sort: { priority: 0, direction: 'desc' },
width: 200,
cellTemplate: '<div><div ng-if="!col.grouping || col.grouping.groupPriority === undefined || col.grouping.groupPriority === null ||' +
' ( row.groupHeader && col.grouping.groupPriority === row.treeLevel )" class="ui-grid-cell-contents" title="TOOLTIP">{{COL_FIELD CUSTOM_FILTERS}}</div></div>'
},
],
data: 'Customers',
onRegisterApi: function (gridApi) {
$scope.gridApi = gridApi;
}
};
please pay attention to fakemax directive which I used in the cellTemplate of customerLastName. the custom directive is so simple.
app.directive('fakemax', function () {
return function(scope, iElement, iAttrs) {
var value = iAttrs.val;
value = value.replace("max:", "");
iElement[0].innerHTML = value;
}
});
Related
In my AngularJS application im using Kendo UI Grid.
I have the following Kendo UI Grid options and dataSource. What im trying to do is to somehow add click event on each row. I have definitions for each column but I cant access the whole row which contains the columns. Is this possible without the use of rowTemplate and altRowTemplate. Because if i use them i have to redefine the whole table again.
HTML:
<div
k-options="ctrl.mainGridOptions"
k-rebind="ctrl.mainGridOptions"
kendo-grid="ctrl.gridInstance">
</div>
Grid Options:
this.mainGridOptions = {
dataSource: {
data: this.allRows,
pageSize: 150,
schema: {
model: {
fields: {
activityType: { type: "string" },
communicationType: { type: "string" },
count: { type: "number" },
}
}
},
aggregate: [
{
field: "activityType",
aggregate: "count"
},
{
field: "communicationType",
aggregate: "count"
},
{
field: "count",
aggregate: "count"
}
],
group: {
field: this.groupBy.field,
aggregates: [
{
field: "activityType",
aggregate: "count"
},
{
field: "communicationType",
aggregate: "count"
},
{
field: "count",
aggregate: "count"
}
]
}
},
scrollable: {
virtual: true
},
sortable: true,
resizable: false,
pageable: false,
groupable: true,
columnMenu: true,
filterable: true,
reorderable: false,
columns: [
{
headerTemplate: '<md-checkbox ng-model="dataItem.checked" ng-change="ctrl.headerSelected(dataItem)" aria-label="row check" ng-transclude=""></md-checkbox>',
template: '<md-checkbox stop-event ng-class="{\'row-selected\' : ctrl.checkVisible.length > 0 || ctrl.headerCb}" ng-model="dataItem.checked" ng-change="ctrl.rowSelected(dataItem, dataItem.cbIndex)" aria-label="item check"></md-checkbox>',
width:"50px"
},
{
field: "activityType",
title: "activityType",
aggregates: ['count'],
template: '<span ng-bind="dataItem.activityType"></span>',
groupHeaderTemplate: '<span class="aggregate-wrapper" ng-click="ctrl.toggleGroupCollapse($event)"><span>' + "activityType" + ':' + '</span>' + ' #= value # (Count: #= count#)</span>'
},{
field: "communicationType",
title: "communicationType",
aggregates: ['count'],
groupHeaderTemplate: '<span class="aggregate-wrapper" ng-click="ctrl.toggleGroupCollapse($event)"><span>' + "communicationType" + '</span>' + ' #= value # (Count: #= count#)</span>'
},{
field: "count",
title: "count",
aggregates: ['count'],
template: '<div layout="row" layout-align="center center">' +
'<md-progress-linear flex="80" md-mode="determinate" ng-value="ctrl.calcProgressValue(dataItem.count)"></md-progress-linear>' +
'<span flex style="text-align:right" ng-bind="dataItem.count"> </span>' +
'</div>',
groupHeaderTemplate: '<span class="aggregate-wrapper" ng-click="ctrl.toggleGroupCollapse($event)"><span>' + "count" + ':' + '</span>' + ' #= value # (Count: #= count#)</span>'
},
{
field: "",
title: null,
template: '<span class="action-controls"><i class="material-icons">label</i><i class="material-icons">star_rate</i><i class="material-icons"> more_vert </i></span>',
width: '200px'
}
],
};
This is the data i pass into the kendo grid
this.allRows = [
{
"activityType": 2,
"activitySubType": 10,
"count": 265
},
{
"activityType": 2,
"activitySubType": 1,
"count": 238
},
{
"activityType": 7,
"activitySubType": 3,
"count": 102
},
{
"activityType": 6,
"activitySubType": 12,
"count": 142
},
{
"activityType": 6,
"activitySubType": 18,
"count": 98
},
{
"activityType": 2,
"activitySubType": 19,
"count": 145
}
];
You can use change event, which is triggered when use changes a row or a cell in the grid when the selectable option is set to true:
change: function() {
// Get your row's data
var dataItem = this.dataItem(this.select());
}
Demo
I am trying to set rows editable/not editable based on a flag in the data.
I can get this working outside an angular 1.5 component, but can't seem to access row.entity inside a controller in a component.
function memberDisplayCtrl ($scope, memberFactory,uiGridConstants) {
var ctrl = this;
ctrl.people = memberFactory.getMembers();
ctrl.checkStatus = function(ctrl){
// How do I do something like this:
// if (ctrl.row.entity.Status === 'Y') { return 'true'; } else {return 'false';}
};
ctrl.gridOptions = {
enableSorting: true,
enableCellEdit:false,
cellEditableCondition: ctrl.checkStatus(ctrl),
enableHorizontalScrollbar : 0,
enableVerticalScrollbar : 0,
enableColumnMenus: false,
minRowsToShow: ctrl.people.length,
columnDefs: [
{ displayName:'First Name', name: 'fname', enableCellEdit:true },
{ displayName:'Last Name', name: 'lname', enableCellEdit:true },
{ displayName:'Date of Birth', name: 'DOB', type:'date', enableCellEdit:true, cellFilter: 'date:"yyyy-MM-dd"'},
{ displayName:'Address', name: 'address', enableCellEdit:true},
{ displayName:'Status',name: 'Status', enableCellEdit: true}
],
data : ctrl.people
};
}
I'm pretty sure I have a scope problem but can't seem to figure it out. How do I access row.entity? I have an isolated scope inside my controller (since it is part of a component)
plunker here: https://plnkr.co/edit/Wz7gKs
Thanks
just pass a function to cellEditableCondition instead of executing it:
cellEditableCondition: ctrl.checkStatus
and note, that parameter received by that function is not current controller's this (aliased in your case as ctrl), but ui-grid's scope, so I renamed ctrl to scope:
function memberDisplayCtrl ($scope, memberFactory,uiGridConstants) {
var ctrl = this;
ctrl.people = memberFactory.getMembers();
ctrl.checkStatus = function(scope) {
return scope.row.entity.Status === 'Y'
};
ctrl.gridOptions = {
enableSorting: true,
enableCellEdit:false,
cellEditableCondition: ctrl.checkStatus,
enableHorizontalScrollbar : 0,
enableVerticalScrollbar : 0,
enableColumnMenus: false,
minRowsToShow: ctrl.people.length,
columnDefs: [
{ displayName:'First Name', name: 'fname', enableCellEdit:true },
{ displayName:'Last Name', name: 'lname', enableCellEdit:true },
{ displayName:'Date of Birth', name: 'DOB', type:'date', enableCellEdit:true, cellFilter: 'date:"yyyy-MM-dd"'},
{ displayName:'Address', name: 'address', enableCellEdit:true},
{ displayName:'Status',name: 'Status', enableCellEdit: true}
],
data : ctrl.people
};
}
also, I see your commented code:
if (ctrl.row.entity.Status === 'Y') {
return 'true';
}
else {
return 'false';
}
here you intend to return string variable in both cases which will always evaluated as boolean true, you should return boolean:
if (ctrl.row.entity.Status === 'Y') {
return true;
}
else {
return false;
}
which is equal to much shorter version:
return ctrl.row.entity.Status === 'Y';
plunker: https://plnkr.co/edit/KXbJ40?p=preview
I'm using ui-grid and I'm grouping the data, I will need to get the group headers and the counters. How can I get those values?
This is an example of the grid
$scope.gridOptions = {
enableFiltering: false,
enableColumnResize: true,
onRegisterApi: function (gridApi) {
$scope.gridApi = gridApi;
},
columnDefs: [
{ field: 'month',enableHiding: false, grouping: { groupPriority: 0 }, sort: { priority: 0, direction: 'desc' }},
{ field: 'facility',enableHiding: false,grouping: { groupPriority: 1 }, sort: { priority: 1, direction: 'asc' }},
...
{ field: 'categorymanager',enableHiding: false, displayName:'CM', grouping:{ groupPriority: 2 }, sort: { priority: 2, direction: 'asc' }},
]
};
You can get the values by writing a custom cellTemplate for the colDef. For example if you can define your template as:
let monthTemplate = '<div><div ng-if="!col.grouping || col.grouping.groupPriority === undefined || col.grouping.groupPriority === null || ' +
'( row.groupHeader && col.grouping.groupPriority === row.treeLevel )" class="ui-grid-cell-contents" ' +
'title="TOOLTIP">{{grid.appScope.getValue(COL_FIELD, row.treeNode.children )}}</div></div>';
Then define your method as:
$scope.getValue = function(item, treeRowEntity){
//item will hold month value
//iterate over treerowentity array and get values
//for example, if column required was facility
treeRowEntity[0].row.entity.facility
};
I am using Kendo UI Grid with row filters. i am facing filters options issue. I am using Filterbale.cell.template for filters to display kendo autoComplete.
Issue is as displayed in image autocomplete options are not updating on selecting of one of the filters.
Below is my html
<div ng-controller="VehiclesController" class="my-grid" >
<kendo-grid options="vehiclesGridOption">
</kendo-grid>
</div>
Below is my Controller
$scope.vehiclesGridOption = {
dataSource: {
schema: {
id: "_id",
model: {
fields: {
make: {type: "string"},
model: {type: "string"},
year: {type: "number"}
}
}
},
transport: {
read: function (e) {
vehicleService.vehicles().then(function (response) {
e.success(response);
console.log(response.length);
}).then(function () {
console.log("error happened");
})
}
},
pageSize: 12,
pageSizes: false,
},
sortable: {
mode: "multiple",
allowUnsort: true
},
filterable: {
mode: "row"
},
pageable: {
buttonCount: 5
},
columns: [
{
title: "",
template: '',
width: "3%" // ACTS AS SPACER
},
{
field: "make",
title: "Make",
filterable: {
cell: {
operator: "contains",
template: function (args) {
args.element.kendoAutoComplete({
dataSource: args.dataSource,
dataTextField: "make",
dataValueField: "make",
valuePrimitive: true,
placeholder: "Make",
});
}
}
},
width: "29%",
}, {
field: "model",
filterable: {
cell: {
operator: "contains",
template: function (args) {
console.log(args);
args.element.kendoAutoComplete({
dataSource: args.dataSource,
dataTextField: "model",
dataValueField: "model",
valuePrimitive: true,
placeholder: "Model",
});
}
}
},
title: "Model",
width: "29%",
}, {
field: "year",
title: "Year",
filterable: {
cell: {
template: function (args) {
args.element.kendoAutoComplete({
dataSource: args.dataSource,
dataTextField: "year",
dataValueField: "year",
placeholder: "Year",
suggest: true,
ignoreCase: true,
filter: "gte"
});
}
}
},
width: "29%",
},
{
field: "",
title: "Edit",
template: '<a class=\"k-link text-center grid-edit-btn vehicle-grid-edit-btn\" ui-sref="vehicleDetails({\'id\': \'#=_id #\' })"><span class=\"icon-editpencil icon-grid\"></span></a>',
width: "10%",
}],
};
Below is the Issue if user selects the Make in the first column filter then Model filter should display only selected make models like Honda (make)-> Accord , Civic ..etc but its displaying all unique values irrespective of model filter..
Kendo filter row uses the same dataSource from the grid component, just providing unique values. Since the autocomplete components are initialized when the grid dataSource is empty, they always show all the values.
You can manually filter based on current filter row values.
Firstly, add ids for your coresponding autocomplete components i.e. inside template functions:
args.element.attr('id', 'make');
//<...>
args.element.attr('id', 'model');
//<...>
args.element.attr('id', 'year');
Then add a data bound event to the grid (since autocomplete components do not fire change events when filters are cleared).
$scope.vehiclesGridOption = {
//...
dataBound : function(e) {
setTimeout(function() { //timeout is to make sure value() is already updated
var make = $('#make').data('kendoAutoComplete').value();
if (make) {
$('#model').data('kendoAutoComplete').dataSource.filter({field: 'make', operator: 'eq', value: make });
} else {
$('#model').data('kendoAutoComplete').dataSource.filter({});
}
});
}
}
Or if you also want to filter by "Year" column, it could go like this:
$scope.vehiclesGridOption = {
//...
dataBound: function(e) {
setTimeout(function() { //timeout is to make sure value() is already updated
var make = $('#make').data('kendoAutoComplete').value();
var model = $('#model').data('kendoAutoComplete').value();
if (make) {
$('#model').data('kendoAutoComplete').dataSource.filter({field: 'make', operator: 'eq', value: make });
} else {
$('#model').data('kendoAutoComplete').dataSource.filter({});
}
var yearFilter = {filters: [], logic: 'and'};
if (make) {
yearFilter.filters.push({field: 'make', operator: 'eq', value: make });
}
if (model) {
yearFilter.filters.push({field: 'model', operator: 'eq', value: model });
}
$('#year').data('kendoAutoComplete').dataSource.filter(yearFilter.filters.length ? yearFilter : null);
});
}
}
I am working on a project where I have used UI-Grid to show list of users. I have specified width:"**" for each column in column definition. In output, all the columns are collapsed in left side. When I resizes browser window or inspects element, then width is auto adjusted quickly. But for first time, all columns are displayed collapsed. Here is my code:
$scope.columns = [
{ field: 'name', name:'Name', width: "**", cellTooltip : false,enablePinning:true,
cellTemplate:'<div class="ui-grid-cell-contents">'+
'<a ng-href="#/account/profile?id={$ grid.appScope.getUserID(grid, row) $}"> {$ grid.appScope.getUserRow(grid, row,"uname") $} </a>'+
'</div>'
},
{ field: 'email', name:'Email', width: "**", cellTooltip : false,enablePinning:true },
{ field: 'role', name:'Role', width: "**", enableSorting: true,
cellTemplate:'<div class="ui-grid-cell-contents"> '+
'{$ grid.appScope.getUserRow(grid, row,"role") $}'+
'<a ng-click="grid.appScope.assignRole({$ grid.appScope.getUserID(grid, row) $})"> add </a>'+
'</div>'
},
{ field: 'isInvited', name:'Invitation status', width: "**", cellTooltip : false,enablePinning:true },
];
$scope.gridOptions = {
showGridFooter: true,
enableSorting: true,
enableGridMenu: true,
enableSelectAll: true,
enableFiltering: true,
enableHorizontalScrollbar : 1,
paginationPageSizes: [10,25, 50, 100],
useExternalPagination: true,
columnDefs: $scope.columns,
enableGridMenu: true,
enableSelectAll: true,
exporterCsvFilename: 'myFile.csv',
exporterPdfDefaultStyle: {fontSize: 9},
exporterPdfTableStyle: {margin: [10, 10, 10, 10]},
exporterPdfTableHeaderStyle: {fontSize: 10, bold: true, italics: true, color: 'red'},
exporterPdfHeader: { text: "My Header", style: 'headerStyle' },
exporterPdfFooter: function ( currentPage, pageCount ) {
return { text: currentPage.toString() + ' of ' + pageCount.toString(), style: 'footerStyle' };
},
exporterPdfCustomFormatter: function ( docDefinition ) {
docDefinition.styles.headerStyle = { fontSize: 22, bold: true };
docDefinition.styles.footerStyle = { fontSize: 10, bold: true };
return docDefinition;
},
exporterCsvLinkElement: angular.element(document.querySelectorAll(".custom-csv-link-location")),
onRegisterApi: function(gridApi){
$scope.gridApi = gridApi;
$scope.gridApi.core.on.sortChanged( $scope, function( grid, sort ) {
$scope.gridApi.core.notifyDataChange( uiGridConstants.dataChange.COLUMN );
});
$scope.gridApi.pagination.on.paginationChanged( $scope, function( currentPage, pageSize){
$scope.getAppDetails(currentPage, pageSize);
});
}
};
I just noticed if you resize the window it renders the grid properly. So a quick and dirty work around and not really intended as a solution, is watching for when the grid becomes visible and calling grid.handleWindowResize() on the gridApi.
Also a $timeout to ensure the rendering is performed after the tab has fully displayed. Here's how I watch:
$scope.test = {isActive: false};
$scope.$watch('test.isActive', function (active, oldActive) {
if(active) {
$timeout(function () {
$scope.gridApi.grid.handleWindowResize();
});
}
});