1. #1
    Sencha User PhiLho's Avatar
    Join Date
    Nov 2011
    Location
    Near Paris, France
    Posts
    140
    Vote Rating
    1
    PhiLho is on a distinguished road

      0  

    Exclamation Beta 2/3: BorderLayoutContainer calls asWidget() twice

    Beta 2/3: BorderLayoutContainer calls asWidget() twice


    Making a standalone proto to show a bug, I think I have hit another one...
    I get an error message:
    AssertionError: The given model is already in the TreeStore, and should not be assigned a new node
    in TreeStore.wrap()

    The message isn't very explicit as I think it only shows I tried to add data to a store that is already there. Although maybe it is accurate after all.

    I have a tree in a BorderLayoutContainer, in the West wing...
    In the asWidget() method of the class instantiating the tree, I do as it is done in most Sencha demos: I call the createAndBindUi, I initialize the tree, including initializing the RPC that will fill it, and I return the widget.

    After investigation, I see the West init (and the others) use a two-fold scheme:
    Code:
      @Override
      public void setWestWidget(IsWidget child) {
        if (west != null) {
          remove(west);
        }
        if (child != null) {
          west = child.asWidget();
          insert(west, 0);
        }
      }
    
      @UiChild(limit = 1, tagname = "west")
      public void setWestWidget(IsWidget child, BorderLayoutData layoutData) {
        if (child != null) {
          child.asWidget().setLayoutData(layoutData);
        }
        setWestWidget(child);
      }
    Do you see the problem? child.asWidget() is called twice!
    So there is two attempts to fetch the data.

    Now, I don't write this message in the Bug section, because perhaps I violated a "GWT best practice", I don't know.

    The workaround is simple: just create the widget in the constructor of the class, and make asWidget() only return the widget class field.
    But it is far from obvious from the (necessarily simplified) examples for a GWT newbie like me. Perhaps you should add a stern warning somewhere, prominently, to warn against such practice (ie. doing too much work in asWidget()).

    Or perhaps you can avoid such double call by changing the code to something like:
    Code:
      private void setWestWidget(Widget w) {
         if (west != null) {
           remove(west);
         }
         if (w != null) {
           west = w;
           insert(west, 0);
         }
       }
     
      @Override
      public void setWestWidget(IsWidget child) {
        if (child != null) {
          setWestWidget(child.asWidget());
        } else {
          setWestWidget(null);
        }
      }
    
      @UiChild(limit = 1, tagname = "west")
      public void setWestWidget(IsWidget child, BorderLayoutData layoutData) {
        Widget w = null;
        if (child != null) {
          w = child.asWidget();
          w.setLayoutData(layoutData);
        }
        setWestWidget(w);
      }
    This breaks the cross-call between the public methods, avoiding this issue.
    It is more friendly for the kind of error / sloppy coding I made.

    At least, I hope this message can be useful for somebody having hit the same error...

  2. #2
    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


    So you are saying that your asWidget always returns another instance? That will not work. And it does not even work in many only GWT cases.

  3. #3
    Sencha User PhiLho's Avatar
    Join Date
    Nov 2011
    Location
    Near Paris, France
    Posts
    140
    Vote Rating
    1
    PhiLho is on a distinguished road

      0  

    Lightbulb I learned something today...

    I learned something today...


    OK, in retrospect, it makes sense... I shouldn't have copied blindly the Sencha examples (even more as I separate EntryPoint from IsWidget).
    Looking more closely at the Google samples, I see they never use IsWidget directly (only to define interfaces), they prefer to use Composite.

    Thanks for the answer.

Thread Participants: 1