Vue.js–Getting started in Dart (Part 1)
Tags: dart, javascript, showdev, vue
Published: 2018-11-05 12:15:16

---
title: Vue.js–Getting started in Dart (Part 1)
published: true
description: Learn how to write Dart code for the Vue.js framework
tags: dart, javascript, showdev, vue
cover_image: https://thepracticaldev.s3.amazonaws.com/i/3ycelqh95j0dszpaa0do.png
series: Vue.js–Getting started in Dart
canonical_url: https://creativebracket.com/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](https://medium.com/@graphicbeacon/how-to-use-vue-2-0-components-in-an-angular-application-4d85bacc42dc) and wanting to use it again, I got curious about what it looks like working with Vue in Dart.

Having demonstrated that it's possible to [use JavaScript libraries in Dart web apps](https://dev.to/graphicbeacon/how-to-use-javascript-libraries-in-your-dart-applications--4mc6), we will go through the Vue.js "**Getting started**" page and rewrite the examples in Dart, using the **`js`** interop package.

{% youtube zoN1_5tYzOM %}
→ [**Watch on Youtube**](https://youtu.be/zoN1_5tYzOM)

---

# 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:

```dart
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:

```html
<!-- 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:

```html
<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 lets 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.

```html
<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:

```html
<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:

```html
<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: 

```js
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. 

As always, I hope this was insightful and you learned something new today.

**Subscribe to [my YouTube channel](https://www.youtube.com/channel/UCHSRZk4k6e-hqIXBBM4b2iA?view_as=subscriber) for the latest videos on Dart**. Thanks!

**Like, share and follow me** 😍 for more content on Dart.

## Further reading

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