Looks like we can't reproduce the issue or there's a problem in the test case provided.
  1. #1
    Sencha Premium Member
    Join Date
    Jun 2012
    Posts
    21
    Vote Rating
    0
    joseph.j.valerio@gmail.com is on a distinguished road

      0  

    Default LiveGrid Loading on hidden tab...

    LiveGrid Loading on hidden tab...


    Hi Guys,

    I have two questions.

    1. When I load a liveDataGrid on a hidden tab, the ui does not update, I have to specifically call grid.show() in a selectionEvent handler to get it to render correctly. Is this a bug, or is this the way it should/has to be done?

    2. When the live grid loads, it does not fill the space available. If I resize the tab, the grid then correctly resizes to fill the tab. I cannot figure out how to get it to ALWAYS fill the tab onload.

    This one is WRONG...
    grid-1.png

    This one is RIGHT...
    grid-2.png

    Here is a patch to the 3.0.4 GXT branch that will update the uiBinder tab example with my issues. I added a filter to getPosts() in the ExampleService to allow you to change the result set. You can see the update failure in question 1 by commenting out the grid.show() in the View's UiHandler. You must hit update to load the data, and "brad" is a good filter value... I am running Firefox 18.0.2 if question 2 gets to that...

    As always, thanks for your efforts,

    - Joe

    Code:
    Index: src/main/java/com/sencha/gxt/explorer/client/tabs/SampleLiveGrid.java
    ===================================================================
    --- src/main/java/com/sencha/gxt/explorer/client/tabs/SampleLiveGrid.java    (revision 0)
    +++ src/main/java/com/sencha/gxt/explorer/client/tabs/SampleLiveGrid.java    (revision 0)
    @@ -0,0 +1,102 @@
    +package com.sencha.gxt.explorer.client.tabs;
    +
    +import java.util.ArrayList;
    +import java.util.Date;
    +import java.util.List;
    +
    +import com.google.gwt.cell.client.DateCell;
    +import com.google.gwt.core.client.GWT;
    +import com.google.gwt.i18n.client.DateTimeFormat;
    +import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
    +import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
    +import com.sencha.gxt.core.client.dom.XDOM;
    +import com.sencha.gxt.data.shared.ListStore;
    +import com.sencha.gxt.data.shared.ModelKeyProvider;
    +import com.sencha.gxt.data.shared.loader.PagingLoadConfig;
    +import com.sencha.gxt.data.shared.loader.PagingLoadResult;
    +import com.sencha.gxt.data.shared.loader.PagingLoader;
    +import com.sencha.gxt.examples.resources.client.model.Post;
    +import com.sencha.gxt.examples.resources.client.model.PostProperties;
    +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.GridView;
    +import com.sencha.gxt.widget.core.client.grid.LiveGridView;
    +
    +public class SampleLiveGrid extends Grid<Post> {
    +    
    +    PostProxy proxy = new PostProxy();
    +    
    +    public SampleLiveGrid(){
    +        
    +        super();
    +
    +        store = new ListStore<Post>(
    +                new ModelKeyProvider<Post>() {
    +                    @Override
    +                    public String getKey(Post item) {
    +                        return "" + item.getId();
    +                    }
    +                });
    +
    +        setLoader(makeLoader(store));
    +
    +        cm = makeColumnConfigs();
    +
    +        setView(makeGridView());
    +
    +        setLoadMask(true);
    +
    +        SafeHtmlBuilder builder = new SafeHtmlBuilder();
    +        view.getAppearance().render(builder);
    +
    +        setElement(XDOM.create(builder.toSafeHtml()));
    +        getElement().makePositionable();
    +
    +        sinkCellEvents();
    +
    +    }
    +    
    +    public PagingLoader<PagingLoadConfig, PagingLoadResult<Post>> makeLoader(ListStore<Post> store) {
    +
    +        final PagingLoader<PagingLoadConfig, PagingLoadResult<Post>> gridLoader = new PagingLoader<PagingLoadConfig, PagingLoadResult<Post>>(proxy);
    +        gridLoader.setRemoteSort(true);
    +        return gridLoader;
    +
    +    }
    +    
    +    public ColumnModel<Post> makeColumnConfigs() {
    +
    +        PostProperties props = GWT.create(PostProperties.class);
    +
    +        ColumnConfig<Post, String> forumColumn = new ColumnConfig<Post, String>(
    +                props.forum(), 150, "Forum");
    +        ColumnConfig<Post, String> usernameColumn = new ColumnConfig<Post, String>(
    +                props.username(), 150, "Username");
    +        ColumnConfig<Post, String> subjectColumn = new ColumnConfig<Post, String>(
    +                props.subject(), 150, "Subject");
    +        ColumnConfig<Post, Date> dateColumn = new ColumnConfig<Post, Date>(
    +                props.date(), 150, "Date");
    +        dateColumn.setCell(new DateCell(DateTimeFormat
    +                .getFormat(PredefinedFormat.DATE_SHORT)));
    +
    +        List<ColumnConfig<Post, ?>> l = new ArrayList<ColumnConfig<Post, ?>>();
    +        l.add(forumColumn);
    +        l.add(usernameColumn);
    +        l.add(subjectColumn);
    +        l.add(dateColumn);
    +
    +        return new ColumnModel<Post>(l);
    +    }
    +    
    +    public GridView<Post> makeGridView(){
    +        final LiveGridView<Post> liveGridView = new LiveGridView<Post>();
    +        liveGridView.setForceFit(true);
    +        return liveGridView;
    +    }
    +    
    +    public void setFilter(String filter){
    +        proxy.setFilter(filter);
    +    }
    +
    +}
    Index: src/main/java/com/sencha/gxt/explorer/client/tabs/BasicTabUiBinderExample.java
    ===================================================================
    --- src/main/java/com/sencha/gxt/explorer/client/tabs/BasicTabUiBinderExample.java    (revision 2683)
    +++ src/main/java/com/sencha/gxt/explorer/client/tabs/BasicTabUiBinderExample.java    (working copy)
    @@ -4,6 +4,7 @@
     import com.google.gwt.core.client.GWT;
     import com.google.gwt.event.logical.shared.SelectionEvent;
     import com.google.gwt.uibinder.client.UiBinder;
    +import com.google.gwt.uibinder.client.UiFactory;
     import com.google.gwt.uibinder.client.UiField;
     import com.google.gwt.uibinder.client.UiHandler;
     import com.google.gwt.user.client.ui.IsWidget;
    @@ -11,34 +12,72 @@
     import com.google.gwt.user.client.ui.Widget;
     import com.sencha.gxt.examples.resources.client.TestData;
     import com.sencha.gxt.explorer.client.model.Example.Detail;
    +import com.sencha.gxt.widget.core.client.PlainTabPanel;
    +import com.sencha.gxt.widget.core.client.Resizable;
     import com.sencha.gxt.widget.core.client.TabItemConfig;
     import com.sencha.gxt.widget.core.client.TabPanel;
    +import com.sencha.gxt.widget.core.client.button.TextButton;
    +import com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer;
    +import com.sencha.gxt.widget.core.client.event.SelectEvent;
    +import com.sencha.gxt.widget.core.client.form.TextField;
    +import com.sencha.gxt.widget.core.client.grid.LiveToolItem;
     import com.sencha.gxt.widget.core.client.info.Info;
     
     @Detail(name = "Basic Tabs (UiBinder)", icon = "basictabs", category = "Tabs", files = "BasicTabUiBinderExample.ui.xml")
     public class BasicTabUiBinderExample implements IsWidget, EntryPoint {
     
    -  interface MyUiBinder extends UiBinder<Widget, BasicTabUiBinderExample> {
    -  }
    +    interface MyUiBinder extends UiBinder<Widget, BasicTabUiBinderExample> {
    +    }
    +
    +    private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
     
    -  private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
    +    @UiField(provided = true)
    +    String txt = TestData.DUMMY_TEXT_SHORT;
    +    @UiField
    +    TextButton update;
    +    @UiField
    +    TextField filter;
    +    @UiField
    +    SampleLiveGrid grid;
    +    @UiField 
    +    PlainTabPanel tabPanel;
    +    @UiField
    +    VerticalLayoutContainer gridTab;
     
    -  @UiField(provided = true)
    -  String txt = TestData.DUMMY_TEXT_SHORT;
    +    public Widget asWidget() {
    +        Widget w = uiBinder.createAndBindUi(this);
    +        new Resizable(tabPanel);
    +        return w;
    +    }
     
    -  public Widget asWidget() {
    -    return uiBinder.createAndBindUi(this);
    -  }
    +    public void onModuleLoad() {
    +        RootPanel.get().add(asWidget());
    +    }
     
    -  public void onModuleLoad() {
    -    RootPanel.get().add(asWidget());
    -  }
    +    @UiHandler(value = { "folder", "tabPanel" })
    +    void onSelection(SelectionEvent<Widget> event) {
    +        TabPanel panel = (TabPanel) event.getSource();
    +        Widget w = event.getSelectedItem();
    +        TabItemConfig config = panel.getConfig(w);
    +        Info.display("Message", "'" + config.getText() + "' Selected");
    +    }
     
    -  @UiHandler(value = {"folder", "panel"})
    -  void onSelection(SelectionEvent<Widget> event) {
    -    TabPanel panel = (TabPanel) event.getSource();
    -    Widget w = event.getSelectedItem();
    -    TabItemConfig config = panel.getConfig(w);
    -    Info.display("Message", "'" + config.getText() + "' Selected");
    -  }
    +    @UiHandler(value = { "tabPanel" })
    +    void onTabSelection(SelectionEvent<Widget> event) {
    +        if(event.getSelectedItem() == gridTab){
    +            grid.show();
    +        }
    +    }
    +    
    +    @UiFactory
    +    public LiveToolItem makeLiveToolItem(SampleLiveGrid grid) {
    +        return new LiveToolItem(grid);
    +    }
    +    
    +    @UiHandler("update")
    +    public void handleUpdate(SelectEvent event){
    +        grid.setFilter(filter.getText());
    +        grid.getLoader().load();
    +    }
    +
     }
    Index: src/main/java/com/sencha/gxt/explorer/client/tabs/BasicTabUiBinderExample.ui.xml
    ===================================================================
    --- src/main/java/com/sencha/gxt/explorer/client/tabs/BasicTabUiBinderExample.ui.xml    (revision 2683)
    +++ src/main/java/com/sencha/gxt/explorer/client/tabs/BasicTabUiBinderExample.ui.xml    (working copy)
    @@ -1,6 +1,13 @@
     <!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
    -<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g="urn:import:com.google.gwt.user.client.ui"
    -  xmlns:tabs="urn:import:com.sencha.gxt.widget.core.client" xmlns:container="urn:import:com.sencha.gxt.widget.core.client.container">
    +<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' 
    +    xmlns:g="urn:import:com.google.gwt.user.client.ui"
    +    xmlns:tabs="urn:import:com.sencha.gxt.widget.core.client" 
    +    xmlns:frm="urn:import:com.sencha.gxt.widget.core.client.form" 
    +    xmlns:btn="urn:import:com.sencha.gxt.widget.core.client.button" 
    +    xmlns:container="urn:import:com.sencha.gxt.widget.core.client.container"
    +    xmlns:gxtt="urn:import:com.sencha.gxt.widget.core.client.toolbar"
    +    xmlns:gxtg="urn:import:com.sencha.gxt.widget.core.client.grid"
    +    xmlns:grid="urn:import:com.sencha.gxt.explorer.client.tabs">
     
       <ui:with type="java.lang.String" field="txt" />
       <ui:with type="com.sencha.gxt.examples.resources.client.images.ExampleImages" field="images" />
    @@ -20,6 +27,12 @@
       <ui:with type="com.sencha.gxt.widget.core.client.TabItemConfig" field="disabledTabConfig">
         <ui:attributes text="Disabled" enabled="false" />
       </ui:with>
    +    <ui:with field="gridVlo" type="com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer.VerticalLayoutData">
    +        <ui:attributes height="1"/>
    +    </ui:with>
    +    <ui:with field="gridFooterVlo" type="com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer.VerticalLayoutData">
    +        <ui:attributes height="30"/>
    +    </ui:with>
     
       <ui:style>
         .sep {
    @@ -41,11 +54,24 @@
           </tabs:child>
         </tabs:TabPanel>
     
    -    <tabs:PlainTabPanel ui:field="panel" pixelSize="450, 250" addStyleNames="margin-10">
    +    <frm:TextField ui:field="filter"/>
    +    <btn:TextButton ui:field="update" text="Update"/>
    +
    +    <tabs:PlainTabPanel ui:field="tabPanel" pixelSize="450, 250" addStyleNames="margin-10">
    +    
           <tabs:child config="{normalTabConfig}">
    -        <g:Label text="Just a plain old tab" addStyleNames="pad-text" />
    +        <container:VerticalLayoutContainer ui:field="gridTab">
    +            <container:child layoutData="{gridVlo}">
    +                <grid:SampleLiveGrid ui:field="grid" />
    +            </container:child>
    +            <container:child layoutData="{gridFooterVlo}">
    +                <gxtt:ToolBar>
    +                    <gxtg:LiveToolItem grid="{grid}"/>
    +                </gxtt:ToolBar>
    +            </container:child>
    +        </container:VerticalLayoutContainer>
           </tabs:child>
    -
    +      
           <tabs:child config="{iconTabConfig}">
             <g:Label text="Just a plain old tab with an icon" addStyleNames="pad-text" />
           </tabs:child>
    @@ -54,6 +80,7 @@
             <g:Label text="This tab should be disabled" addStyleNames="pad-text" />
           </tabs:child>
         </tabs:PlainTabPanel>
    +
       </container:FlowLayoutContainer>
     
     </ui:UiBinder>
    Index: src/main/java/com/sencha/gxt/explorer/client/tabs/PostProxy.java
    ===================================================================
    --- src/main/java/com/sencha/gxt/explorer/client/tabs/PostProxy.java    (revision 0)
    +++ src/main/java/com/sencha/gxt/explorer/client/tabs/PostProxy.java    (revision 0)
    @@ -0,0 +1,32 @@
    +package com.sencha.gxt.explorer.client.tabs;
    +
    +import com.google.gwt.core.client.GWT;
    +import com.google.gwt.user.client.rpc.AsyncCallback;
    +import com.sencha.gxt.data.client.loader.RpcProxy;
    +import com.sencha.gxt.data.shared.loader.PagingLoadConfig;
    +import com.sencha.gxt.data.shared.loader.PagingLoadResult;
    +import com.sencha.gxt.examples.resources.client.ExampleService;
    +import com.sencha.gxt.examples.resources.client.ExampleServiceAsync;
    +import com.sencha.gxt.examples.resources.client.model.Post;
    +
    +public class PostProxy extends RpcProxy<PagingLoadConfig, PagingLoadResult<Post>>{
    +
    +    final ExampleServiceAsync service = GWT.create(ExampleService.class);
    +
    +    String filter;
    +    
    +    @Override
    +    public void load(PagingLoadConfig loadConfig,
    +            AsyncCallback<PagingLoadResult<Post>> callback) {
    +        service.getPosts(loadConfig, filter, callback);
    +    }
    +
    +    public String getFilter() {
    +        return filter;
    +    }
    +
    +    public void setFilter(String filter) {
    +        this.filter = filter;
    +    }
    +
    +}
    Index: src/main/java/com/sencha/gxt/examples/resources/server/ExampleServiceImpl.java
    ===================================================================
    --- src/main/java/com/sencha/gxt/examples/resources/server/ExampleServiceImpl.java    (revision 2683)
    +++ src/main/java/com/sencha/gxt/examples/resources/server/ExampleServiceImpl.java    (working copy)
    @@ -79,16 +79,33 @@
     
       @Override
       public PagingLoadResult<Post> getPosts(PagingLoadConfig config) {
    +      return getPosts(config, null);      
    +  }
    +
    +  @Override
    +  public PagingLoadResult<Post> getPosts(PagingLoadConfig config, String filter) {
         if (posts == null) {
           loadPosts();
         }
    -
    +    
    +    List<Post> subPosts = new ArrayList<Post>();
    +    if(filter == null
    +    || filter.isEmpty()){
    +        subPosts = posts;
    +    } else {
    +        for(Post p : posts){
    +            if(p.getUsername().matches(filter)){
    +                subPosts.add(p);
    +            }
    +        }
    +    }
    +    
         if (config.getSortInfo().size() > 0) {
           SortInfo sort = config.getSortInfo().get(0);
           if (sort.getSortField() != null) {
             final String sortField = sort.getSortField();
             if (sortField != null) {
    -          Collections.sort(posts, sort.getSortDir().comparator(new Comparator<Post>() {
    +          Collections.sort(subPosts, sort.getSortDir().comparator(new Comparator<Post>() {
                 public int compare(Post p1, Post p2) {
                   if (sortField.equals("forum")) {
                     return p1.getForum().compareTo(p2.getForum());
    @@ -108,14 +125,14 @@
     
         ArrayList<Post> sublist = new ArrayList<Post>();
         int start = config.getOffset();
    -    int limit = posts.size();
    +    int limit = subPosts.size();
         if (config.getLimit() > 0) {
           limit = Math.min(start + config.getLimit(), limit);
         }
         for (int i = config.getOffset(); i < limit; i++) {
    -      sublist.add(posts.get(i));
    +      sublist.add(subPosts.get(i));
         }
    -    return new PagingLoadResultBean<Post>(sublist, posts.size(), config.getOffset());
    +    return new PagingLoadResultBean<Post>(sublist, subPosts.size(), config.getOffset());
       }
     
       @Override
    Index: src/main/java/com/sencha/gxt/examples/resources/client/ExampleService.java
    ===================================================================
    --- src/main/java/com/sencha/gxt/examples/resources/client/ExampleService.java    (revision 2683)
    +++ src/main/java/com/sencha/gxt/examples/resources/client/ExampleService.java    (working copy)
    @@ -17,7 +17,8 @@
     public interface ExampleService extends RemoteService {
     
       PagingLoadResult<Post> getPosts(PagingLoadConfig config);
    -
    +  PagingLoadResult<Post> getPosts(PagingLoadConfig config, String filter);
    +  
       /**
        * Returns the music root folder with all child references.
        * 
    Index: src/main/java/com/sencha/gxt/examples/resources/client/ExampleServiceAsync.java
    ===================================================================
    --- src/main/java/com/sencha/gxt/examples/resources/client/ExampleServiceAsync.java    (revision 2683)
    +++ src/main/java/com/sencha/gxt/examples/resources/client/ExampleServiceAsync.java    (working copy)
    @@ -15,7 +15,8 @@
     public interface ExampleServiceAsync {
     
       void getPosts(PagingLoadConfig config, AsyncCallback<PagingLoadResult<Post>> callback);
    -
    +  void getPosts(PagingLoadConfig config, String filter, AsyncCallback<PagingLoadResult<Post>> callback);
    +  
       void getMusicRootFolder(AsyncCallback<FolderDto> callback);
       
       void getMusicFolderChildren(FolderDto folder, AsyncCallback<List<BaseDto>> callback);

  2. #2
    Sencha Premium Member
    Join Date
    Jun 2012
    Posts
    21
    Vote Rating
    0
    joseph.j.valerio@gmail.com is on a distinguished road

      0  

    Default


    Guys,

    I posed two questions here, are they both bugs?

  3. #3
    Software Architect
    Join Date
    Sep 2007
    Posts
    13,971
    Vote Rating
    132
    sven is a glorious beacon of light sven is a glorious beacon of light sven is a glorious beacon of light sven is a glorious beacon of light sven is a glorious beacon of light sven is a glorious beacon of light

      0  

    Default


    Not sure where my reply went to:

    1) The problem is that when something is hidden with display none, it has no sizes and so the rowcount is not working correclty. A workaround would be to change the HideMode to HideMode.OFFSETS on the component that you add to the TabPanel.

    2) This might be solved with the workaround from 1) too


    I moved this into the bugs forum to add workarounds internly like Ext GWT 2 had in place.

  4. #4
    Sencha Premium Member
    Join Date
    Jun 2012
    Posts
    21
    Vote Rating
    0
    joseph.j.valerio@gmail.com is on a distinguished road

      0  

    Default


    I'll try the the hide mode, but 2, the display issue, happens even when visable.

  5. #5
    Sencha Premium Member
    Join Date
    Jun 2012
    Posts
    21
    Vote Rating
    0
    joseph.j.valerio@gmail.com is on a distinguished road

      0  

    Default


    HideMode.OFFSETS works when set on the parent container, thanks. Do you think there will ever be a fix for this other than the work around?

  6. #6
    Sencha Premium Member
    Join Date
    Jun 2012
    Posts
    21
    Vote Rating
    0
    joseph.j.valerio@gmail.com is on a distinguished road

      0  

    Default


    To be more specific, it would be great if the control knew it wasn't rendered because it was hidden, and then on re-attach to the dom, it would lay itself out correctly.

    I am having the same issue where the LiveGrid is not on a tab panel, but in a completely different view. I want to update data in the store, depending on actions in the other view, and have the data waiting for when the user inevitably returns. I now I could change the architecture of the site and use decks, but I shouldn't have to design my app according to what I consider a bug.

  7. #7
    Sencha User
    Join Date
    Nov 2011
    Posts
    10
    Vote Rating
    0
    Tony Stuart is on a distinguished road

      0  

    Default


    There are two aspects to this issue: visibility and layout:

    1. GXT 3 does not provide notification to child components when an ancestor's visibility changes. This means that an application may be responsible for notifying a component when it becomes visible, if for example, it performs an update while hidden.

    2. FlowLayoutContainers lay out their widgets using the default HTML layout behavior. This means that they do not propagate GXT layout requests to children. This can result in unexpected component layouts, if for example, an ancestor of the component is hidden using display: none (the default) when the component is added to it.

    To avoid these types of issues:

    1. Invoke setHideMode(HideMode.VISIBILITY) on the component's container (e.g. the container added to a TabPanel).

    2. Use a container that propagates layout requests to its children (e.g. VerticalLayoutContainer) instead of a FlowLayoutContainer.

    3. Modify the application to notify components when ancestor visibility changes.

Thread Participants: 2