17

I created a few styles into a CSSResource and it works well whether I use

GWT.<MyResources>create(MyResources.class).myStyles().ensureInjected();

or not.

Could anyone shed a light on this and explain when to use ensureInjected or not?

Thank you! Daniel

Ali
  • 261,656
  • 265
  • 575
  • 769
user198313
  • 4,228
  • 6
  • 24
  • 19

4 Answers4

8

As Christian said, inside the UiBinder ui.xml file you don't have to worry about invoking ensureInjected(), the following XML statements do the job:

<ui:with field='myStyle' type='com...MyStyle'/>
<div class='{myStyle.redBorder}'/>

Of course this is assuming that there is somewhere a MyStyle interface defined:

public interface MyStyle {
    public String redBorder();
}

Now I agree with you that things get annoying when you need to manipulate the CssResource extension outside of UiBinder templates. Precisely because you have to take care of invoking ensureInjected() somewhere before using the MyStyle instance with your widgets.

I personally use GIN to inject instances of extensions of CssResource whenever I need them.That way you can implement a custom GIN provider ensuring that ensureInjected() is called on the CssResource before injecting it. There are three steps involved there:

  • Create an interface for MyStyle alongside with a CSS file.
    MyStyle.java

    public interface MyStyle {
        public String redBorder();
    }
    
  • MyStyle.css

    .redBorder { border: 1px solid red; }
    
  • Expose it through a ClientBundle extension.
    Resources.java

    public interface Resources extends ClientBundle {
        @Source("MyStyle.css")
        public MyStyle style();
    }
    
  • Configure a GIN provider method to inject your instances of MyStyle.
    ClientModule.java

    public class ClientModule extends AbstractGinModule {
        @Override
        protected void configure() {
        //...
        }
    
        @Provides MyStyle createStyle(final Resources resources) {
            MyStyle style = resources.style();
            style.ensureInjected();
            return style;
        }
    }
    

We smoothly inject the Resources instance here above, which means no more hassle of a static accessor calling GWT.<Resources>create(Resources.class) anywhere, it just all happens through the GIN injection.

Having done that you can inject your instances of MyStyle when you need them.
For example (in some MVP context):

private Widget widget;

@Inject
public SomeView(final MyStyle style) {
    //...
    widget = uiBinder.createAndBindUi(this);
    widget.addStyleName(style.redBorder());
}
Mathias
  • 75
  • 8
mks-d
  • 166
  • 3
  • 14
6

The rule is easy: you have to call ensureInjected() explicitly, unless the CssResource is being generated from an <ui:style> in a UiBinder template (because most of the time you won't have a handle on the generated CssResource.
Specifically, <ui:with> provides no special treatment for CssResources.

Also, a few widgets take a specific ClientBundle as argument to a constructor (such as CellTable), they will then call ensureInjected() on the CssResource they use.

Thomas Broyer
  • 64,353
  • 7
  • 91
  • 164
  • Can you be a bit more specific on `ui:with`. Does ensureInjected() have to be called for that or not? – Ali May 08 '14 at 01:13
  • Because `ui:with` does nothing special regarding `CssResource`, it means that, yes, you have to call `ensureInjected()` _manually_, explicitly. – Thomas Broyer May 08 '14 at 01:32
  • is there any way to have the CssResource be auto included when its called from uiBinder? – Ali May 08 '14 at 12:37
  • No. Declare it has a `@UiField` in your Java counterpart (with the same name as the `field` attribute of the ``) so you can call `ensureInjected()` after the `createAndBindUi()`. – Thomas Broyer May 08 '14 at 13:53
  • What about if I do ``? Also, are you saying that the accepted answer (http://stackoverflow.com/a/5536378/49153) is wrong? Its saying that `ui:with` does auto include the css – Ali May 08 '14 at 22:28
  • As I said in the answer, ``automatically injects the stylesheet, because there might not even be an explicit Java interface for it. And there's no accepted answer. The most up-voted one is not wrong though, it says “you have to take care of invoking `ensureInjected()` somewhere before using the `MyStyle` instance with your widgets.” – Thomas Broyer May 08 '14 at 22:39
  • The most upvoted one (that I linked to) says this: `inside the UiBinder ui.xml file you don't have to worry about invoking ensureInjected(), the following XML statements do the job: `. Isn't that saying that by doing `ui:with`, it takes care of injecting the css? – Ali May 08 '14 at 23:24
  • Note that I'm only talking about using the cssResource within the uiBinder template, not in the java code. – Ali May 08 '14 at 23:27
  • It's misleading, but the phrase I quoted makes it clearer. I think what the author wanted to say is that you won't call `ensureInjected()` from within the `ui.xml`. Also note that the `` has to be on the `ClientBundle` (not the `CssResource`) unless you use a `@UiField(provided=true)` or `@UiFactory`. – Thomas Broyer May 08 '14 at 23:44
  • Thanks, that makes it much clearer. One question, if I want to do `ui:style` and my css resource was located in a different package, e.g if my uiBinder xml file is in `com.foo.view.someUi.ui.xml`, and I wanted to include `com.foo.css.SomeCssResource` via `ui:style src=..`, how would I give the path to `SomeCssResource?` – Ali May 08 '14 at 23:52
  • 1
    `ui:style src=` links to a CSS file, not a `CssResource` (you can use `type=` for that, it'll then generate an interface the `inherits` the on you name). The path can be either relative (using `../`) or, starting with GWT 2.5.0, absolute (starting with a `/`). See https://code.google.com/p/google-web-toolkit/issues/detail?id=7230 – Thomas Broyer May 08 '14 at 23:58
  • 1
    Thanks so much for your help. I'll give you a bounty since you helped me a lot. – Ali May 09 '14 at 23:41
6

Good question - one situation that comes to my mind is when you want to use styles from some global stylesheet in a UiBinder template - then you need to call ensureInjected to... ensure the styles are indeed injected when you are referencing them (the "local" UiBinder styles, that you define in xml are automagically injected).

You can see this used as such in the Mail example:

public void onModuleLoad() {
    // Inject global styles.
    GWT.<GlobalResources>create(GlobalResources.class).css().ensureInjected();

    // Create the UI defined in Mail.ui.xml.
    DockLayoutPanel outer = binder.createAndBindUi(this);

    // ...rest of the code
}

Note how ensureInjected is called before binding the UI.

This is the only situation I know that warrants using ensureInjected, but maybe I missed something.

Igor Klimer
  • 15,321
  • 3
  • 47
  • 57
  • Yes, I understood this as well but: I am using a global css file and it works well whether I use ensureInjected or not. This is the mystery I am try to solve. – user198313 Mar 10 '10 at 11:55
1

If you use UiBinder the call to ensureInjected is provided by the tag ui:with. For any other css you are using in a client bundle (i.e. legacy css excluded) and that are not declared in a ui:with block, you have to call ensureInjected explicitly.

Christian Achilli
  • 5,547
  • 2
  • 25
  • 24
  • 2
    I'm using UiBinder exclusively, but for me, it isn't provided...I had to call it explicitly. – buc Mar 14 '11 at 00:11