Skip to content

Angular

Terminal window
bun add @slop-ai/client @slop-ai/angular

Create a SLOP client instance for your app:

import { createSlop } from "@slop-ai/client";
export const slop = createSlop({
id: "notes-app",
name: "Notes App",
});

The useSlop function is called in the constructor. It registers a node using Angular signals for reactivity and unregisters it on destroy.

import { action, useSlop } from "@slop-ai/angular";

The signature is useSlop(client, pathOrGetter, descriptorFactory) where the descriptor function is re-evaluated whenever the signals it reads change.

import { Component, signal, computed } from "@angular/core";
import { action, useSlop } from "@slop-ai/angular";
import { slop } from "./slop";
interface Note {
id: string;
title: string;
pinned: boolean;
}
@Component({
selector: "app-notes",
template: `
<ul>
@for (note of notes(); track note.id) {
<li>{{ note.pinned ? "📌 " : "" }}{{ note.title }}</li>
}
</ul>
`,
})
export class NotesComponent {
notes = signal<Note[]>([]);
constructor() {
useSlop(slop, "/notes", () => ({
type: "collection",
props: { count: this.notes().length },
actions: {
create: action({ title: "string" }, ({ title }) => {
this.notes.update((prev) => [
...prev,
{ id: crypto.randomUUID(), title, pinned: false },
]);
}),
clear_all: action(() => this.notes.set([]), { dangerous: true }),
},
items: this.notes().map((note) => ({
id: note.id,
props: { title: note.title, pinned: note.pinned },
actions: {
toggle_pin: action(() => {
this.notes.update((prev) =>
prev.map((entry) =>
entry.id === note.id ? { ...entry, pinned: !entry.pinned } : entry,
),
);
}),
},
})),
}));
}
}