How do you stop scrolling to top when grid store is reloaded - extjs3

I have an app that uses ExtJS 3.3.0. It uses an EditorGridPanel in which after the store is reloaded - I would like it to preserve the scroll position of the grid rather than sending it back up to the top.
Because this is an earlier version of ExtJS - this DOES NOT work:
viewConfig: {
preserveScrollOnRefresh: true
}
So far the only thing I can come up with is to save the position of the scroll bar prior to loading - and then reset the position once the reload is complete.
I can get as far as saving the position:
var scrollPos;
bodyscroll: function(sl, st) {
scrollPos = st;
},
However I can't figure out how to set the position afterwards.
Any suggestions?
Thanks in advance.

There might be multiple ways to do this but one way is to use the scroller element, which is accessible through the grid's gridview. See fiddle here: Grid scoll save/restore.
To get scroll value (which you've already got figured out):
var top = grid.getView().scroller.getScroll().top;
To restore:
grid.getView().scroller.scrollTo('top',top);

Related

Can QML drag-and-drop mechanic work without drag item moving?

I have a listview and a rectangle on top of it. The ListView's delegates have DropAreas in them and the rectangle has drag enabled on Y axis with its relevant properties (hotspot, target).
When I move the rectangle up and down on the ListView, the DropAreas of the delegates are registering onEntered signals. Working as intended.
However, I am using SmoothedAnimation to scroll the list up and down when the rectangle is at the most top and bottom coordinates (list.y = 0 and list.height). So the rectangle is not moving, and the DropAreas of the list's delegates are moving under it. In that case, the onEntered is not registered because there is no dragging, the rectangle is completely still and although its hotspot is entering and leaving the DropAreas, there is no interaction.
This is because dragging mechanic is sending events all the time when moving and any DropAreas it comes inside can register the event. In my case there is no dragging and therefore no events.
Question: Can drag events be manually activated? Can I somehow simulate drag?
At first, you should change the drag.target: parent to drag.target: this. In this way instead of dragging the parent item, you drag only the mouseArea. After that, you should grab an image from the item that you want to drag. The code is here:
Rectangle {
id: rec
width: 100
height: 100
Drag.active: dragArea.drag.active
Drag.dragType: Drag.Automatic
Drag.supportedActions: Qt.CopyAction
MouseArea {
id: dragArea
anchors.fill: parent
drag.target: this
onPressed:{
parent.grabToImage(function(result) {
parent.Drag.imageSource = result.url
})
}
}
}
I have managed to induce drag events by manually changing the hotSpot property of the rectangle above the list. QML Drag documentation says:
Changes to hotSpot trigger a new drag move with the updated position.
So I have done this every time Listview contentY changes (vertical scrolling happens)
onContentYChanged:
{
rectangle.Drag.hotSpot.x += 0.0001
rectangle.Drag.hotSpot.x -= 0.0001
}
In hindsight, however, this is a 'hacky' solution. hotSpot property is a QPointF class property (link). This means it can be set using various methods (setX, setY, rx, ry..). For example, this:
rectangle.hotSpot += Qt.point(0,0)
or
rectangle.hotSpot = Qt.point(rectangle.hotSpot.x,rectangle.hotSpot.y)
should work in theory by resetting the hotSpot point when contentY changes, but testing revealed it unfortunately does not trigger a new drag move. (bug or intended, I don't know)
Now some of you that are more into Qt and QML might know more about this and how to properly adress the issue, but the above solution works for me and after testing everything I could imagine to get a cleaner solution, I settled on it.

How to make AG-Grid to have fluid layout

I'm trying to use the AG-Grid for my project and I've been trying to play around with it for a while now, but one problem I came across with this grid is that I can't easily make the columns to auto resize whenever the div or browser resizes like a fluid layout.
I know there is the .api.sizeColumnsToFit() function to use which will do it once it's called, but this would mean I will to manually add a listener or some sort to the window to check if it has been resize and call it if it has?? Is there a better way to achieve this??
Thanks
Try calling sizeColumnsToFit whenever the grid onGridSizeChanged event fires. The following will run when the grid first loads/ or data adjusts (onModelUpdated) and when the grids size changes.
i.e
this.gridOptions = <GridOptions>{
onModelUpdated: () => {
this.gridOptions.api.sizeColumnsToFit();
},
onGridSizeChanged: () => {
this.gridOptions.api.sizeColumnsToFit();
}
};

How to save scroll position on an extjs form?

I have a long form with comboboxes and buttons that add element to the form. Every time combobox's value gets upldated or elements get added, it scrolls up to the top of the form. I want the scrollbar to retain its position. I tried saving current scroll position by doing
this.myForm.getScrollPosition();
But I get getScrollPosition is not a function error.
Any help on this?
If you are using extjs there is a way to manipulate the scroll using the Ext.dom.Element class, each component in Extjs inherits from it, then if you add a new component that modifies the height or width of your form, you can first get the height and width of that component using:
var newcompwidth = comboboxexample.getWidth();
var newcompheight = comboboxeample.getHeight();
Later you can modify the scroll value using scrollTo method like this:
myformcontainer.getEl().scrollTo('Top',myformcontainer.getEl().getScroll().top - newcompheight);
myformcontainer.getEl().scrollTo('Top',myformcontainer.getEl().getScroll().left - newcompwidth);
there are other methods like scrollBy or scroll but I didn't test it yet, I guess this will help you.
the docs: http://docs.sencha.com/extjs/4.1.0/#!/api/Ext.dom.Element

GWT drag and drop animation

I have a flow panel with many photo-widgets inside (gallery with random number of rows and columns, depends on screen size) for which I want to implement drag and drop behavior to change their order. I am using gwt-dnd library. Its FlowPanelDropController allows you to define your own positioner (delimiter) which shows the candidate location for dropping the dragged widget.
I want this positioner to be the empty space with defined width, and the challenging thing is to implement sliding animation effect for the when positioner is added and removed.
If you are a desktop Picasa app user you know what I mean: the target row slides both sides (little to the left, little to the right) extending the space between the items where you are going to drop a photo.
The whole thing is complex enough, but any help related to how to apply the animation for positioner attach/detach is appreciated. Maybe I need to use a different approach (e.g., use GWT native dnd instead of gwt-dnd lib and no "positioners" at all) if you have any ideas how this could be helpful.
Thanks.
Well, I ended up overriding AbstractPositioningDropController (parent of FlowPanelDropController) and adding some extra features.
1) newPositioner() method now builds the Label, which is vertical space with some small width, height and decoration. This widget's element has constant id (say, "POSITIONER"), which helps to distinguish between multiple positioners if you plan to have several of them while navigating with a drag object over multiple drop targets. Also some transition CSS effects were applied to the Label, which will be responsible for handling animated extension of Label's width.
2) in onEnter() I do the following
...
removePositioner(getPositionerElement());
Widget positioner = newPositioner();
dropTarget.insert(positioner, targetIndex);
animatePositionerExtension();
where getPositionerElement() returns DOM.getElementById(POSITIONER)
At the same time removePositioner(..) resets the id of this element to something abstract and ideally should provide some animation before calling .removeFromParent(). But I didn't have enough time to properly debug this so ended up just removing the old positioner with no animation.
Method animatePositionerExtension() contains the code that changes the width of the positioner widget, so that CSS transition will catch that and provides animation.
All access to positioner widget in the class should be provided through updated methods.
3) onLeave() contains line removePositioner(getPositionerElement());
4) In the end of onMove() I added a couple of lines:
galleryWidget.extendHoveredRow(targetIndex - 1);
animatePositionerExtension();
where extendHoveredRow(hoveredWidgetOrdinal) implemented the logic to "limit" the sliding effect in the single line:
int rowHovered = -1;
public void extendHoveredRow(int hoveredWidgetOrdinal) {
int newRowHovered = getRowByOrdinalHovered(hoveredWidgetOrdinal);
if (rowHovered != newRowHovered) {
// adjust position of items in the previously hovered row
int firstInPreviouslyHoveredRow = (rowHovered - 1) * itemsInARow;
shiftFirstItemLeft(firstInPreviouslyHoveredRow, false);
rowHovered = newRowHovered;
// extend this row
int firstInThisRow = getOrdinalFirstInThisRowByOrdinal(hoveredWidgetOrdinal);
shiftFirstItemLeft(firstInThisRow, true);
}
}
This is in short how I did the thing. And still there's some room for improvements, like adding animated removal.
Again, it's all about overriding DropController and manipulations with elements inside the "gallery" widget. The benefit of this approach is that I remain in the gwt-dnd operations framework, and also reused a bunch of existent code.
Some notes:
CSS transition is not supported in IE pre-9, but this is unrelated to
this topic.
Put a transparent "glass" div on top of the Image widget if you use it
as a face of dragProxy. This will save you tons of time trying to
understand why either setting element's draggable to false, or
calling event.preventDefault() somewhere else, or other workarounds don't work in one or several browsers and the image itself is being dragged instead of the whole dragProxy widget.

GWT 2.4 DataGrid automatic scrolling when selecting an item

I am using GWT 2.4's new DataGrid in a project. I configured the DataGrid with a pagesize of 50.
The available screen is not big enough to display all items and thus a vertical scrollbar is shown (this is actually the main purpose for using a DataGrid in the first place).
I attached a SingleSelectionModel to the DataGrid in order to be able to select items.
This works fine so far.
However I also have another widget with which the user can interact. Based on that user action a item from the DataGrid should be selected.
Sometimes the selected item is not in the visible screen region and the user has to scroll down in the DataGrid to see it.
Is there any way to automatically or manually scroll down, so that the selected item is visible?
I checked the JavaDocs of the DataGrid and found no appropriate method or function for doing that.
Don't know if this works, but you could try to get the row element for the selection and use the scrollIntoView Method.
Example Code:
dataGrid.getRowElement(INDEX_OF_SELECTED_ITEM).scrollIntoView();
The answer above works pretty well, though if the grid is wider than your window and has a horizontal scroll bar, it also scrolls all the way to the right which is pretty annoying. I was able to get it to scroll down and stay scrolled left by getting the first cell in the selected row and then having it scroll that into view.
dataGrid.getRowElement(dataGrid.getVisibleItems().indexOf(object)).getCells().getItem(0).scrollIntoView();
Don't have time to try it out, but DataGrid implements the interface HasRows, and HasRows has, among other things, a method called setVisibleRange. You just need to figure out the row number of the item that you want to focus on, and then set the visible range from that number n to n+50. That way the DataGrid will reset to put that item at the top (or near the top if it is in the last 50 elements of the list backing the DataGrid). Don't forget to redraw your DataGrid.
Have you already looked at this? If so, I'd be surprised that it didn't work.
Oh, and since this is one widget talking to another, you probably have some messaging set up and some message handlers so that when the user interacts with that second widget and "selects" the item, the message fires on the EventBus and a handler for that message fixes up the DataGrid along the lines I've described. I think you'll have to do this wiring yourself.
My solution, a little better:
dataGrid.getRow(model).scrollIntoView();
I got a Out of bounds exception doing the above.
I solved it getting the ScrollPanel in the DataGrid and used .scrollToTop() and so on on the ScrollPanel. However, to access the ScrollPanel in the DataGrid I had to use this comment:
http://code.google.com/p/google-web-toolkit/issues/detail?id=6865
As Kem pointed out, it's annoying the "scrollToRight" effect after the scrollIntoView. After me, Kem's solution gives a better behaviour than the base one as usually the first columns in a table are the more meaningful.
I improved a bit his approach, which scrolls horizontally to the first column of the row we want to be visible, by calculating the first visible column on the left before applying the scroll and then scrolling to it.
A final note: Columns absolute left is tested against "51". This is a value I found "experimentally" by looking the JS values in the browser's developer tool, I think it depends on the table's style, you may need to change/calculate it.
Below the code:
public void scrollIntoView(T next) {
int index = datagrid.getVisibleItems().indexOf(next);
NodeList<TableCellElement> cells = datagrid.getRowElement(index).getCells();
int firstVisibleIndex = -1;
for(int i=0; i<cells.getLength() && firstVisibleIndex<0;i++)
if(UIObject.isVisible(cells.getItem(i)) && (cells.getItem(i).getAbsoluteLeft() > 51) && (cells.getItem(i).getAbsoluteTop() > 0))
firstVisibleIndex = i;
cells.getItem(firstVisibleIndex>=0? firstVisibleIndex : 0).scrollIntoView();
}