# Vue.js–Get started in Dart (Part 1)

I’ve been impressed with the mark that Vue.js has been making lately. Having used it [in the past and wantin](https://medium.com/@graphicbeacon/how-to-use-vue-2-0-components-in-an-angular-application-4d85bacc42dc)g to use it again, I got curious about what it looks like working with Vue in Dart.

## Prefer a video?

%[https://www.youtube.com/watch?v=zoN1_5tYzOM] 

Having demonstrated that it’s possible to [use JavaScript libraries in Dart web apps, we will go through the Vue.js “**Getting**](http://localhost:8080/how-to-use-javascript-libraries-in-your-dart-applications/) **started**” page and rewrite the examples in Dart, using the `js` interop package.

## **Before we begin:**

### **1\. Set up your project**

Set-up your web project quickly with Stagehand:

```bash
$ mkdir vue_dart && cd vue_dart
$ stagehand web-simple
```

### **2\. Install the js interop package**

Ensure that the `js` dependency is added to your `pubspec.yaml` file:

```yaml
dependencies:
  js: ^0.6.1+1
```

Save and run `pub get` to update your dependencies.

### **3\. Import the Vue.js library**

In `web/index.html` in the `<head>` before `<script defer src="main.dart.js"></script>` import the dev version of the library:

```xml
<!-- development version, includes helpful console warnings -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
```

Now we can go through the examples!

## **Getting started**

Create a `web/app.dart` file with our library declaration and imports:

```dart
@JS()
library vue_interop;

import 'package:js/js.dart';

// TODO: The rest of the code to go here
```

### **Declarative rendering**

Here’s the first example of a template with the `message` property placeholder:

```xml
<div id="app">
  {{ message }}
</div>
```

Create an annotated factory constructor for `Vue`:

```dart
@JS()
class Vue {
  external factory Vue(VueOptions options);
}
```

The JavaScript api takes an object literal when a new `Vue` instance is declared. Notice the declaration of the `VueOptions` type instead of `Map`? We cannot use Dart `Map`s here since they are opaque in JavaScript.

Therefore, we need to create a factory constructor to house our options:

```dart
@JS()
@anonymous
class VueOptions {
  external factory VueOptions({ String el, VueDataOptions data });
  external String get el;
  external VueDataOptions get data;
}
```

And the data prop is a `VueDataOptions` object:

```dart
@JS()
@anonymous
class VueDataOptions {
  external factory VueDataOptions({
    String message = '', // Set to empty string as default
  });
  external String get message;
}
```

Return to `web/main.dart` and let's use these factories:

```dart
// Relative imports
import './app.dart';

void main() {
  Vue(VueOptions(
    el: '#app',
    data: VueDataOptions(
      message: 'Hello Vue!',
    ),
  ));
}
```

You should now see the text “**Hello Vue!**” on the screen:

In addition to string interpolation we can also bind element attributes.

```xml
<div id="app-2">
  <span v-bind:title="message">
    Hover your mouse over me for a few seconds
    to see my dynamically bound title!
  </span>
</div>
```

No changes needed on our factory, just declare a call:

```dart
// web/main.dart
...
void main() {
  ...

  // App 2 example
  Vue(VueOptions(
    el: '#app-2',
    data: VueDataOptions(
      message: 'You loaded this page on ${DateTime(2018).toLocal()}',
    ),
  ));
}
```

### **Conditionals**

Use the `v-if` attribute to toggle the presence of an element:

```xml
<div id="app-3">
  <span v-if="seen">Now you see me</span>
</div>
```

Since we are watching a new property (`seen`), let’s add a getter for this in our factory:

```dart
@JS()
@anonymous
class VueDataOptions {
  external factory VueDataOptions({
    String message = '',
    bool seen = null, // <-- Added this
  });
  external String get message;
  external bool get seen; // <-- Added this
}
```

And in `web/main.dart`:

```dart
...
void main() {
  ...
  // App 3 example
  var app3 = Vue(VueOptions(
    el: '#app-3',
    data: VueDataOptions(seen: true),
  ));
}
```

In the snippet above we have assigned the result of calling `Vue()` to an `app3` variable. The docs demonstrate doing `app3.seen = false`, which means we have to add a getter of type boolean to `Vue` class in `web/app.dart`:

```dart
@JS()
class Vue {
  external factory Vue(VueOptions options);
  external void set seen(bool val); // <-- Added this
}
```

And in `web/main.dart`, we will do:

```dart
import 'dart:async'; // <-- Added this line to use `Future.delayed`

// Relative imports
import './todo.dart'; // <-- Added this line
import './app.dart';

void main() {
  ...
  ...

  // App 3 example
  var app3 = Vue(VueOptions(
    el: '#app-3',
    data: VueDataOptions(seen: true),
  ));

  // Added a delay to see disappearing text
  Future.delayed(Duration(seconds: 2), () async {
    app3.seen = false;

    // Added a delay and then restored text visibility
    await Future.delayed(Duration(seconds: 2));
    app3.seen = true;
  });
}
```

### **Loops**

The `v:for` attribute is used when iterating over arrays:

```xml
<div id="app-4">
  <ol>
    <li v-for="todo in todos">
      {{ todo.text }}
    </li>
  </ol>
</div>
```

This introduces a new factory constructor, which we’ll call `Todo`.

Create `web/todo.dart` with our factory class:

```dart
@JS()
library todo;

import 'package:js/js.dart';

@JS()
@anonymous
class Todo {
  external factory Todo({String text});
  external String get text;
}
```

And in `web/app.dart`, let’s define a list of `Todo`s:

```dart
@JS()
class Vue {
  external factory Vue(VueOptions options);
  external void set seen(bool val);
  external List<Todo> get todos; // <-- Added this line
}

...

@JS()
@anonymous
class VueDataOptions {
  external factory VueDataOptions({
    String message = '',
    bool seen = null,
    List<Todo> todos = const [],
  });
  external String get message;
  external bool get seen;
  external List<Todo> get todos; // <-- Added this line
}
```

And in `web/main.dart` we’ll use it:

```dart
...
...
void main() {
  ...
  ...

  // App 4 example
  var app4 = Vue(VueOptions(
    el: '#app-4',
    data: VueDataOptions(todos: [
      Todo(text: 'Learn Dart'),
      Todo(text: 'Learn Aqueduct'),
      Todo(text: 'Build something awesome!'),
    ]),
  ));
}
```

In order to add a new item to the todos list like the docs show:

```dart
app4.todos.push({ text: 'New item' });
```

We’ll need to add a getter for `todos` on `Vue`:

```dart
// web/app.dart
...
...

@JS()
class Vue {
  external factory Vue(VueOptions options);
  external void set seen(bool val);
  external List<Todo> get todos; // <-- Added this line
}
```

And in `web/main.dart`:

```dart
...
...
  // App 4 example
  var app4 = Vue(VueOptions(
    el: '#app-4',
    data: VueDataOptions(todos: [
      Todo(text: 'Learn Dart'),
      Todo(text: 'Learn Aqueduct'),
      Todo(text: 'Build something awesome!'),
    ]),
  ));

  app4.todos.add(Todo(text: 'New item')); // <-- Added this line
```

## **Conclusion**

And this brings us to the end of Part 1. In part 2, we will look at handling user input and composition with Vue components.

## **Further reading**

1. [js package](https://pub.dartlang.org/packages/js)
    
2. [How to Use JavaScript libraries in your Dart applications](http://localhost:8080/how-to-use-javascript-libraries-in-your-dart-applications/)
    
3. [**Full-stack web development with Dart**](http://bit.ly/2P2N1jC)
