Results 1 to 4 of 4

Thread: Drag and drop on LiveGrid not working

    Thank you for reporting this bug. We will make it our priority to review this report.
  1. #1
    Sencha Premium Member
    Join Date
    Oct 2009
    Posts
    112

    Default Drag and drop on LiveGrid not working

    I had the following code working in GXT 3.1.4

    Code:
    new GridDragSource<T>(grd);
            GridDropTarget<T> drpTrgt = new GridDropTarget<T>(grd);
            drpTrgt.setAllowSelfAsSource(true);
            drpTrgt.setFeedback(Feedback.INSERT);
            drpTrgt.addDropHandler(new DndDropHandler() {
    
    
                @SuppressWarnings("unchecked")
                @Override
                public void onDrop(DndDropEvent event) {
                    ...
                }
            });
    After upgrading to GXT 4, it lets me drag, but I can't drop. It behaves like setAllowSelfAsSource(false).

    My grid is using LiveGridView, and I am using DndDropHandler to handle moving the item on server-side and reloading the view, which shouldn't affect the dnd behavior on client side.

  2. #2
    Sencha Premium Member
    Join Date
    Oct 2009
    Posts
    112

    Default

    Looks like it may be caused by a change in LiveGridView scroller implementation.

    In GripDropTarget.onDragMove, the following condition is always true for LiveGridView, setting drop allowed status to false:

    Code:
    if (Element.is(target) && !grid.getView().getScroller().isOrHasChild(Element.as(target))) {
          event.setCancelled(true);
          event.getStatusProxy().setStatus(false);
          return;
        }
    I override it with:

    Code:
    GridDropTarget<T> drpTrgt = new GridDropTarget<T>(grd) {
                @Override
                protected void onDragMove(DndDragMoveEvent event) {
                    Element target = getElementFromEvent(event.getDragMoveEvent().getNativeEvent());
    
    
                    if (Element.is(target) && !(grid.getView() instanceof LiveGridView)
                            && !grid.getView().getScroller().isOrHasChild(Element.as(target))) {
                        event.setCancelled(true);
                        event.getStatusProxy().setStatus(false);
                        return;
                    }
    
    
                    event.setCancelled(false);
                    event.getStatusProxy().setStatus(true);
                }
            };
    Which works for me, but not sure if it's correct.

    Not sure if it's bug. Could someone clarify?

    I think LiveGridView needs better documentation and support. Because it extends GridVew, it seems to support a lot of grid features, such as DnD. But over the years I have learned it has a lot of gotchas, such as:
    - fixed row height
    - couldn't handle touch scroll (until GXT 4)
    - DnD doesn't auto scroll.

    Would be nice if the documentation warns user about some of the gotchas.

  3. #3
    Sencha Sr Product Manager
    Join Date
    Jan 2012
    Location
    Arlington, WA
    Posts
    1,165

    Default

    I worked up a test case to test drag and drop with the live grid. I'm not sure I understand the issue quite yet.

    This allows me to drag and drop into the live grid. There is an issue with this mock up, is that it clobbers what I add if it pages through the data because it doesn't get persisted. I mocked up a server side code. But I think this might help provide some hints, or it will help me sync up with what you're experiencing.
    Code:
    import java.util.ArrayList;
    import java.util.List;
    
    
    import com.google.gwt.core.client.EntryPoint;
    import com.google.gwt.event.logical.shared.AttachEvent;
    import com.google.gwt.event.logical.shared.AttachEvent.Handler;
    import com.google.gwt.user.client.rpc.AsyncCallback;
    import com.google.gwt.user.client.ui.HasHorizontalAlignment;
    import com.google.gwt.user.client.ui.IsWidget;
    import com.google.gwt.user.client.ui.RootPanel;
    import com.google.gwt.user.client.ui.Widget;
    import com.sencha.gxt.core.client.ValueProvider;
    import com.sencha.gxt.core.client.util.Margins;
    import com.sencha.gxt.data.client.loader.RpcProxy;
    import com.sencha.gxt.data.shared.ListStore;
    import com.sencha.gxt.data.shared.ModelKeyProvider;
    import com.sencha.gxt.data.shared.loader.FilterPagingLoadConfig;
    import com.sencha.gxt.data.shared.loader.FilterPagingLoadConfigBean;
    import com.sencha.gxt.data.shared.loader.LoadResultListStoreBinding;
    import com.sencha.gxt.data.shared.loader.PagingLoadResult;
    import com.sencha.gxt.data.shared.loader.PagingLoader;
    import com.sencha.gxt.dnd.core.client.GridDragSource;
    import com.sencha.gxt.dnd.core.client.GridDropTarget;
    import com.sencha.gxt.dnd.core.client.DND.Feedback;
    import com.sencha.gxt.widget.core.client.ContentPanel;
    import com.sencha.gxt.widget.core.client.container.BorderLayoutContainer;
    import com.sencha.gxt.widget.core.client.container.BorderLayoutContainer.BorderLayoutData;
    import com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer;
    import com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer.VerticalLayoutData;
    import com.sencha.gxt.widget.core.client.grid.ColumnConfig;
    import com.sencha.gxt.widget.core.client.grid.ColumnModel;
    import com.sencha.gxt.widget.core.client.grid.Grid;
    import com.sencha.gxt.widget.core.client.grid.LiveGridView;
    import com.sencha.gxt.widget.core.client.grid.filters.StringFilter;
    
    
    public class LiveGridDndExample implements IsWidget, EntryPoint {
    
    
      protected static final int MIN_HEIGHT = 450;
      protected static final int MIN_WIDTH = 450;
    
    
      private VerticalLayoutContainer panel;
    
    
      private static final int COLUMNS_SIZE = 5;
      private static final int TOTAL_LENGTH = 300;
    
    
      private PagingLoader<FilterPagingLoadConfig, PagingLoadResult<Data>> pagingLoader1;
      private PagingLoader<FilterPagingLoadConfig, PagingLoadResult<Data>> pagingLoader2;
      private Grid<Data> grid1;
      private Grid<Data> grid2;
    
    
      @Override
      public Widget asWidget() {
        if (panel == null) {
          panel = new VerticalLayoutContainer();
          panel.add(createGrids1And2(), new VerticalLayoutData(1, 0.5, new Margins(0, 0, 10, 0)));
        }
    
    
        return panel;
      }
    
    
      private ContentPanel createGrids1And2() {
        ListStore<Data> listStore1 = getStore1();
        ListStore<Data> listStore2 = getStore2();
    
    
        LiveGridView<Data> liveGridView1 = new LiveGridView<Data>();
        LiveGridView<Data> liveGridView2 = new LiveGridView<Data>();
    
    
        ColumnModel<Data> cm1 = new ColumnModel<Data>(getColumns());
        ColumnModel<Data> cm2 = new ColumnModel<Data>(getColumns());
    
    
        pagingLoader1 = getLoader(listStore1, false);
        pagingLoader2 = getLoader(listStore2, true);
    
    
        grid1 = new Grid<Data>(listStore1, cm1, liveGridView1);
        grid1.setLoader(pagingLoader1);
        grid1.addAttachHandler(new Handler() {
          @Override
          public void onAttachOrDetach(AttachEvent event) {
            pagingLoader1.load();
          }
        });
    
    
        grid2 = new Grid<Data>(listStore2, cm2, liveGridView2);
        grid2.setLoader(pagingLoader2);
        grid2.addAttachHandler(new Handler() {
          @Override
          public void onAttachOrDetach(AttachEvent event) {
            pagingLoader2.load();
          }
        });
    
    
        GridDragSource<Data> gds1 = new GridDragSource<Data>(grid1);
        GridDragSource<Data> gds2 = new GridDragSource<Data>(grid2);
        
        gds1.setGroup("top");
        gds2.setGroup("top");
    
    
        GridDropTarget<Data> gdt1 = new GridDropTarget<Data>(grid1);
        GridDropTarget<Data> gdt2 = new GridDropTarget<Data>(grid2);
        
        gdt1.setGroup("top");
        gdt2.setGroup("top");
        
        gdt1.setFeedback(Feedback.INSERT);
        gdt2.setFeedback(Feedback.INSERT);
    
    
        BorderLayoutData westData = new BorderLayoutData(0.5);
        westData.setMargins(new Margins(0, 2, 0, 0));
    
    
        BorderLayoutData centerData = new BorderLayoutData();
        centerData.setMargins(new Margins(0, 0, 0, 2));
    
    
        BorderLayoutContainer borderLayoutContainer = new BorderLayoutContainer();
        borderLayoutContainer.setWestWidget(grid1, westData);
        borderLayoutContainer.setCenterWidget(grid2, centerData);
    
    
        ContentPanel panel = new ContentPanel();
        panel.setHeadingText("Grid to Grid  Insert at Sort Position");
        panel.add(borderLayoutContainer);
    
    
        return panel;
      }
    
    
      private ListStore<Data> getStore1() {
        ListStore<Data> store = new ListStore<Data>(new ModelKeyProvider<Data>() {
          @Override
          public String getKey(Data item) {
            return "a" + item.getKey();
          }
        });
        return store;
      }
    
    
      private ListStore<Data> getStore2() {
        ListStore<Data> store = new ListStore<Data>(new ModelKeyProvider<Data>() {
          @Override
          public String getKey(Data item) {
            return "b" + item.getKey();
          }
        });
        return store;
      }
    
    
      @Override
      public void onModuleLoad() {
        ContentPanel cp = new ContentPanel();
        cp.add(asWidget());
        cp.setPixelSize(700, 500);
    
    
        RootPanel.get().add(cp);
      }
    
    
      private List<ColumnConfig<Data, ?>> getColumns() {
        List<ColumnConfig<Data, ?>> columns = new ArrayList<ColumnConfig<Data, ?>>();
    
    
        for (int c = 0; c < COLUMNS_SIZE; c++) {
          String header = "col" + c;
          ColumnConfig<Data, String> col = new ColumnConfig<Data, String>(new ValueProviderExt(c), 70, header);
          col.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
    
    
          columns.add(col);
        }
        return columns;
      }
    
    
      private PagingLoader<FilterPagingLoadConfig, PagingLoadResult<Data>> getLoader(ListStore<Data> store,
          final boolean grid1OrGrid2) {
        RpcProxy<FilterPagingLoadConfig, PagingLoadResult<Data>> proxy = new RpcProxy<FilterPagingLoadConfig, PagingLoadResult<Data>>() {
          @Override
          public void load(FilterPagingLoadConfig loadConfig, AsyncCallback<PagingLoadResult<Data>> callback) {
            getDatas(loadConfig, callback, grid1OrGrid2);
          }
        };
    
    
        PagingLoader<FilterPagingLoadConfig, PagingLoadResult<Data>> loader = new PagingLoader<FilterPagingLoadConfig, PagingLoadResult<Data>>(
            proxy);
        loader.useLoadConfig(new FilterPagingLoadConfigBean());
        loader.addLoadHandler(new LoadResultListStoreBinding<FilterPagingLoadConfig, Data, PagingLoadResult<Data>>(store));
        loader.setRemoteSort(true);
    
    
        return loader;
      }
    
    
      private void getDatas(FilterPagingLoadConfig loadConfig, AsyncCallback<PagingLoadResult<Data>> callback,
          boolean grid1OrGrid2) {
        final int offset = loadConfig.getOffset();
        int limit = loadConfig.getLimit();
    
    
        System.out.println("getDatas: offset=" + offset + " limit=" + limit);
    
    
        final List<Data> datas = new ArrayList<Data>();
        for (int i = offset; i < offset + limit; i++) {
          datas.add(getData(i, grid1OrGrid2));
        }
    
    
        PagingLoadResult<Data> result = new PagingLoadResult<Data>() {
          @Override
          public List<Data> getData() {
            return datas;
          }
    
    
          @Override
          public void setTotalLength(int totalLength) {
          }
    
    
          @Override
          public void setOffset(int offset) {
          }
    
    
          @Override
          public int getTotalLength() {
            return TOTAL_LENGTH;
          }
    
    
          @Override
          public int getOffset() {
            return offset;
          }
        };
        callback.onSuccess(result);
      }
    
    
      private Data getData(int row, boolean grid1OrGrid2) {
        String aOrB = "~~A:";
        if (grid1OrGrid2) {
          aOrB = "B:";
        }
    
    
        String key = aOrB + "key" + row;
    
    
        String[] values = new String[COLUMNS_SIZE];
        for (int col = 0; col < COLUMNS_SIZE; col++) {
          values[col] = aOrB + col + "," + row;
        }
    
    
        Data data = new Data(key, values);
        return data;
      }
    
    
      public class ValueProviderExt implements ValueProvider<Data, String> {
        private int index;
    
    
        public ValueProviderExt(int index) {
          this.index = index;
        }
    
    
        @Override
        public String getValue(Data data) {
          return data.getValue(index);
        }
    
    
        @Override
        public void setValue(Data object, String value) {
        }
    
    
        @Override
        public String getPath() {
          return "path" + index;
        }
      }
    
    
      public class StringFilterExt extends StringFilter<Data> {
        public StringFilterExt(int index) {
          super(new ValueProviderExt(index));
        }
      }
    
    
      public class Data {
        private String key;
        private String[] values;
    
    
        public Data(String key, String[] values) {
          this.key = key;
          this.values = values;
        }
    
    
        public String getKey() {
          return key;
        }
    
    
        public void setKey(String key) {
          this.key = key;
        }
    
    
        public String getValue(int index) {
          return values[index];
        }
    
    
        public void setValue(int index, String value) {
          this.values[index] = value;
        }
    
    
        @Override
        public String toString() {
          String s = "Data(";
          s += "key=" + key;
          s += ")";
          return s;
        }
      }
    }
    Could you help mock the issue in the test case and return it? And then provide the steps of the issue to help me understand how to reproduce it.

    Thanks for the tips on the guides. I'll add some todos for that too.

    Thanks,
    Brandon

  4. #4
    Sencha Premium Member
    Join Date
    Oct 2009
    Posts
    112

    Default

    From what I can tell, the test case you have is a Grid to Grid DnD.

    In my case, I have only one grid, and I want to reorder an item in the grid by DnD (move it up or down). Hence setAllowSelfAsSource(true);

    The idea is: on drop, I figure out the item's new position relative to the other items before and after it, and update the server side position and then reload the grid. That's not an issue.

    The issue is I can drag an item, but it won't let me drop it on the same grid. From what I can tell, the if statement in onDragMove method evaluates to true. So it sets the StatusProxy to false, preventing the drop.

    I am not sure what the if statement is checking, but my workaround is to bypass the check if View is LiveGridView - which I admit hacky.

    Really the issue is setAllowSelfAsSource(true); is not behaving as expected. It worked in GXT 3.1.4.

    Thanks.

Similar Threads

  1. LiveGrid Drag And Drop Scrolling
    By mdomingo in forum Ext GWT: Discussion
    Replies: 1
    Last Post: 7 Apr 2011, 10:51 PM
  2. Drag and drop in livegrid
    By dineshv87 in forum Ext GWT: Discussion
    Replies: 3
    Last Post: 3 Jan 2011, 11:18 PM
  3. Replies: 2
    Last Post: 10 Dec 2008, 9:07 PM
  4. Very simple drag and drop - not working
    By qwerti in forum Ext 2.x: Help & Discussion
    Replies: 5
    Last Post: 21 Aug 2008, 1:41 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •