After each cell change, I am sending the cell's content to the backend, getting updated meta object and am applying it to the cell. The new meta object holds a different colour for the renderer. I need to retrigger cell rendering after I've set the meta data. I found the event afterSetCellMeta() but I can't find a way to rerender a single cell only. Just for reference, this is the function I am using:
function updateCell(data) {
var i = 0;
var to = data.length;
for (i; i<to; i++) { // Go trough all changed cells, update their meta object.
var row = data[i].row;
var col = data[i].col;
var metaObject = data[i];
console.log('About to set: ', metaObject);
vm.hot.setCellMetaObject(row, col, metaObject);
// I need to update the renderer here.
}
}
Anyone had done that? Any ideas are appreciated, since I'm out of any.
Handsontable doesn't just re-render a single cell. Any event that triggers a change will re-render the entire table. This is done on purpose to make sure the table is "state-less" and always reflecting what the data represents. With that said, what's the problem with re-rendering the whole table? It should be pretty quick since HOT uses virtual rendering but are you seeing issues there?
If what you mean is that you want to update your renderer, then where you have that comment on updating the renderer you can insert:
hot.updateSettings({
cells: newCellsDefinition // here you would define a new renderer for whatever cells you want to change the renderer for
});
Related
I'm trying to update an ag-Grid row data the following way:
this.table.api.updateRowData({
update: [response.data]
})
The updating works fine, the cells get the updated values. However, Ag Grid is not re-evaluating the class of the row. Additionally, I get an error message:
ag-Grid: could not find data item as object was not found
Here is my rowClassRule:
rowClassRules: {
"row-disabled": function(params) {
if (params.data.status != 1) {
return true
}
}
}
What am I doing wrong here and how can I get ag Grid to update the class as well? I have tried using: rowNode.setData() which was working perfectly (updating the cell value + class) - but I can't use it because it's not refreshing the filters, unfortunately.
After setting the new row data, since you are using rowClass feature you have to use api.redrawRows()
rowNode.setData() being an api method is closely tied with ag-grid change detection mechanism and would automatically trigger api.refreshCells() for you. But if you are manually updating the data set, you need to invoke api.redrawRows() for styles to change.
As per docs -
Use redraw row if you want to create the row again from scratch. This
is useful when you have changed a property that only gets used when
the row is created for the first time such as:
Whether the row is fullWidth or not.
The cellRenderer used for any cell (as this is specified once when the cell is created).
You want to specify different styles for the row via the callbacks getRowStyle() or getRowClass().
Example here - redraw nodes
When users modify any data in the table and on click of the cancel button i need to restore the data to original state .
Issue is, resetRowData() function is not resetting the original value but instead it deletes all the record in the table. Please help
Note: I'm using Angular 2
resetRowData() {
this.rowData = [];
this.gridOptions.api.setRowData(this.rowData);
}
<button class="secondary-btn btn-pair" (click)="onCancelRowClicked()">Cancel</button>
There is an API provided by Ag-Grid. If you pass true as the parameter, data will be reset to the original value.
api.stopEditing(true);
Ref - https://www.ag-grid.com/javascript-grid-cell-editing/#editing-api
I'm trying to flatten my data structure so I have Flights, and inside Users I have a node called currentTrip, which contains the ID for all the flights a person has in a current trip. The Id maps to the Id of the flight in Flights.
If I was just querying Flights, I can get the datasource set and it will continue to update the listview perfectly as the data changes.
But since I'm trying to flatten, I can't seem to find the right spot to set the new datasource. If I set it where I expect, it gets set before any of the flights are finished adding to a flights array. If I set it directly after a new flight is pushed to the array, then each new change results in a whole new copy of the flight being added. I hesitate to use .once because I want the data to remain fresh and real-time.
Here is the code for the FB piece. This is within a React Native project. I'm sure I'm just thinking too synchronously.
listenForItems(tripRef) {
var flightRef = this.getRef().child('flights')
var tripSegments = [];
var flights = [];
tripRef.on('value', (snap) => {
// Create a list of Trip Segments
snap.forEach((child) => {
// For each segment, get the ID and then go get the flight details
var indFlightRef = flightRef.child(child.val().legId);
indFlightRef.on('value', (snap) => {
flights.push({
departureAir: snap.val().depAir,
_key: child.key
});
});
});
// In a synchronous world I would expect to set the new datasource here
this.setState({
dataSource: this.state.dataSource.cloneWithRows(flights)
});
});
}
Any nudge in the right direction would be awesome. Thanks.
UPDATE EDIT: If I setState directly after flights.push my initial ListView is perfect. If I expect 2 rows, I see the two rows. However... if the data changes in any of the existing nodes, it won't simply update the corresponding row in the ListView, it will add a whole new row.
Is there a way to know on the client side when the data has been re-rendered?
I am using aldeed:tabular package and the problem I'm having is that when the data changes, I loose my selected highlighted row because the table is completely redrawn.
So, I need to catch this re-rendering event in order to re-highlight my selected row.
When you create your data table options, add a callback function for the drawCallback property, documented here
Like so:
TabularTables.MyTable = new Tabular.Table({
// other DT properties...
drawCallback: function( settings ) {
// do your magic here
}
});
(I know there are other questions here asking the same thing; I've tried them and they don't apply here)
I have a collection being displayed by a Knockout JS foreach. For each item, the visible binding is set by call a method, based on something external to the item itself. When the externality changes, I need the UI to be redrawn.
A striped down version can be seen in this Fiddle: http://jsfiddle.net/JamesCurran/2us8m/2/
It starts with a list of four folder names, and displays the ones starting with 'S'.
<ul data-bind="foreach: folders">
<li data-bind="text: $data,
visible:$root.ShowFolder($data)"></li>
</ul>
<button data-bind="click:ToA">A Folders</button>
Clicking the button should display the ones starting with 'A' instead.
self.folders = ko.observableArray(['Active', 'Archive', 'Sent', 'Spam']);
self.letter = 'S';
// Behaviours
self.ShowFolder = function (folder)
{
return folder[0] === self.letter;
}
self.ToA = function ()
{
self.letter = 'A';
}
UPDATE:
After Loic showed me how easily this example could be fixed, I reviewed the differences between this example and my actual code. I'm using an empty object as a dictionary to toggle if an item is selected self.Selected()[item.Id] = !self.Selected()[item.Id];
The object being changed is already an observable. I assumed that Knockout didn't realize that the list is dependent on the external observable, but it does. What Knockout was missing was that the observable was in fact changing. So, the solution was simply:
self.Selected()[item.Id] = !self.Selected()[item.Id];
self.Selected.notifySubscribers();
Here's what I came up with:
What you have to understand is that Knockout is only "answering" to data changes in observables. If an observable changes, it will trigger every object that uses it. By making your self.letter an observable. You can simply change it's value and uses it somewhere like self.letter() and it will automagically redraw when needed.
http://jsfiddle.net/2us8m/3/
function WebmailViewModel() {
// Data
var self = this;
self.folders = ko.observableArray(['Active', 'Archive', 'Sent', 'Spam']);
self.letter = ko.observable('S');
// Behaviours
self.ShowFolder = function (folder)
{
return folder[0] === self.letter();
}
self.ToA = function ()
{
self.letter('A');
}
};
ko.applyBindings(new WebmailViewModel());
In case you have complex bindings, like storing an object inside an observable. If you want to modify that object you have multiple possible choices.
self.Selected()[item.Id] = !self.Selected()[item.Id];
You could change it to this by making everything "observables" but if my memory is right, it can become complicated.
self.Selected()[item.Id](!self.Selected()[item.Id]());
I remember I had one similar issue where I had dependency problem where I had to update a country, region, city. I ended up storing it as list inside an observable to prevent update on individual element change. I had something like this.
var path = PathToCity();
path[0] = 'all';
path[1] = 'all';
PathtoCity(path);
By doing this, the change would be atomic and there will be only one update. I haven't played a lot with knockout for a while. I'm not sure but I do believe that the last time I worked with knockout, it was able to "optimize" and prevent to redraw the whole thing. But be careful because if it is not able to guess that you didn't change many thing, it could redraw the whole observable tree (which could end up pretty bad in term of performance)
In your example, we could use the same behaviour with my modified example:
http://jsfiddle.net/2us8m/4/