VueJS demo todo app guide

This guide provides step-by-step instructions for setting up and running a Jazz-powered Todo application using VueJS.

See the full example here.


Setup

Create a new app

Run the following command to create a new VueJS application:

pnpm create vue@latest Project name: vue-setup-guide Add TypeScript? Yes Add JSX Support? No Add Vue Router for Single Page Application development? Yes Add Pinia for state management? No Add Vitest for Unit Testing? No Add an End-to-End Testing Solution? No Add ESLint for code quality? Yes Add Prettier for code formatting? Yes

Install dependencies

Run the following command to install Jazz libraries:

pnpm install jazz-tools jazz-browser jazz-vue

Implement schema.ts

Define the schema for your application.

Example schema inside src/schema.ts for a todo app:

import { Account, CoList, CoMap, Group, Profile, co } from "jazz-tools"; export class ToDoItem extends CoMap { name = co.string; completed = co.boolean; } export class ToDoList extends CoList.Of(co.ref(ToDoItem)) {} export class Folder extends CoMap { name = co.string; items = co.ref(ToDoList); } export class FolderList extends CoList.Of(co.ref(Folder)) {} export class ToDoAccountRoot extends CoMap { folders = co.ref(FolderList); } export class ToDoAccount extends Account { profile = co.ref(Profile); root = co.ref(ToDoAccountRoot); migrate(this: ToDoAccount, creationProps?: { name: string }) { super.migrate(creationProps); if (!this._refs.root) { const group = Group.create({ owner: this }); const firstFolder = Folder.create( { name: "Default", items: ToDoList.create([], { owner: group }), }, { owner: group }, ); this.root = ToDoAccountRoot.create( { folders: FolderList.create([firstFolder], { owner: this, }), }, { owner: this }, ); } } }

Refactor main.ts

Update the src/main.ts file to integrate Jazz:

import "./assets/main.css"; import { DemoAuthBasicUI, createJazzVueApp, useDemoAuth } from "jazz-vue"; import { createApp, defineComponent, h } from "vue"; import App from "./App.vue"; import router from "./router"; import { ToDoAccount } from "./schema"; const Jazz = createJazzVueApp<ToDoAccount>({ AccountSchema: ToDoAccount }); export const { useAccount, useCoState } = Jazz; const { JazzProvider } = Jazz; const RootComponent = defineComponent({ name: "RootComponent", setup() { const { authMethod, state } = useDemoAuth(); return () => [ h( JazzProvider, { auth: authMethod.value, peer: "wss://cloud.jazz.tools/?key=vue-todo-example-jazz@garden.co", }, { default: () => h(App), }, ), state.state !== "signedIn" && h(DemoAuthBasicUI, { appName: "Jazz Vue Todo", state, }), ]; }, }); const app = createApp(RootComponent); app.use(router); app.mount("#app");

Set up router/index.ts:

Create a basic Vue router configuration. For example:

import { createRouter, createWebHistory } from "vue-router"; import HomeView from "../views/HomeView.vue"; const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: "/", name: "Home", component: HomeView, }, ], }); export default router;

Implement App.vue

Update the App.vue file to include logout functionality:

<template> <div class="app-container"> <header v-if="me" class="app-header"> <h1>Todo App</h1> <div class="user-section"> <span>{{ me.profile?.name }}</span> <button class="logout-btn" @click="logOut">Log out</button> </div> </header> <main> <router-view /> </main> </div> </template> <script setup lang="ts"> import { useAccount } from "./main"; const { me, logOut } = useAccount(); </script>

Subscribing to a CoValue

Subscribe to a CoValue inside src/views/HomeView.vue:

<script setup lang="ts"> import { Group, type ID } from "jazz-tools"; import { ref, toRaw, watch } from "vue"; import { computed } from "vue"; import { useAccount, useCoState } from "../main"; import { Folder, FolderList, ToDoItem, ToDoList } from "../schema"; const { me } = useAccount(); // Computed ID for the folders list const computedFoldersId = computed(() => me.value?.root?.folders?.id); // Load folders and nested values const folders = useCoState(FolderList, computedFoldersId, [{ items: [{}] }]);

See the full example here.

Mutating a CoValue

Here's how to create a new folder:

// continues previous example const createFolder = async (name: string) => { // Create a group owned by the current user const group = Group.create({ owner: me.value }); // Create the folder const newFolder = Folder.create( { name, items: ToDoList.create([], { owner: group }), }, { owner: group }, ); // Add the folder to the list of folders. // This change is sent to all connected clients and will be synced in real time. folders.value?.push(newFolder); newFolderName.value = ""; };

See the full example here.