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.