I created an editable grid using ag-grid and I need to highlight the cells that were changed. I added the following code:
(cellValueChanged)="onDemandsCellValueChanged($event)"
And the method:
onDemandsCellValueChanged(params): void {
if (params.oldValue === params.newValue) {
return;
}
params.data.modified = true; // add modified property so it can be filtered on save
const column = params.column.colDef.field;
params.column.colDef.cellStyle = { 'background-color': '#e1f9e8' }; // highlight modified cells
params.api.refreshCells({
force: true,
columns: [column],
rowNodes: [params.node],
});
}
The cell is highlighted but when I scroll up and down all the cell from that column are highlighted.
You can check the behavior on stackblitz.
Also if you have a better way of doing this I'm open to new solutions.
I understand your problem You can achieve what you want like this - you should use cellStyle in your column definition as showing in docs and for this code is below
cellStyle: params => {
if (
params.data["modifiedRow" +
params.node.rowIndex +"andCellKey"+
params.column.colDef.field]
) {
return { backgroundColor: "#e1f9e8" };
} else {
return null;
}
},
and after that in this function onDemandsCellValueChanged please add and modify this property modified as true and change your function like this as shown below
onDemandsCellValueChanged(params): void {
if (params.oldValue === params.newValue) {
return;
}
const column = params.column.colDef.field;
params.data["modifiedRow" + params.rowIndex + "andCellKey" + column] = true;
params.api.refreshCells({
force: true,
columns: [column],
rowNodes: [params.node]
});
}
Now it should work even when you scroll. Here is complete working Example on stackblitz
Related
i want to show the selected items of listview in a grid. all selected items should show on the home page. but i cant find a way to do so. i have attached the js file code and screenshot of the popup
var subItemsLoaded = false,
SubItemSelectionModalId = '#subItemSelectionModal';
listViewHeight = 400,
subItemClicked = 0;
$(SubItemSelectionModalId).on('shown.bs.modal', function () {
if (
(window.selections.assetTemplate.id != null &&
window.selections.assetTemplate.id != 0)) {
$(SubItemSelectionModalId + ' .modal-body').ejWaitingPopup({
showOnInit: true
});
$(SubItemSelectionModalId + ' .listViewItems').ejListView({
"height": 400,
"loadComplete": function () {
repositionSearchBoxFor(SubItemSelectionModalId);
var obj = $(SubItemSelectionModalId + ' .modal-body').data("ejWaitingPopup");
console.log("12345.5");
obj.hide();
console.log("123456");
},
"mouseUp": function (e) {
},
"enableAjax": true,
"enableCheckMark": true,
"enableFiltering": true,
"dataSource": ej.DataManager({
"url": "/Shared",
"cachingPageSize": 0,
"timeTillExpiration": 0
}),
"query": ej.Query().from("GetSubItems").addParams("assetTemplateId", window.selections.assetTemplate.id).addParams("assetTemplateVariantId", window.selections.assetTemplateVariant.id),
"fieldSettings": {
"text": "SubItemName",
"id": "SubItemId"
}
});
}
});
$(SubItemSelectionModalId).on('hidden.bs.modal', function () {
var listViewItems = $(SubItemSelectionModalId + ' .listViewItems');
if (listViewItems.find('ul').length > 0) {
var selections = $(SubItemSelectionModalId + ' .listViewItems').ejListView("getCheckedItems");
if (selections.length > 0) {
$('#selectedSubItems').html(selections.join(' , ')).removeClass('hidden');
}
}
});
enter image description here
Yes, it is possible to show the selected items of the Listview in a Grid. For this, you have to use the mouseUp event of the Listview to take the selected items of the list and then give these selected items as the dataSource for the Grid control.
Also in order to get the ID of the selected list, you have to get the ID attribute and take its ID and bind the ID field as one of the columns of the Grid control. This way, you can get the ID of a particular list in a Listview and then bind it to the Grid.
We have also prepared a sample for your reference: http://jsplayground.syncfusion.com/prahqy2i
Regards,
Arun P.
I am trying to customize the behaviour of Angular Gantt.
On cell click : I have to get the current cell value & corresponding header value.
I gone thru the documentation present in this url : https://angular-gantt.readthedocs.io/en/latest/
but couldn't get the required event.
Is there any event present to achieve this functionality. Any help is much appreciated.
I tried following code
mainApp.controller("TestController", function ($scope, TestService) {
$scope.registerApi = function (api) {
api.tasks.on.change($scope, onTaskChange); //working
//TO handle the cell click & corresponding header value
api.core.getDateByPosition($scope, getHeader)
//api.core.on.ready($scope, getDateByPosition) //not working
//api.core.on.rendered($scope, getDateByPosition) //not working
}
var onTaskChange = function (selected) {
$scope.currCell = selected.model;
console.log("onTaskChange: " + selected.model.name);
};
var getHeader= function (getHeader) {
// I should get the current clicked cell header value. But getting error
};
}
Answering my own question as someone may find it useful.
I am able to achieve this from this link
https://angular-gantt.readthedocs.io/en/latest/configuration/customize/
Following is the code which I used:
$scope.registerApi = function (api) {
api.directives.on.new($scope, function (dName, dScope, dElement, dAttrs, dController) {
if (dName === 'ganttTask') {
dElement.bind('click', function (event) {
debugger;
$scope.RowName1 = dScope.task.row.model;
$scope.currentTask = dScope.task.model;
});
}
else if (dName === 'ganttRow')
{
dElement.bind('click', function (event) {
debugger;
$scope.RowName = dScope.row.model.name;
$scope.Header = api.core.getDateByPosition(event.offsetX, true)
});
}
});
I'm trying to tie a function to be executed after the renderRow event of the grid. So I used the aspect.after from DOJO, but here is the kicker. This execute before the row is indeed rendered, therefore the divs\tds are not on the screen yet. And since I do want to use the position of the items, using the dojo/domgeometry returns an object filled with zeroes. How can I guarantee that my function will execute after the row is finished displaying?
Below you can find the JS where I'm calling it.
aspect.after(grid, 'renderRow', function(row, args) {
var object = args[0];
if (object.type == 'tipo_exec') {
row.className += ' black';
} else if(object.type == 'exec') {
row.className += ' gray';
} else if(object.type == 'ic') {
if ((typeof(object.dep)!='undefined') && (object.dep.length > 0)) {
require(['dojo/dom-geometry','dojo/dom-construct'],
function(domGeom, domConstruct){
console.log(domGeom.position(row));
}
);
}
}
return row;
});
EDIT: Another thing, I'm using the tree extension, and the renderRow happens after a click on the parent to expand.
EDIT: So here is a bit of more info in case it is needed. The store is simple:
store = new Observable(new Memory({'data': data,
'getChildren': function(parent, options){
return this.query({'parent': parent.id}, options);
},
'mayHaveChildren': function(parent){
return parent.hasChildren;
}
}));
And the grid is declared as:
grid = new (declare([OnDemandGrid, Selection, Keyboard, CompoundColumns]))({
'columns': nCols,
'query': { 'parent': undefined },
'store': store
}, gridId);
This is the inside of the aspect after
if ((typeof(object.dep)!='undefined') && (object.dep.length > 0)) {
console.log('just before adding the refresh');
on.once(this, 'dgrid-refresh-complete', function(){
console.log('finished refreshing');
require(['dojo/dom-geometry','dojo/dom-construct'],
function(domGeom, domConstruct){
console.log(domGeom.position(node));
}
);
});
}
The console.log('finished refreshing');never gets called, neither does the the position log.
There are many columns on the grid, a couple tied on a compouding column, a name colum which is a tree, and a couple of others. The renderRow is called when expanding the tree!
Image of the grid with a couple of data removed
You can defer the invocation of domGeom.position(row) until the dgrid-refresh-complete event has been emitted. You'll need to include dojo/on.
aspect.after(grid, 'renderRow', function(row, args) {
var object = args[0];
if (object.type == 'tipo_exec') {
row.className += ' black';
} else if(object.type == 'exec') {
row.className += ' gray';
} else if(object.type == 'ic') {
if ((typeof(object.dep)!='undefined') && (object.dep.length > 0)) {
on.once(this, 'dgrid-refresh-complete', function(){
require(['dojo/dom-geometry','dojo/dom-construct'],
function(domGeom, domConstruct){
console.log(domGeom.position(row));
}
);
})
}
}
return row;
});
EDIT
Updated jsfiddle to accommodate tree
http://jsfiddle.net/rayotte/q8bCx/2/
I have a dataTable object on a page representing a list of releases I need to keep track of with the url /releases I want to add the following functionality
if /releases?query=<query>, the dataTable will initialized with the provided query
The query parameter is updated if the user changes the search term
The back and forward buttons in the browser go the appropriate query
So far I am able to do the first 2, but when I listen for the popstate event, redrawing the table triggers a pushState which I can't figure out how to prevent. Here's my code so far:
$(document).ready(function(){
var prevSearch;
var table = $('#releases').dataTable({
"bJQueryUI" : true,
"sPaginationType" : "full_numbers",
"iDisplayLength" : 50,
"oSearch": {"sSearch": '#{params[:query]}'},
"fnDrawCallback": function(oSettings) {
var curSearch = oSettings.oPreviousSearch.sSearch;
if (!prevSearch) {
prevSearch = curSearch;
} else if (curSearch != prevSearch) {
console.log("changed to: " + curSearch);
history.pushState({query: curSearch}, "title", "releases?query=" + curSearch);
prevSearch = curSearch;
}
}
});
window.addEventListener("popstate", function(e) {
if (e.state) {
table.fnFilter(e.state.query);
}
});
});
Note, I am using a rails backend and this is inlined javascript being served in the page.
you have only 2 options here:
move pushState code out of drawCallback. There must be some other code that causes the datatables to draw when user enters something. put your pushState code there. This is the ideal solution
add a hack like this
$(document).ready(function () {
var prevSearch;
var saveState = true;
var table = $('#releases').dataTable({
"bJQueryUI":true,
"sPaginationType":"full_numbers",
"iDisplayLength":50,
"oSearch":{"sSearch":'#{params[:query]}'},
"fnDrawCallback":function (oSettings) {
var curSearch = oSettings.oPreviousSearch.sSearch;
if (!prevSearch) {
prevSearch = curSearch;
} else if (curSearch != prevSearch) {
console.log("changed to: " + curSearch);
if (saveState) {
history.pushState({query:curSearch}, "title", "releases?query=" + curSearch);
}
prevSearch = curSearch;
}
}
});
window.addEventListener("popstate", function (e) {
if (e.state) {
saveState = false;
table.fnFilter(e.state.query);
saveState = true;
}
});
});
I currently have a GridPanel with the Ext.ux.RowEditor plugin. Four fields exist in the row editor: port, ip address, subnet and DHCP. If the DHCP field (checkbox) of the selected row is checked, I need to make the other three fields un-editable.
I've been trying to perform this code when the beforeedit event is triggered, but to no avail... I've only found ways to make the entire column un-editable. My code so far:
this.rowEditor.on({
scope: this,
beforeedit: this.checkIfEditable
});
checkIfEditable:function(rowEditor, rowIndex) {
if(this.getStore().getAt(rowIndex).get('dhcp')) {
// this function makes the entire column un-editable:
this.getColumnModel().setEditable(2, false);
// I want to make only the other three fields of the current row
// uneditable.
}
}
Please let me know if any clarification is needed.
Any help potentially extending RowEditor to accomplish the target functionality would be greatly appreciated as well!
You can add into RowEditor.js within the function startEditing the call to the function isCellEditable
//.... RowEditor.js
startEditing: function(rowIndex, doFocus){
//.... search for the starting of the below loop into the source code
var cm = g.getColumnModel(), fields = this.items.items, f, val;
for(var i = 0, len = cm.getColumnCount(); i < len; i++){
val = this.preEditValue(record, cm.getDataIndex(i));
f = fields[i];
f.setValue(val);
// *** here add a call to isCellEditable *** //
f.setDisabled(!cm.isCellEditable(i, rowIndex));
// ***************************************** //
this.values[f.id] = Ext.isEmpty(val) ? '' : val;
}
//....
Then override the isCellEditable of your column model and disabled the field based on you condition:
YYY.getColumnModel().isCellEditable = function(colIndex, rowIndex){
if (grid.getStore().getAt(rowIndex).get('dhcp')) {
// you can do more check base on colIndex
// only to disabled the one you want
return false;
}
return Ext.grid.ColumnModel.prototype.isCellEditable.call(this, colIndex, rowIndex);
}
As the docs state:
If the listener returns false
the editor will not be activated.
So...
this.rowEditor.on({
scope: this,
beforeedit: this.checkIfEditable
});
checkIfEditable:function(rowEditor, rowIndex) {
if(this.getStore().getAt(rowIndex).get('dhcp')) {
return false;
}
}
Simply returning false will be enough to cancel the editing ability.
Gotcha.
Interesting idea - a bit of a hassle to implement, but possible.
You need to approach this from two directions:
1 ) edit starts
2 ) checkbox is checked/unchecked
For the first part, I think you could use almost the same code I have above, remove the 'return false' and use the reference to the rowEditor to loop through the items collection, disabling (call the disable method on them) the fields that are not your checkbox field.
The second part of this is to add a handler to the checkbox which would do the same thing.
The following works to make a specific cell uneditable (add the event to the roweditor):
beforeedit: function (roweditor, rowIndex) {
var data = roweditor.grid.store.getAt(rowIndex).data;
var cm = roweditor.grid.getColumnModel();
// disable the first column (can not be edited)
if (** make your check here ***) {
var c = cm.getColumnAt(0);
c.editor.disable();
}
roweditor.initFields();
}
As of ExtJS 3.4 you can just override isCellEditable, as in the example here:
http://docs.sencha.com/ext-js/3-4/#!/api/Ext.grid.ColumnModel-method-isCellEditable
Here's the simpler version :
http://jsfiddle.net/snehalmasne/8twwywcp/
plugins: [
Ext.create('Ext.grid.plugin.CellEditing', {
clicksToEdit: 1
,pluginId: 'editing'
})
]
Provide the condition below for the cells to make the un-editable :
grid.on('beforeedit', function(editor, e) {
if (e.record.get('phone') == '555-111-1224')
return false;
});
just set the column in your columnModel/columns to editable:false for fields that should not be editable.
columns: [
{ header: "Ticker", width: 60, editable:false },
{ header: "Company Name", width: 150, id: 'company'},
{ header: "Market Cap."},
{ header: "$ Sales", renderer: money},
{ header: "Employees", resizable: false}
]
I ran into the same problem. Rather than using the GridPanel with the Ext.ux.RowEditor plugin, I used the Ext.grid.EditorGridPanel. In this case, you can specify the editor for each of the other three fields (port, ip address, and subnet) in the column model with a beforeshow event handler as follows:
editor: new Ext.form.TextArea({
height:80,
allowBlank: false,
listeners:{
beforeshow: function(column) {
if (column.gridEditor.record.get('dhcp')) {
column.gridEditor.cancelEdit();
}
}
}
})
Ha!
I made a dirty one, I added an event this.fireEvent('starting', this, fields,record); AT THE END of startEditing
startEditing: function(rowIndex, doFocus){
if(this.editing && this.isDirty()){
this.showTooltip(this.commitChangesText);
return;
}
if(Ext.isObject(rowIndex)){
rowIndex = this.grid.getStore().indexOf(rowIndex);
}
if(this.fireEvent('beforeedit', this, rowIndex) !== false){
this.editing = true;
var g = this.grid, view = g.getView(),
row = view.getRow(rowIndex),
record = g.store.getAt(rowIndex);
this.record = record;
this.rowIndex = rowIndex;
this.values = {};
if(!this.rendered){
this.render(view.getEditorParent());
}
var w = Ext.fly(row).getWidth();
this.setSize(w);
if(!this.initialized){
this.initFields();
}
var cm = g.getColumnModel(), fields = this.items.items, f, val;
for(var i = 0, len = cm.getColumnCount(); i < len; i++){
val = this.preEditValue(record, cm.getDataIndex(i));
f = fields[i];
f.setValue(val);
this.values[f.id] = Ext.isEmpty(val) ? '' : val;
}
this.verifyLayout(true);
if(!this.isVisible()){
this.setPagePosition(Ext.fly(row).getXY());
} else{
this.el.setXY(Ext.fly(row).getXY(), {duration:0.15});
}
if(!this.isVisible()){
this.show().doLayout();
}
if(doFocus !== false){
this.doFocus.defer(this.focusDelay, this);
}
/*I ADDED THIS EVENT ---- contains the fields and record
*/
this.fireEvent('starting', this, fields,record);
}
}
THEN
var editor = new Ext.ux.grid.RowEditor({
saveText: 'Update',
listeners : {
'starting' : function(rowEditor, fields, record){
if(!record.data.equipo_id){
fields[4].setDisabled(false);
}else{
fields[4].setDisabled(true);
}
},
Using Ext JS 4 and the RowEditing plugin i managed to achieve this using something like
rowEditor.on('beforeedit', function (context) {
this.editor.query('textfield')[0].setDisabled(/* your condition here */);
});
the record data is available through context.record.data