# Getting Started

This documentation comes from the official Vue.js guide and has been adapted for Vue GWT.

If you already know GWT then you should be familiar with the concept of Widgets. In Vue.js the equivalent of Widgets are Components.

Vue Components are like GWT Widgets, they are reusable and isolated pieces of your application.

# Your First Component

Let's create our first Component and use it in a real app. We will call it SimpleLinkComponent. This Component will simply display an html link.

# Declaring the Component

# SimpleLinkComponent.java

To create our Component, we must create a Class annotated by @Component that implements IsVueComponent.

@Component
public class SimpleLinkComponent implements IsVueComponent {
    @Data String linkName = "Hello Vue GWT!";
}

Adding @Data on the property makes it visible in the HTML template.

# SimpleLinkComponent.html

We will then create a template for our SimpleLinkComponent. It should have the same name as our Java Class file and be in the same package. Vue GWT will detect it automatically and use it as our Component template.

<a href="https://github.com/VueGWT/vue-gwt">
    {{ linkName }}
</a>

In this template we see that we use the linkName property from our Java Class between double curly braces. This is called String interpolation. At runtime, this expression is replaced by the value we have set in our Class.

Bellow we have instantiated an instance of our SimpleLinkComponent:

The bindings in the Components are dynamic, each time the value of linkName changes in your Component instance, the value is updated automatically in the view.

You can try it now on this page! Open the console of your browser and type:

simpleLinkComponent.linkName = "This is working!";

# Instantiating the Component

How do we instantiate our SimpleLinkComponent? First, in our GWT index page we add a div to attach the instance:

GwtIndex.html

<div id="simpleLinkComponentContainer"></div>

Then when GWT starts, we need to bootstrap an instance of our SimpleLinkComponent and attach it in our simpleLinkComponentContainer div.

To do this we simply call the Vue.attach() static method and pass the selector of our container and the Component factory. This factory is generated for you by Vue GWT annotation processor. If your IDE can't find it, make sure it is configured correctly.

RootGwtApp.java

public class RootGwtApp implements EntryPoint {
    public void onModuleLoad() {
        VueGWT.init();
        SimpleLinkComponent simpleLinkComponent = Vue.attach("#simpleLinkComponentContainer", SimpleLinkComponentFactory.get());
    }
}

In a typical application we only do this for the first root Component. We can then use Component composition.

# Why can't I just do new SimpleLinkComponent()?

Behind the scene, our Java IsVueComponent Class is converted to the options that Vue.js is expecting:

{
    render: function() {
    	...
    },
    data: {
        linkName: null
    },
    methods: {
    	...
    }
}

Those options are passed to the Vue.extend() JavaScript method. The result is a Factory we can use to generate new instances of our Vue Component.

# Binding Element Attributes

Our SimpleLinkComponent component works, but the target of our link is set in the template. What if we wanted to declare it in our Component?

Luckily, in addition to text interpolation, we can also bind element attributes. Let see how to do this with a new LinkComponent. This one will allow us to set the link href attribute in our Java Class.

@Component
public class LinkComponent implements IsVueComponent {
    @Data String linkName = "Hello Vue GWT!";
    @Data String linkTarget = "https://github.com/VueGWT/vue-gwt";
}
<a v-bind:href="linkTarget">
    {{ linkName }}
</a>

Here we are encountering something new. The v-bind attribute you are seeing is called a directive.

Directives are prefixed with v- to indicate that they are special attributes provided by Vue, and as you may have guessed, they apply special reactive behavior to the rendered DOM. Here it is basically saying "keep this element’s href attribute up-to-date with the linkTarget property on the Vue instance."

# Conditional and Loops

# Conditional

It’s quite simple to toggle the presence of an element too. For this we can use the v-if directive. Let's check this with a small example:

<div v-if="visible">
    The property "visible" is set to true!
</div>
@Component
public class CanHideComponent implements IsVueComponent {
    @Data boolean visible = true;
}

As you can see below the div is created if the property visible of the Component instance is set to true.

You can try to interact in your browser console by typing:

canHideComponent.visible = false;

The div will be removed from the DOM.

This example demonstrates that we can bind data to not only text and attributes, but also the structure of the DOM.

# Loops

There are quite a few other directives, each with its own special functionality. For example, the v-for directive can be used for displaying a list of items.

Let's assume we have a Todo POJO:

public class Todo {
    private String text;

    public Todo(String s) {
        this.text = s;
    }

    public String getText() {
        return text;
    }
}

We will then create a list of Todo in a SimpleTodoListComponent.

You will notice that we added a created method to our Component by implementing the HasCreated interface. This method will be called on each created instance of your Component. This is where you should put your initialization logic. You can see it as your Component constructor.

@Component
public class SimpleTodoListComponent implements IsVueComponent, HasCreated {
    @Data  
    @JsProperty
    List<Todo> todos = new LinkedList<>();
    
    @Override
    public void created() {
        this.todos.add(new Todo("Learn Java"));
        this.todos.add(new Todo("Learn Vue GWT"));
        this.todos.add(new Todo("Build something awesome"));
    }
}
<vue-gwt:import class="com.mypackage.Todo"/>
<ol>
    <li v-for="Todo todo in todos">
        {{ todo.getText() }}
    </li>
</ol>

You will notice that we added the @JsProperty annotation on the @Data field. Java collections fields need this annotation to be observed in Vue GWT. If you forget it, Vue GWT will throw an explicit error at compile time to remind you. For now this observation works for the List, Set and Map interfaces. For more information about Collections observation in Vue GWT check this page.

Another difference with Vue.js is you must indicate your loop variable type. This is because Vue GWT compile templates expressions to Java and so needs the type information. You can import Java types in your template by using the vue-gwt:import element.

TIP

You can also use static java imports in your templates:

<vue-gwt:import static="com.mypackage.Util.MY_STATIC_VARIABLE"/>
<vue-gwt:import static="com.mypackage.Util.myStaticMethod"/>

# Handling User Input

# Events

To let users interact with your app, we can use the v-on directive to attach event listeners that invoke methods on our Vue instances:

<div>
    <p>{{ message }}</p>
    <button v-on:click="addExclamationMark()">Add an explanation mark</button>
</div>
@Component
public class ExclamationComponent implements IsVueComponent {
    @Data String message = "Hello Vue GWT!";
    
    @JsMethod // Notice the @JsMethod annotation to expose this method to our template
    public void addExclamationMark() {
        this.message += "!";
    }
}

Note in the addExclamationMark method we simply update the state of our app without touching the DOM - all DOM manipulations are handled by Vue, and the code you write is focused on the underlying logic.

You can even call the addExclamationMark from your browser's console:

exclamationComponent.addExclamationMark();

# The v-model Directive

Vue also provides the v-model directive that makes two-way binding between form input and app state a breeze:

<div>
    <p>{{ message }}</p>
    <input type="text" v-model="message">
</div>
@Component
public class MessageComponent implements IsVueComponent {
    @Data String message = "Hello Vue GWT!";
}

Changing the value of the input will automatically update the content of our message property. Changing the value of our Java property will change the value of input:

WARNING

It's important to note that for now in Vue GWT only @Data fields or @Computed with a getter and a setter can be used directly in v-model. Check here to see why and get solutions.

# Composing with Components

The component system is another important concept in Vue, because it’s an abstraction that allows us to build large-scale applications composed of small, self-contained, and often reusable components. If we think about it, almost any type of application interface can be abstracted into a tree of components.

# Creating a Child Component

Let's create a child Component called TodoComponent. We will then instantiate this component in an ParentComponent.

This Component will display a simple message.

TodoComponent.java

We first create a Class like in our previous examples.

@Component
public class TodoComponent implements IsVueComponent {
}

We then create an HTML file with our Component template. We add this file next to our Java class as before.

TodoComponent.html

<li>
    I'm an amazing Todo!
</li>

ParentComponent.java

We will then create our ParentComponent that uses TodoComponent.

We first register TodoComponent to be used in our ParentComponent by passing it to the @Component annotation.

@Component(components = {TodoComponent.class})
public class ParentComponent implements IsVueComponent {
}

ParentComponent.html

Now you can compose it in our ParentComponent’s template:

<div>
    <ol>
        <todo></todo>
    </ol>
</div>

# Passing Properties to Children Components

Right now we render the same text for every todo, which is not super interesting. We should be able to pass data from the parent scope into child components.

Let’s modify our TodoComponent to make it accept a property.

TodoComponent.java

@Component
public class TodoComponent implements IsVueComponent {
    @Prop Todo todo;
}

The @Prop annotation tells Vue GWT that our todo property will be passed from a parent component.

TodoComponent.html

<li>
    {{ todo.getText() }}
</li>

TodoListComponent.java

Let's see how to pass this value from the parent.

We create a list of Todos like before. Let's call it TodoListComponent:

@Component(components = {TodoComponent.class})
public class TodoListComponent implements IsVueComponent, HasCreated {
    @Data
    @JsProperty
    List<Todo> todos = new LinkedList<>();
    
    @Override
    public void created() {
        this.todos.add(new Todo("Learn Java"));
        this.todos.add(new Todo("Learn Vue GWT"));
        this.todos.add(new Todo("Build something awesome"));
    }
}

TodoListComponent.html

And now we are able to pass the Todo into each repeated component using v-bind:

<vue-gwt:import class="com.mypackage.Todo"/>
<div>
    <ol>
        <todo v-for="Todo todo in todos" v-bind:todo="todo"></todo>
    </ol>
</div>

This is just a contrived example, but we have managed to separate our app into two smaller units, and the child is reasonably well-decoupled from the parent via the props interface. We can now further improve our <todo-item> component with more complex template and logic without affecting the parent app.

In a large application, it is necessary to divide the whole app into components to make development manageable. We will talk a lot more about components later in the guide, but here’s an (imaginary) example of what an app’s template might look like with components:

<div id="app">
  <app-nav></app-nav>
  <app-view>
    <app-sidebar></app-sidebar>
    <app-content></app-content>
  </app-view>
</div>

# How Is the Component HTML Name Set?

The name of the html element for our Component in the template (here, todo) is determined using the Component's Class name.

The name is converted from CamelCase to kebab-case. If the name ends with "Component" this part is dropped.

For example:

  • TodoComponent -> todo
  • TodoListComponent -> todo-list
  • Header -> header

# Registering Components Globally

Components can also be registered globally. They will then be usable in any Component in your app. You won't need to pass the class of your Vue Component to the components attribute in the @Component annotation.

public class RootGwtApp implements EntryPoint {
    public void onModuleLoad() {
        VueGWT.init();
        // Register TodoComponent globally under the name "todo"
        Vue.component(TodoComponentFactory.get());
    }
}

TIP

It's better to register locally whenever you can. Locally registered components get compile time type checking when binding property values. They also break at compile time if you forget a required property.

It is strongly recommended to read the whole Essentials section even if skimming through it. It will teach you everything you need to know to make full use of the framework.

You can then check some specific topics like Unit Testing, Custom Element (Web Component) support or Routing.