Angular UI-Grid filtering - angularjs

On my angular application I have a UI-Grid and a button to open a modal window.
In my gridoptions I enabled external filtering. But the problem is whenever I enter the filter field and press enter the button(modal window) is triggered and the modal opens up. I don't have any key events inside my controller.
Here are my gridoptions for the ui-grid:
gridOptions: uiGrid.IGridOptionsOf<any> = {
appScopeProvider: this,
data: [] as any[],
enableFiltering: true,
enablePaginationControls: false,
useExternalPagination: true,
minRowsToShow: 5,
useExternalSorting: true,
useExternalFiltering: true,
onRegisterApi: (gridApi: uiGrid.IGridApiOf<any>) => {
this.gridApi = gridApi;
this.gridApi.core.on.sortChanged(this.$scope, (grid: uiGrid.IGridInstanceOf<any>, columns: Array<uiGrid.IGridColumnOf<any>>) => this.sortRequests(grid, columns));
this.gridApi.pagination.on.paginationChanged(this.$scope, (newPage: number, pageSize: number) => this.changePage(newPage, pageSize));
this.gridApi.core.on.filterChanged(this.$scope, () => {
if (this.filterTimeout != undefined) {
this.$timeout.cancel(this.filterTimeout);
}
this.filterTimeout = this.$timeout(() => this.filterRequests(), 500);
});
},
I've set debuggers inside the filter methods but it doesn't get triggered by pressing enter only when you type a character.
Does anyone know what is triggering this button when enter is pressed?
UPDATE 1
<button class="btn btn-primary" ng-click="vm.open()" translate="country.headers.selectCountry"></button>
<div id="grid1" ui-grid="vm.gridOptions" ui-grid-pagination></div>
open() {
let instance = this.$uibModal.open({
templateUrl: 'app/common/controllers/html.html',
controller: 'controller as vm',
backdrop: 'static',
windowClass: 'country-modal',
resolve: {
programId: () => this.$stateParams['programId']
}
});
instance.result.then((dataGenerated: boolean) => {
if (dataGenerated) {
this.loadData();
}
});
}
UPDATE 2:
private filterRequests(): void {
let grid = this.gridApi.grid;
this.filtering = [];
for (let i = 0; i < grid.columns.length; i++) {
let column = grid.columns[i];
if (column.filters.length > 0) {
for (let j = 0; j < column.filters.length; j++) {
let filter = column.filters[j].term;
if (filter != undefined && filter != '')
this.filtering.push(column.field + '.contains("' + filter + '")');
}
}
}
this.loadRequests();
}
loadRequests(): void {
this.service
.get(
this.model.id,
{
params: {
page: this.pagingInfo.page,
pageSize: this.pagingInfo.pageSize,
sort: this.sorting,
filter: this.filtering
}
})
.then((data: any) => {
this.gridOptions.data = data.data;
this.gridHeight = (this.gridOptions.data.length + 2) * this.gridOptions.rowHeight;
this.pagingInfo.page = data.page;
this.pagingInfo.pageSize = data.pageSize;
this.pagingInfo.totalCount = data.totalCount;
});
}
With kinds regards, Brent

Related

Cannot find method on button click event in ag-grid with Angular2

I want to call editAsset() method on button's click event in ag-grid.
ListComponent :
ngOnInit() {
this.route.data.forEach((data: { assets: Asset[]}) => {
this.gridOptions.columnDefs = this.createColumnDefs(data.assets[0]);
this.gridOptions.rowData = data.assets
});
}
private createColumnDefs(asset) {
let keyNames = Object.keys(asset);
let headers = []
keyNames.filter(key => key != '__v' && key != '_id').map(key => {
headers.push({
headerName: key,
field: key,
width: 100
})
});
headers.push({
headerName: 'update',
field: 'update',
cellRendererFramework: {
template: '<button (click) = "editAsset()"> Edit </button>'
},
width: 100
});
return headers;
}
editAsset(): void {
alert("here");
}
Both of these are defined in the same component.
But it can't find the method and showing the following error :
Here's the Snapshot of error report
Here's the grid

Angularjs toolbar commands- disable and disable buttons

I am trying to disable and enable button:
for instance: If I click on Modify button I want to disable it and Enable Save button and if I click on Save button I want to enable Modify button and disable Save button. Thank you.
Below the Angularjs code:
angular.module('virtoCommerce.catalogModule')
.controller('virtoCommerce.catalogModule.categoriesItemsListController', ['$scope', function ($scope) {
var isFieldEnabled = true;
blade.updatePermission = 'catalog:update';
... (more codes but not included)
var formScope;
$scope.setForm = function (form) { formScope = form; }
//Save the prices entered by the user.
function savePrice()
{
//TODO: Save the price information.
}
function isDirty() {
return blade.hasUpdatePermission();
};
//function enablePriceField
function enablePriceField() {
var inputList = document.getElementsByTagName("input");
var inputList2 = Array.prototype.slice.call(inputList);
if (isFieldEnabled == true) {
for (i = 0; i < inputList.length; i++) {
var row = inputList2[i];
if (row.id == "priceField") {
row.disabled = false;
}
}
} else {
for (i = 0; i < inputList.length; i++) {
var row = inputList2[i];
if (row.id == "priceField") {
row.disabled = true;
}
}
}
//Set the flag to true or false
if (isFieldEnabled == true) {
isFieldEnabled = false
} else {
isFieldEnabled = true;
}
}
var formScope;
$scope.setForm = function (form) { formScope = form; }
function canSave() {
return isDirty() && formScope && formScope.$valid;
}
//Angular toolbar commands
blade.toolbarCommands = [
{
name: "platform.commands.modify",
icon: 'fa fa-pencil',
executeMethod: function () { enablePriceField();},
canExecuteMethod: function () { return true; }
},
{
name: "platform.commands.save",
icon: 'fa fa-floppy-o',
executeMethod: function () { savePrice(); },
canExecuteMethod: canSave,
permission: blade.updatePermission
}];
}]);
I am not sure I see how your code is related to the question, but you can enable/disable a button programatically using the ngDisabled directive (see the docs).
In your controller, intialize $scope.enableSave = true (of false, as you want). Then in your html:
<button class="btn btn-primary" ng-disabled="!enableSave" ng-click="enableSave=!enableSave">Save</button>
<button class="btn btn-primary" ng-disabled="enableSave" ng-click="enableSave=!enableSave">Modify</button>
You will toggle 'enableSave' each time you click on the active (ie. not disabled) button, which will in turn disable the button you just clicked, and enable the other one.
Sorry, I had not seen... I am not familiar with virtoCommerce, but if I understand correctly you want to update the 'canExecuteMethod' ? Maybe try something like that:
$scope.enableSave = false;
function canSave() {
return isDirty() && formScope && formScope.$valid && $scope.enableSave;
}
Then for the buttons:
{
name: "platform.commands.modify",
icon: 'fa fa-pencil',
executeMethod: function () {
enablePriceField();
$scope.enableSave = true;
},
canExecuteMethod: function () { return !canSave(); }
},
{
name: "platform.commands.save",
icon: 'fa fa-floppy-o',
executeMethod: function () {
savePrice();
$scope.enableSave = false;
},
canExecuteMethod: function () { return canSave(); },
permission: blade.updatePermission
}
As a side note, if isFieldEnabled is a boolean you can replace:
if (isFieldEnabled == true) {
isFieldEnabled = false
} else {
isFieldEnabled = true;
}
By: isFieldEnabled = !isFieldEnabled;

Kendo Multiselect with AngularJS

I want to set maxSelectedItems from a textbox value. Apart from that I want to reset kendo multiselect if textbox value change. I have tried below thing but it is not working.
<input type="hidden" ng-model="DTO.ProgramID" id="ProgramID" value="3">
<input class="form-control" data-val="true" id="ClassSize " maxlength="2" name="ClassSize " ng-model="DTO.ClassSize "type="text" ng-blur="OnClassSizeChange()">
<select id="CourseClientIDs" kendo-multi-select k-options="selectClientOptions" ng-model="DTO.CourseClientIDs"></select>
$scope.selectClientOptions = {
placeholder: "---Select Clients---",
dataTextField: "ClientFLName",
dataValueField: "ClientID",
valuePrimitive: true,
autoBind: false,
dataSource: {
type: "jsonp",
serverFiltering: true,
transport: {
read: {
url: "Home/ClientDataSource/",
cache: false
},
parameterMap: function (data, action) {
if (action === "read") {
if ($scope.DTO.ProgramID != undefined) {
return {
programID: $scope.DTO.ProgramID
};
}
} else {
return data;
}
}
}
}
};
$scope.OnClassSizeChange = function () {
if ($scope.DTO.ClassSize == 0) {
var message = "Class size cannot be 0.";
return false;
}else{
$scope.selectClientOptions.maxSelectedItems = $scope.DTO.ClassSize; //Not Working
$scope.selectClientOptions.dataSource.read(); //Not Working
}
return true;
};
I am trying angularjs with kendo first time. Please help me.
In the textbox define ngChange specify the function to execute when value change. Supposing ngModel for textbox is in $scope.nvm, try this:
$scope.nvm = 1; //value in textfield
$scope.setnvm = function(){//change maxSelectedItems and reset values
var ms = angular.element(document.getElementById("sems")).data("kendoMultiSelect");
ms.setOptions({
maxSelectedItems: $scope.nvm,
});
ms.value([]);
};

AngularJS + Datatables + Dropdownlist

I'm using AngularJS to populate my datatable. What I want to know is how can I populate the datatable based on the dropdownlist
This is my dropdownlist
<div>
Get Users with Role:
<select id="ddlRole" data-ng-model="selectedRole" data-ng-change="populateDataTable()" data-ng-options="v.name for (k,v) in roles"></select>
<input type="hidden" value="{{selectedRole}}" />
</div>
This is my angular code
$scope.roles = [
{name: 'XXX' },
{name: 'YYY' }
];
$scope.selectedRole = $scope.roles[0];
//onchange event
$scope.populateDataTable = function () {
$scope.selectedRole = $scope.selectedRole.name;
RefreshDataTable(); //TODO
};
How can I change this to make an ajax call to retreive the data, populate the datatable based on the dropdownlist value and retain the value of dropdownlist as well.
I'm sure we can do this using JQuery but I dont want to mix these and make a mess. Is there any way I can acheive this using AngularJS?
Here is a simple data table directive:
appModule.directive('dataTable', [function () {
return function (scope, element, attrs) {
// apply DataTable options, use defaults if none specified by user
var options = {};
if (attrs.myTable.length > 0) {
options = scope.$eval(attrs.myTable);
} else {
options = {
"bStateSave": true,
"iCookieDuration": 2419200, /* 1 month */
"bJQueryUI": true,
"bPaginate": false,
"bLengthChange": false,
"bFilter": false,
"bInfo": false,
"bDestroy": true
};
}
// Tell the dataTables plugin what columns to use
// We can either derive them from the dom, or use setup from the controller
var explicitColumns = [];
element.find('th').each(function (index, elem) {
explicitColumns.push($(elem).text());
});
if (explicitColumns.length > 0) {
options["aoColumns"] = explicitColumns;
} else if (attrs.aoColumns) {
options["aoColumns"] = scope.$eval(attrs.aoColumns);
}
// aoColumnDefs is dataTables way of providing fine control over column config
if (attrs.aoColumnDefs) {
options["aoColumnDefs"] = scope.$eval(attrs.aoColumnDefs);
}
if (attrs.fnRowCallback) {
options["fnRowCallback"] = scope.$eval(attrs.fnRowCallback);
}
// apply the plugin
var dataTable = element.dataTable(options);
// watch for any changes to our data, rebuild the DataTable
scope.$watch(attrs.aaData, function (value) {
var val = value || null;
if (val) {
dataTable.fnClearTable();
dataTable.fnAddData(scope.$eval(attrs.aaData));
}
});
if (attrs.useParentScope) {
scope.$parent.dataTable = dataTable;
} else {
scope.dataTable = dataTable;
}
};
}]);
Then initialize it in your controller. Override fnServerData method, append your selected value (selected role) and filter data on server side.
$scope.overrideOptions = {
"bStateSave": true,
"iDisplayLength": 8,
"bProcessing": false,
"bServerSide": true,
"sAjaxSource": 'Data/Get',
"bFilter": false,
"bInfo": true,
"bLengthChange": false,
"sServerMethod": 'POST', ,
"fnServerData": function(sUrl, aoData, fnCallback, oSettings) {
var data = {
dataTableRequest: aoData,
selectedDropDownValue: $scope.selectedRole
};
$http.post(sUrl, data).success(function (json) {
if (json.sError) {
oSettings.oApi._fnLog(oSettings, 0, json.sError);
}
$(oSettings.oInstance).trigger('xhr', [oSettings, json]);
fnCallback(json);
});
}
};
var columnDefs = [
{
"mData": "id",
"bSortable": false,
"bSearchable": false,
"aTargets": ['tb-id']
},
{
"mData": "data",
"aTargets": ['tb-data']
}
];
Refresh the datatable on select change.
$scope.populateDataTable = function () {
if ($scope.dataTable) {
$scope.dataTable.fnDraw();
}
};
Html markup:
<table class="display m-t10px" data-table="overrideOptions" ao-column-defs="columnDefs">
<thead>
<tr>
<th class="tb-id"></th>
<th class="tb-data></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
Hope above your code is in controller.
Inject $http and make a $http get or post call
$scope.populateDataTable = function () {
$scope.selectedRole = $scope.selectedRole.name;
$http.get('api/controller', function(result){
//response from the service call in result
});
};

Using buffered store + infinite grid with dynamic data

The goal is to use buffered store for the dynamic data set.
The workflow is below:
Some data is already present on server.
Clients uses buffered store & infinite grid to handle the data.
When the application runs the store is loading
and 'load' event scrolls the grid to the last message.
Some records are added to server.
Client gets a push notification and runs store reload.
topic.store.load({addRecords: true});
The load event runs and tries to scroll to the last message again but failes:
TypeError: offsetsTo is null
e = Ext.fly(offsetsTo.el || offsetsTo, '_internal').getXY();
Seems that the grid view doesn't refreshes and doesn't show the added records, only the white spaces on their places.
Any ideas how can I make the grid view refresh correctly?
The store initialization:
Ext.define('orm.data.Store', {
extend: 'Ext.data.Store',
requires: ['orm.data.writer.Writer'],
constructor: function (config) {
Ext.apply(this, config);
this.proxy = Ext.merge(this.proxy, {
type: 'rest',
batchActions: true,
reader: {
type: 'json',
root: 'rows'
},
writer: {
type: 'orm'
}
});
this.callParent(arguments);
}
});
Ext.define('akma.chat.model.ChatMessage', {
extend:'Ext.data.Model',
fields:[
{ name:'id', type:'int', defaultValue : undefined },
{ name:'createDate', type:'date', dateFormat:'Y-m-d\\TH:i:s', defaultValue : undefined },
{ name:'creator', type:'User', isManyToOne : true, defaultValue : undefined },
{ name:'message', type:'string', defaultValue : undefined },
{ name:'nameFrom', type:'string', defaultValue : undefined },
{ name:'topic', type:'Topic', isManyToOne : true, defaultValue : undefined }
],
idProperty: 'id'
});
Ext.define('akma.chat.store.ChatMessages', {
extend: 'orm.data.Store',
requires: ['orm.data.Store'],
alias: 'store.akma.chat.store.ChatMessages',
storeId: 'ChatMessages',
model: 'akma.chat.model.ChatMessage',
proxy: {
url: 'http://localhost:8080/chat/services/entities/chatmessage'
}
});
var store = Ext.create('akma.chat.store.ChatMessages', {
buffered: true,
pageSize: 10,
trailingBufferZone: 5,
leadingBufferZone: 5,
purgePageCount: 0,
scrollToLoadBuffer: 10,
autoLoad: false,
sorters: [
{
property: 'id',
direction: 'ASC'
}
]
});
Grid initialization:
Ext.define('akma.chat.view.TopicGrid', {
alias: 'widget.akma.chat.view.TopicGrid',
extend: 'akma.chat.view.grid.DefaultChatMessageGrid',
requires: ['akma.chat.Chat', 'akma.UIUtils', 'Ext.grid.plugin.BufferedRenderer'],
features: [],
hasPagingBar: false,
height: 500,
loadedMsg: 0,
currentPage: 0,
oldId: undefined,
forceFit: true,
itemId: 'topicGrid',
selModel: {
pruneRemoved: false
},
multiSelect: true,
viewConfig: {
trackOver: false
},
plugins: [{
ptype: 'bufferedrenderer',
pluginId: 'bufferedrenderer',
variableRowHeight: true,
trailingBufferZone: 5,
leadingBufferZone: 5,
scrollToLoadBuffer: 10
}],
tbar: [{
text: 'unmask',
handler: function(){
this.up('#topicGrid').getView().loadMask.hide();
}
}],
constructor: function (config) {
this.topicId = config.topicId;
this.store = akma.chat.Chat.getMessageStoreInstance(this.topicId);
this.topic = akma.chat.Chat.getTopic(this.topicId);
var topicPanel = this;
this.store.on('load', function (store, records) {
var loadedMsg = store.getTotalCount();
var pageSize = store.pageSize;
store.currentPage = Math.ceil(loadedMsg/pageSize);
if (records && records.length > 0) {
var newId = records[0].data.id;
if (topicPanel.oldId) {
var element;
for (var i = topicPanel.oldId; i < newId; i++) {
element = Ext.get(i + '');
topicPanel.blinkMessage(element);
}
}
topicPanel.oldId = records[records.length-1].data.id;
var view = topicPanel.getView();
view.refresh();
topicPanel.getPlugin('bufferedrenderer').scrollTo(store.getTotalCount()-1);
}
});
this.callParent(arguments);
this.on('afterrender', function (grid) {
grid.getStore().load();
});
var me = this;
akma.UIUtils.onPasteArray.push(function (e, it) {
if(e.clipboardData){
var items = e.clipboardData.items;
for (var i = 0; i < items.length; ++i) {
if (items[i].kind == 'file' && items[i].type.indexOf('image/') !== -1) {
var blob = items[i].getAsFile();
akma.chat.Chat.upload(blob, function (event) {
var response = Ext.JSON.decode(event.target.responseText);
var fileId = response.rows[0].id;
me.sendMessage('<img src="/chat/services/file?id=' + fileId + '" />');
})
}
}
}
});
akma.UIUtils.addOnPasteListener();
},
sendMessage: function(message){
if(message){
var topicGrid = this;
Ext.Ajax.request({
method: 'POST',
url: topicGrid.store.proxy.url,
params:{
rows: Ext.encode([{"message":message,"topic":{"id":topicGrid.topicId}}])
}
});
}
},
blinkMessage: function (messageElement) {
if (messageElement) {
var blinking = setInterval(function () {
messageElement.removeCls('red');
messageElement.addCls('yellow');
setTimeout(function () {
messageElement.addCls('red');
messageElement.removeCls('yellow');
}, 250)
}, 500);
setTimeout(function () {
clearInterval(blinking);
messageElement.addCls('red');
messageElement.removeCls('yellow');
}, this.showInterval ? this.showInterval : 3000)
}
},
columns: [ {
dataIndex: 'message',
text: 'Message',
renderer: function (value, p, record) {
var firstSpan = "<span id='" + record.data.id + "'>";
var creator = record.data.creator;
return Ext.String.format('<div style="white-space:normal !important;">{3}{1} : {0}{4}</div>',
value,
creator ? '<span style="color: #' + creator.chatColor + ';">' + creator.username + '</span>' : 'N/A',
record.data.id,
firstSpan,
'</span>'
);
}
}
]
});
upd: Seems that the problem is not in View. The bufferedrenderer plugin ties to scroll to the record.
It runs a callback function:
callback: function(range, start, end) {
me.renderRange(start, end, true);
targetRec = store.data.getRange(recordIdx, recordIdx)[0];
.....
store.data.getRange(recordIdx, recordIdx)[0]
tries to get the last record in the store.
....
Ext.Array.push(result, Ext.Array.slice(me.getPage(pageNumber), sliceBegin, sliceEnd));
getPage returns all records of the given page, but the last record is missing i.e. the store was not updated perfectly.
Any ideas how to fix?
The problem is that store.load() doesn't fill up store PageMap with the new data. The simplest fix is using store.reload() instead.
Maybe you are to early when listening to the load event. I am doing roughly the same in my application (not scrolling to the end, but to some arbitrary record after load). I do the view-refresh and bufferedrender-scrollTo in the callback of the store.load().
Given your code this would look like:
this.on('afterrender', function (grid) {
var store = grid.getStore();
store.load({
callback: function {
// snip
var view = topicPanel.getView();
view.refresh();
topicPanel.getPlugin('bufferedrenderer').scrollTo(store.getTotalCount()-1);
}
});
});

Resources