Skip to content

Commit ed56044

Browse files
committed
Add documentation on Dependency Injection
1 parent 8148b0b commit ed56044

File tree

54 files changed

+4230
-128
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+4230
-128
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ It lets you write Vue.js components in Java.
2020
* Template expressions **type checking** at compile time
2121
* **HTML templates are compiled** during Java Compilation (only requires Vue.js runtime)
2222
* Use **regular Java Objects and Collections** in your templates
23-
* Supports **injection** in Components
23+
* Supports [**injection** in Components](https://axellience.github.io/vue-gwt/essential/dependency-injection.html)
2424
* Supports **most of Vue.js features**
25-
* Integrates with GWT Resources and Widgets
25+
* Integrates with [GWT Resources](https://axellience.github.io/vue-gwt/gwt-integration/client-bundles.html) and [Widgets](https://axellience.github.io/vue-gwt/gwt-integration/user-panels.html)
2626

2727
## Who is this for?
2828

docs-source/book/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ It lets you write Vue.js components in Java.
2020
* Template expressions **type checking** at compile time
2121
* **HTML templates are compiled** during Java Compilation (only requires Vue.js runtime)
2222
* Use **regular Java Objects and Collections** in your templates
23-
* Supports **injection** in Components
23+
* Supports [**injection** in Components](essential/dependency-injection.md)
2424
* Supports **most of Vue.js features**
25-
* Integrates with GWT Resources and Widgets
25+
* Integrates with [GWT Resources](gwt-integration/client-bundles.md) and [Widgets](gwt-integration/user-panels.md)
2626

2727
## Who is this for?
2828

docs-source/book/SUMMARY.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@
2323
* [Props](essential/components.md#props)
2424
* [Content Distribution with Slots](essential/components.md#content-distribution)
2525
* [Dynamic Components](essential/components.md#dynamic-components)
26+
* [Dependency Injection](essential/dependency-injection.md)
27+
* [Why Dependency Injection?](essential/dependency-injection.md#why-dependency-injection)
28+
* [Setting up Dagger 2](essential/dependency-injection.md#dagger-2)
29+
* [Injecting a Vue GWT Component](essential/dependency-injection.md#injecting-a-component)
30+
* [Injecting Component's Children](essential/dependency-injection.md#injecting-children)
31+
* [Globally Registered Components](essential/dependency-injection.md#globally-registered-components)
32+
* [Injecting Routes in Vue GWT Router](essential/dependency-injection.md#vue-gwt-router)
2633

2734
## Transitions & Animation
2835
* [Enter/Leave & List Transitions](transitions/transitions.md)
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
# Dependency Injection
2+
3+
!INCLUDE "../dependencies.md"
4+
5+
## Why Dependency Injection? {#why-dependency-injection}
6+
7+
When developing your App *you want to keep a maximum of business logic out of your Components*.
8+
For example you can create Services that can be reused across Components.
9+
10+
But in Vue GWT you are not responsible for your Components instantiation.
11+
Apart from your application root, other Components are instantiated for you by Vue depending on your model.
12+
13+
So how do you pass the instance of those Services to your Components?
14+
Sure you could have a static instance of those Services as a Singleton, but this is awful for testing.
15+
16+
Luckily, **Vue GWT supports Dependency Injection**.
17+
An instance of your Services can be automatically provided when your Components are instantiated.
18+
You can also provide a mock yourself when you are [testing your Components](../tooling/unit-testing.md).
19+
20+
## Setting up Dagger 2 {#dagger-2}
21+
22+
In GWT two solutions exist for Dependency Injection:
23+
24+
* [Dagger 2](https://google.github.io/dagger/users-guide)
25+
* [GIN](https://github.com/nishtahir/google-gin) *deprecated*
26+
27+
In this documentation we will explain Injection with Dagger 2 as GIN is deprecated.
28+
However Vue GWT also works with GIN.
29+
30+
To setup Dagger 2 on your project you can follow this guide: [Dependency injection in GWT using Dagger 2](http://www.g-widgets.com/2017/06/28/dependency-injection-in-gwt-using-dagger-2/).
31+
32+
The version of the Maven dependency in the guide is a little out of date.
33+
You can check for the latest version of Dagger GWT to use on the [Dagger GWT Maven repo](https://mvnrepository.com/artifact/com.google.dagger/dagger-gwt).
34+
35+
## Injecting a Vue GWT Component {#injecting-a-component}
36+
37+
### Declaring the Component
38+
39+
Let's say we have a `GotQuotesService` that is able to provide us with a random quote from a famous TV Show.
40+
41+
We want to use that service in a `GotQuotesComponent` that will display a random quote.
42+
We simply add `GotQuotesService` as an attribute of our Component with the `@Inject` annotation.
43+
44+
<p class="warning-panel">
45+
It's not possible to use injected constructor parameters as Java constructors are not supported in Vue GWT Components.
46+
<p>
47+
48+
```java
49+
@Component
50+
public class GotQuotesComponent extends VueComponent implements HasCreated {
51+
@JsProperty GotQuote quote;
52+
@Inject GotQuotesService gotQuotesService;
53+
54+
@Override
55+
public void created() {
56+
changeQuote();
57+
}
58+
59+
@JsMethod
60+
protected void changeQuote() {
61+
quote = gotQuotesService.getRandomQuote();
62+
}
63+
}
64+
```
65+
66+
We can then simply use `quote` in our `GotQuotesComponent` template:
67+
68+
```html
69+
<div>
70+
<blockquote>
71+
{{ quote.getText() }}
72+
<cite>
73+
<strong>{{ quote.getAuthor() }}</strong>, Season <strong>{{ quote.getSeason() }}</strong>, Episode <strong>{{ quote.getEpisode() }}</strong>
74+
</cite>
75+
</blockquote>
76+
<button @click="changeQuote">Give me another!</button>
77+
</div>
78+
```
79+
80+
To make this Component work we now must find a way to have it Injected.
81+
82+
### Instantiating the `GotQuotesComponent` with Injection
83+
84+
Every Vue GWT Component get an associated Factory generated for them by the Vue GWT annotation processor.
85+
This means that `GotQuotesComponent` have a generated `GotQuotesComponentFactory`.
86+
87+
To bootstrap injection we need to inject `GotQuotesComponentFactory`.
88+
Every instance of our `GotQuotesComponent` created using the injected `GotQuotesComponentFactory` will then be correctly injected.
89+
90+
To inject this factory we declare a Dagger 2 Component.
91+
92+
<p class="warning-panel">
93+
Dagger 2 have it's own <code>Component</code> annotation.
94+
So you must be careful to use the right one when declaring your Dagger 2 Component.
95+
<p>
96+
97+
```java
98+
@Component // ⚠️ This is Dagger 2 @Component annotation, not the Vue GWT one.
99+
@Singleton
100+
public interface ExampleInjector {
101+
GotQuotesComponentFactory gotQuoteComponentFactory();
102+
}
103+
```
104+
105+
<p class="info-panel">
106+
If <code>GotQuotesComponentFactory</code> doesn't exist, then check your annotation processor configuration in your IDE to make sure that it's running.
107+
<p>
108+
109+
110+
We can then create our Dagger Injector, get our `GotQuotesComponentFactory` and use it to create our injected `GotQuotesComponent`:
111+
112+
```java
113+
public class VueGwtExamplesApp implements EntryPoint {
114+
public void onModuleLoad() {
115+
// Create Dagger Injector
116+
ExampleInjector exampleInjector = DaggerExampleInjector.builder().build();
117+
// Get our Factory from the Injector
118+
GotQuotesComponentFactory factory = exampleInjector.gotQuoteComponentFactory();
119+
// Create our Component, it will be correctly injected
120+
GotQuotesComponent component = factory.create();
121+
// Mount (attach) our Component to an existing div
122+
component.$mount("#gotQuotesComponent");
123+
}
124+
}
125+
```
126+
127+
And here is the resulting live Component:
128+
129+
{% raw %}
130+
<div class="example-container" data-name="gotQuotesComponent">
131+
<br/>
132+
<span id="gotQuotesComponent"></span>
133+
</div>
134+
{% endraw %}
135+
136+
## Injecting Component's Children {#injecting-children}
137+
138+
We injected our root Component, that's great, but how about it's children?
139+
140+
Here is the good news: if you inject your root Component, then the whole tree of locally declared Components will be injected 🎉!
141+
142+
For example if you have the following Components, you only need to inject `RootComponentFactory` and use it to create your `RootComponent`.
143+
All the Components used in the template and declared in `components` will be injected.
144+
145+
### RootComponent
146+
147+
```java
148+
@Component(components = {Child1Component.class, Child2Component.class})
149+
public class RootComponent extends VueComponent {}
150+
```
151+
152+
```html
153+
<div>
154+
<!-- Create 10 instances of Child1Component -->
155+
<child1 v-for="i in 10"></child1>
156+
<child2></child2>
157+
</div>
158+
```
159+
160+
### Child1Component
161+
162+
```java
163+
@Component(components = GrandChild1Component.class)
164+
public class Child1Component extends VueComponent {
165+
@Inject MyService myService;
166+
}
167+
```
168+
169+
```html
170+
<div>
171+
<grand-child1></grand-child1>
172+
</div>
173+
```
174+
175+
### Child2Component
176+
177+
```java
178+
@Component
179+
public class Child2Component extends VueComponent {
180+
@Inject MyService myService;
181+
@Inject AnotherService anotherService;
182+
}
183+
```
184+
185+
### GrandChild1Component
186+
187+
```java
188+
@Component
189+
public class GrandChild1Component extends VueComponent {
190+
@Inject AnotherService anotherService;
191+
}
192+
```
193+
194+
## Globally Registered Components {#globally-registered-components}
195+
196+
It's also possible to inject Components that are declared globally.
197+
For this you only need to inject their factory and use it for the global registration.
198+
When used in the templates, the instances will automatically be injected.
199+
200+
```java
201+
public class VueGwtExamplesApp implements EntryPoint {
202+
public void onModuleLoad() {
203+
ExampleInjector exampleInjector = DaggerExampleInjector.builder().build();
204+
MyGlobalComponentFactory factory = exampleInjector.getMyGlobalComponentFactory();
205+
VueGWT.register("my-global-component", factory);
206+
}
207+
}
208+
```
209+
210+
## Injecting Routes in Vue GWT Router {#vue-gwt-router}
211+
212+
If you are using [Vue GWT Router](https://github.com/Axellience/vue-router-gwt), you can also inject your Routes.
213+
214+
```java
215+
public class RoutesConfig implements CustomizeOptions {
216+
@Inject LoginComponentFactory loginComponentFactory;
217+
@Inject HomeComponentFactory homeComponentFactory;
218+
@Inject SettingsComponentFactory settingsComponentFactory;
219+
220+
@Override
221+
public void customizeOptions(VueComponentOptions vueComponentOptions) {
222+
RouterOptions routerOptions = new RouterOptions()
223+
.setMode(RouterMode.HISTORY)
224+
.addRoute("/login", loginComponentFactory)
225+
.addRoute("/home", homeComponentFactory)
226+
.addRoute("/settings", homeComponentFactory);
227+
228+
vueComponentOptions.set("router", new VueRouter(routerOptions));
229+
}
230+
}
231+
```

docs-source/examples/pom.xml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,16 @@
3232
<version>${vue-gwt.version}</version>
3333
</dependency>
3434
<dependency>
35-
<groupId>com.google.gwt.inject</groupId>
36-
<artifactId>gin</artifactId>
37-
<version>${gin.version}</version>
35+
<groupId>com.google.dagger</groupId>
36+
<artifactId>dagger-gwt</artifactId>
37+
<version>2.11</version>
38+
<scope>provided</scope>
39+
</dependency>
40+
<dependency>
41+
<groupId>com.google.dagger</groupId>
42+
<artifactId>dagger-compiler</artifactId>
43+
<version>2.11</version>
44+
<scope>provided</scope>
3845
</dependency>
3946

4047
<dependency>

docs-source/examples/src/main/java/com/axellience/vuegwtexamples/VueGwtExamples.gwt.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<inherits name='com.google.gwt.user.User'/>
77

88
<inherits name='com.axellience.vuegwt.VueGwt'/>
9-
<inherits name="com.google.gwt.inject.Inject"/>
9+
<inherits name="dagger.Dagger"/>
1010

1111
<!-- Specify the app entry point class. -->
1212
<entry-point class='com.axellience.vuegwtexamples.client.VueGwtExamplesApp'/>

docs-source/examples/src/main/java/com/axellience/vuegwtexamples/client/ExampleGinModule.java

Lines changed: 0 additions & 24 deletions
This file was deleted.
Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
package com.axellience.vuegwtexamples.client;
22

3-
import com.axellience.vuegwtexamples.client.examples.recursive.RecursiveComponentFactory;
4-
import com.axellience.vuegwtexamples.client.examples.tree.TreeComponentFactory;
5-
import com.google.gwt.inject.client.GinModules;
6-
import com.google.gwt.inject.client.Ginjector;
3+
import com.axellience.vuegwtexamples.client.examples.gotquotes.GotQuotesComponentFactory;
4+
import dagger.Component;
75

8-
@GinModules(ExampleGinModule.class)
9-
public interface ExampleInjector extends Ginjector
6+
import javax.inject.Singleton;
7+
8+
@Component
9+
@Singleton
10+
public interface ExampleInjector
1011
{
11-
RecursiveComponentFactory recursiveComponentFactory();
12-
TreeComponentFactory treeComponentFactory();
12+
GotQuotesComponentFactory gotQuoteComponentFactory();
1313
}

docs-source/examples/src/main/java/com/axellience/vuegwtexamples/client/VueGwtExamplesApp.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.axellience.vuegwtexamples.client.examples.message.MessageComponent;
2525
import com.axellience.vuegwtexamples.client.examples.parent.ParentComponent;
2626
import com.axellience.vuegwtexamples.client.examples.propdefaultvalue.ParentPropDefaultValueComponent;
27+
import com.axellience.vuegwtexamples.client.examples.recursive.RecursiveComponent;
2728
import com.axellience.vuegwtexamples.client.examples.reverse.ReverseComponent;
2829
import com.axellience.vuegwtexamples.client.examples.shareddatamodel.SharedDataModelComponent;
2930
import com.axellience.vuegwtexamples.client.examples.simplelink.SimpleLinkComponent;
@@ -32,14 +33,14 @@
3233
import com.axellience.vuegwtexamples.client.examples.todolist.TodoListComponent;
3334
import com.axellience.vuegwtexamples.client.examples.todotext.TodoTextComponent;
3435
import com.axellience.vuegwtexamples.client.examples.todotextcomputed.TodoTextComputedComponent;
36+
import com.axellience.vuegwtexamples.client.examples.tree.TreeComponent;
3537
import com.axellience.vuegwtexamples.client.examples.vforonobject.VForOnObjectComponent;
3638
import com.axellience.vuegwtexamples.client.examples.vforonobjectwithkey.VForOnObjectWithKeyComponent;
3739
import com.axellience.vuegwtexamples.client.examples.vforonobjectwithkeyandindex.VForOnObjectWithKeyAndIndexComponent;
3840
import com.axellience.vuegwtexamples.client.examples.vforwithindex.VForWithIndexComponent;
3941
import com.axellience.vuegwtexamples.client.examples.vforwithrange.VForWithRangeComponent;
4042
import com.axellience.vuegwtexamples.client.examples.vonwithdomevent.VOnWithDOMEventComponent;
4143
import com.google.gwt.core.client.EntryPoint;
42-
import com.google.gwt.core.client.GWT;
4344
import com.google.gwt.dom.client.Document;
4445

4546
/**
@@ -58,7 +59,7 @@ public void onModuleLoad()
5859
VueComponent myComponent = vueClass.instantiate();
5960
myComponent.$mount("#fullJsComponent");
6061

61-
ExampleInjector exampleInjector = GWT.create(ExampleInjector.class);
62+
ExampleInjector exampleInjector = DaggerExampleInjector.builder().build();
6263

6364
this.addExample("simpleLinkComponent", SimpleLinkComponent.class);
6465
this.addExample("linkComponent", LinkComponent.class);
@@ -88,14 +89,15 @@ public void onModuleLoad()
8889
this.addExample("sharedDataModelComponent2", SharedDataModelComponent.class);
8990
this.addExample("sharedDataModelComponent3", SharedDataModelComponent.class);
9091
this.addExample("counterWithEventComponent", CounterWithEventComponent.class);
91-
this.addExample("treeComponent", exampleInjector.treeComponentFactory());
92-
this.addExample("recursiveComponent", exampleInjector.recursiveComponentFactory());
92+
this.addExample("treeComponent", TreeComponent.class);
93+
this.addExample("recursiveComponent", RecursiveComponent.class);
9394
this.addExample("focusDirectiveComponent", FocusDirectiveComponent.class);
9495
this.addExample("renderAppComponent", RenderAppComponent.class);
9596
this.addExample("extendJavaComponent", ChildComponent.class);
9697
this.addExample("extendJsComponent", ChildJavaComponent.class);
9798
this.addExample("fullJsWithMethodsComponent", FullJsWithMethodsComponentFactory.get());
9899
this.addExample("propDefaultValueComponent", ParentPropDefaultValueComponent.class);
100+
this.addExample("gotQuotesComponent", exampleInjector.gotQuoteComponentFactory());
99101
}
100102

101103
private void addExample(String exampleId, Class<? extends VueComponent> exampleVueClass)

0 commit comments

Comments
 (0)