views:

751

answers:

2

Hi

I'm attempting to create a composite widget, which will show a 'list' of child widgets, but I'm having some trouble getting css to work in this setting. Have constructed a simple demo, to try and figure out a solution. Have tried to specify the parent widget like this

<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
   xmlns:g='urn:import:com.google.gwt.user.client.ui'>

 <ui:with field='res' type='egov.widgets.discussion.client.poc.Resources' />

 <g:FlowPanel ui:field="childPanel" stylePrimaryName='{res.style.parentStyle}'>

 </g:FlowPanel>

</ui:UiBinder>

with code

public class CssParent extends Composite{

interface MyUiBinder extends UiBinder<Widget, CssParent> {}
private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);

@UiField FlowPanel childPanel;

   public CssParent() {
      initWidget(uiBinder.createAndBindUi(this));

       CssChild child = new CssChild();
      childPanel.add(child);
   }  
}

the child widget is simply specified as

<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
   xmlns:g='urn:import:com.google.gwt.user.client.ui'>

 <ui:with field='res' type='egov.widgets.discussion.client.poc.Resources' />

    <g:HTMLPanel stylePrimaryName='{res.style.childStyle}'>
       Howdy folks
    </g:HTMLPanel>

  </ui:UiBinder>

now, as you can see they both reference a resource bundle:

public interface Resources extends ClientBundle {

@Source("CssDemo.css")
Style style();

  public interface Style extends CssResource{
     String parentStyle();
     String childStyle();
  }
}

which again references CssDemo.css: .parentStyle{ background-color: grey; }

.parentStyle .childStyle{
    background-color: yellow;
}

but for some reason these css rules are never applied to the two div elements above. Any idea as to why this fails? Or a better way of sharing a .css style sheets between widgets, when the styles include dependency-rules between different css classes?

+1  A: 

It's not obvious to me what's wrong - your code is at least close to correct (I've been using styleName=<whatever> instead of stylePrimaryName=<whatever>, so that's one thing you might look into).

The way to debug issues like this is to use Firebug to see (1) what class names have been applied to the DOM elements, and (2) what CSS rules take effect on the basis of those styles.

If you put @external parentStyle, childStyle; at the start of your CSS file, then GWT won't obfuscate the style names, and you'll be able to tell in Firebug what names have been applied.

A couple more suggestions:

  1. Use DevMode and look to see if it shows any errors (they'll be in red text) when you load the page - scroll to the bottom of the DevMode window's top pane.
  2. You can try this with a simpler example, with a single Composite class rather than two.
aem
Thanks for the @external hint. Have really had trouble debugging what is going on with all those obfuscated names.Have posted my solution below here. Do you know if there is a more elegant way to what I'm trying to archive?
Jannick
Ah, yes, I forgot about the ensureInjected which you describe in your answer. That's the correct way to get a shared stylesheet to work; if you don't do that, I believe the symptom was that the CSS classes are applied but no rules are associated with them.Igor Kilmer's comment below is right - only use shared stylesheets when there's a style that spans multiple UiBinder widgets. For instance, I've used them to get a similar look across related but different UI elements.
aem
+2  A: 

Found out that you need to inject styles used in this way

 static{
     Resources.INSTANCE.style().ensureInjected();
 }

(added this singleton-ish instance field to the bundle)

public interface Resources extends ClientBundle {

    public static final Resources INSTANCE =  GWT.create(Resources.class);

    @Source("Resources.css")
    Style style();

it works now, but I really don't like having to do it this way ("{res.style.someClass}") + all the methods I have to define in the CssResource interface.

Would be nice if one could do a shared ui:style declaration (perhaps based on a css file), and just use it like a normal internal style block.

Jannick
I think you are misunderstanding one core concept of CSS + UiBinder - the CSS styles you define locally (in a UiBinder XML template) are *local* - meaning, your `CssParent` and `CssChild` widgets can have a style with the same name (with different rules or not) - there's no global CSS namespace, all the style names will be obfuscated so that they won't collide. So, in most cases you don't really have to write selectors like `.parentStyle .childStyle` - since you apply that style only "locally". I only use global CSS file for truly global styles, like errors in TextBoxes, etc.
Igor Klimer
Good point. In this case the css and base-html comes form a designer. Guess I'll have to get them onboard with this approach. :)
Jannick