I have a slickgrid that, in the 'onMouseEnter' event, I do the following:
change the underlying css for the row in question
call grid.invalidateRow()
call grid.render()
These latter two calls are necessary for the new css classes to be reflected. However, I then need to capture the onMouseLeave event, and it is not fired when I move my mouse away from the cell (or row), presumably because the call to invalidate/render has placed a new DOM element under my mouse, and it's no longer the one I initially "entered."
So I have two questions:
Is there another way to have the new css classes for a given cell be rendered without calling invalidateRow/render?
If not, is there another way to do this and still have the onMouseLeave event fired?
One option is to use the setCellCssStyles function.
grid.onMouseEnter.subscribe(function(e, args){
var cell = grid.getCellFromEvent(e),
param = {},
columnCss = {};
for(index in columns){
var id = columns[index].id;
columnCss[id] = 'my_highlighter_style'
}
param[cell.row] = columnCss
args.grid.setCellCssStyles("row_highlighter", param);
})
So the above changes the background-color of every cell of the row that has been moused into. In my fiddle, the mouseLeave subscription performs a simple console.log to ensure it is still firing.
Edit: fixed the external resource usages in the fiddle for cross-browser support
Related
What is the best way to set a saved grid state after the angular-slickgrid has already been created? The Grid State/Presets - Wiki explains setting the saved state on load by setting the gridOptions.presets. In my case, I would like to update the grid state when the underlying saved state has changed in local storage (perhaps saved from another instantiation of the app), and apply the state to the current slickgrid. If I update the gridOptions.presets, is there a method I can call to force the grid to update with the new presets?
Please note that I'm the author of Angular-Slickgrid.
The answer is No it's called Presets for a reason, it only works when creating the grid...but you can still do it with a few method calls. So if you really wanted to use the Grid State then you'll have to save it yourself and then reload the entire grid after applying all previous State. The Grid State that can be applied dynamically are the Filters and Sorting which you can see in Example 4 and Example 25 (with a button click or a dropdown selection like the last example). I did later add a method to change the columns as well and that one is demoed under this Slickgrid-Universal Example 11, in fact that demo will show you exactly the way you want to do it, you can follow the code here.
for a short code sample, you'll need to get the angularGrid instance from (onAngularGridCreated) and then use it to dynamically change the grid. It shows you all the options, you can skip any of them if you don't need or want to change that option.
angularGridReady(angularGrid: AngularGridInstance) {
this.angularGrid = angularGrid;
}
// the `selectedView` should be the result of your Grid State
changeGridView(selectedView: GridState) {
if (selectedView) {
const columns = selectedView?.columns ?? [];
const filters = selectedView?.filters ?? [];
const sorters = selectedView?.sorters ?? [];
this.angularGrid.filterService.updateFilters(filters as CurrentFilter[]);
this.angularGrid.sortService.updateSorting(sorters as CurrentSorter[]);
this.angularGrid.gridStateService.changeColumnsArrangement(columns);
// if you have a frozen grid (pinning)
this.angularGrid.gridService.setPinning(pinning);
} else {
// to reset the grid
this.angularGrid.filterService.clearFilters();
this.angularGrid.sortService.clearSorting(); this.angularGrid.gridStateService.changeColumnsArrangement([...this.columnDefinitions].map(col => ({ columnId: `${col.id}` })));
// if you have a frozen grid (pinning)
this.angularGrid.gridService.clearPinning();
}
// you might want to scroll back to top of the grid if filters are changed
this.angularGrid.slickGrid.scrollColumnIntoView(0);
}
You might not need to re-render the grid but in case the grid UI doesn't show correctly, you could force a re-render of the grid by invalidating all its rows
this.angularGrid.slickGrid.invalidate();
I am trying to change the recordtext of a display grid to a custom format. I am using a treeview as the selector that refreshes the display grid. I need to find the total records for the grid and I am able to get this value using the getGridParam records method when I click on the treeview node and load the display grid.
However, after I get this value and try to create the custom recordtext, the record count is the previous value, not the current records count. I know that the gridComplete happens before the loadComplete, but even placing the get in the gridComplete and the set int he loadComplete, it still doesn't work, even with a reloadGrid trigger. If I click on the treeview node twice, I get the correct value.
I am thinking it is a timing issue as to when the new value is ready to set the recordtext. Any help would be great, thanks in advance.
I recommend you to try updatepager method, which updates the information on the pager. Alternatively you can do for example the following:
loadComplete: function () {
var p = $(this).jqGrid("getGridParam");
p.records = 123;
p.recordtext = "My View {0} - {1} of <i>{2}<i>";
this.updatepager();
}
to see the viewrecords
I have a grid that is locally initialized from an array data. after adding the rows to it I want to be able to get the event of the scrollbar when it reaches to the end and load more rows locally.
(the grid has certain height and 'overflow-y' : scroll)
How can this be done?
Thanks In Advance.
You can see the code for loading more data at line 1831 of grid.base.js:
case "local":
case "clientside":
beginReq();
ts.p.datatype = "local";
var req = addLocalData();
addJSONData(req,ts.grid.bDiv,rcnt,npage>1,adjust);
$(ts).triggerHandler("jqGridLoadComplete", [req]);
if(lc) { lc.call(ts,req); }
$(ts).triggerHandler("jqGridAfterLoadComplete", [req]);
if (pvis) { ts.grid.populateVisible(); }
endReq();
The good news is that the loadComplete event is called, so you can put your code there. The only complication is that loadComplete may also be called when the grid is initially constructed, so you have to take that into account as well.
I have a form with 2 text inputs and 2 span controls. Normally, when textbox A is changed an event is fired to change span A, and when textbox B is changed, an event is fired to change span B.
However, in one particualar case I would like a change either textbox A or textbox B to update both span A and B. I tried wiring the events up to the corresponding controls in this case, but it didn't work because there is much state that is set up in the event building code (not to mention each event calls 'this', which would make the logic use the wrong control if it were fired from a different one than it was intended).
To make things easy, it would be best to pass a string (representing the other text input id) to the event handler at the time it is created, and then calling the change() event manually on the second control. However, this puts things in an infinite loop of recursion. I thought of a way to get around the recursion, but it reqires a global variable.
Is there a better way than this, preferably one that doesn't require a global variable?
ml_inEvent = false;
$ctlToVal.bind('keyup change', {feedbackCtl: ml_feedback, controlsToMonitor: ary, validationGroup: this.validationGroup, controlToFire: ctlToFire}, function(event) {
// Other processing happens here...
if (event.data.controlToFire != '') {
var $controlToFire = $('#' + event.data.controlToFire);
if ($controlToFire.length) {
// Use a global variable to ensure this event is not fired again
// as a result of calling the other one
if (!ml_inEvent) {
ml_inEvent = true;
$controlToFire.change();
ml_inEvent = false;
}
}
}
});
You can use the extraParameters argument on .trigger() to break out, for example:
$ctlToVal.bind('keyup change', {feedbackCtl: ml_feedback, controlsToMonitor: ary, validationGroup: this.validationGroup, controlToFire: ctlToFire}, function(event, fire) {
// Other processing happens here...
if(fire !== false) $('#' + event.data.controlToFire).trigger('change', false);
});
You can give it a try here. What this does is the event handler callback not only receives the event object but also any other arguments you pass in, in this case we're just using a simple false and a !=== check this in important so undefined (the parameter not passed at all) still changes both controls. So for instance $("#control").change() would change both controls, but still not loop...you can test that here.
When using Sortable.create I can't seem to get the element that is being dragged. Does Sciptaculous not fully implement all Draggable and Droppable features when you use sortable?
Given:
Sortable.create("sortArea", {scroll:window, onChange:orderLi});
function orderLi(){
console.log(this.draggables.each(function(e){if(e.dragging==true){return e};}));
}
My console always shows all the array of draggables. How do I only grab the one that is being dragged?
The onChange function actually gets a handle to the element passed in.
Sortable.create("sortArea", {scroll:window, onChange:orderLi});
function orderLi(elementBeingDragged){
console.log(elementBeingDragged);
}