Allows watching for various playground events. It takes 2 arguments: event name and a callback function that will be called on every event.
The watch method returns an object with a single method (remove), which when called will remove the callback from watching further events.
Signature
playground.watch(
event: "load" | "ready" | "code" | "console" | "tests" | "destroy",
fn: (data?: any) => void
): { remove: () => void }
Parameters
The event name to watch. Must be one of:
"load" - Called when the playground first loads
"ready" - Called when a new project is loaded and ready to run
"code" - Called when code changes
"console" - Called when there’s console output
"tests" - Called when tests run
"destroy" - Called when playground is destroyed
Callback function to execute when the event occurs. Receives event-specific data as an argument:
"load": No data
"ready": { config: Config }
"code": { code: Code, config: Config }
"console": { method: string, args: any[] }
"tests": { results: TestResult[], error?: string }
"destroy": No data
Returns
An object with a remove() method that, when called, unsubscribes the callback from the event.
Usage
Watch for Code Changes
import { createPlayground } from "livecodes";
const playground = await createPlayground("#container");
const codeWatcher = playground.watch("code", ({ code, config }) => {
// This runs on every code change
console.log("Code changed!");
console.log("Script content:", code.script.content);
console.log("Script language:", code.script.language);
console.log("Project title:", config.title);
});
// Later, stop watching
// codeWatcher.remove();
Watch Console Output
import { createPlayground } from "livecodes";
const playground = await createPlayground("#container");
const consoleWatcher = playground.watch("console", ({ method, args }) => {
// Mirror console output to parent page
console[method](...args);
// Or display in custom console UI
if (method === 'error') {
displayError(args);
}
});
Watch Test Results
import { createPlayground } from "livecodes";
const playground = await createPlayground("#container", {
config: {
tests: {
language: "javascript",
content: "test('example', () => expect(1).toBe(1));",
},
},
});
const testsWatcher = playground.watch("tests", ({ results, error }) => {
if (error) {
console.error("Test error:", error);
return;
}
results.forEach((testResult) => {
console.log("Test:", testResult.testPath.join(' > '));
console.log("Status:", testResult.status); // "pass", "fail", or "skip"
console.log("Duration:", testResult.duration, "ms");
if (testResult.status === 'fail') {
console.log("Errors:", testResult.errors);
}
});
});
Watch Playground Load
import { createPlayground } from "livecodes";
const playground = await createPlayground("#container", {
loading: "click", // Don't auto-load
});
const loadWatcher = playground.watch("load", () => {
console.log("Playground loaded!");
// Show UI elements, enable buttons, etc.
document.getElementById('run-button').disabled = false;
});
// Manually load when needed
await playground.load();
Watch for Ready State
import { createPlayground } from "livecodes";
const playground = await createPlayground("#container");
const readyWatcher = playground.watch("ready", ({ config }) => {
console.log("New project ready!");
console.log("Project title:", config.title);
console.log("Active editor:", config.activeEditor);
// Update UI to reflect the new project
document.getElementById('project-title').textContent = config.title;
});
// Load different projects
await playground.setConfig({ /* new config */ });
// "ready" event fires when new project is loaded
Watch for Destroy
import { createPlayground } from "livecodes";
const playground = await createPlayground("#container");
const destroyWatcher = playground.watch("destroy", () => {
console.log("Playground destroyed");
// Clean up any external resources
// Update UI state
});
await playground.destroy();
// "destroy" event fires
Auto-Save on Code Changes
import { createPlayground } from "livecodes";
const playground = await createPlayground("#container", {
config: {
autoupdate: true,
autosave: false, // We'll handle saving manually
},
});
let saveTimeout;
const codeWatcher = playground.watch("code", async ({ code, config }) => {
// Debounce saves
clearTimeout(saveTimeout);
saveTimeout = setTimeout(async () => {
console.log("Auto-saving...");
const fullConfig = await playground.getConfig(true);
localStorage.setItem('autosave', JSON.stringify(fullConfig));
console.log("Saved!");
}, 2000); // Save 2 seconds after last change
});
Display Live Code Stats
import { createPlayground } from "livecodes";
const playground = await createPlayground("#container");
const codeWatcher = playground.watch("code", ({ code }) => {
// Update stats display
const stats = {
markup: code.markup.content.length,
style: code.style.content.length,
script: code.script.content.length,
total: code.markup.content.length +
code.style.content.length +
code.script.content.length,
};
document.getElementById('stats').innerHTML = `
<div>Markup: ${stats.markup} chars</div>
<div>Style: ${stats.style} chars</div>
<div>Script: ${stats.script} chars</div>
<div><strong>Total: ${stats.total} chars</strong></div>
`;
});
Multiple Watchers
import { createPlayground } from "livecodes";
const playground = await createPlayground("#container");
// Watch multiple events
const watchers = [
playground.watch("load", () => {
console.log("Loaded");
}),
playground.watch("ready", ({ config }) => {
console.log("Ready:", config.title);
}),
playground.watch("code", ({ code }) => {
console.log("Code changed");
}),
playground.watch("console", ({ method, args }) => {
console[method](...args);
}),
];
// Later, remove all watchers
function cleanup() {
watchers.forEach(watcher => watcher.remove());
}
Conditional Event Handling
import { createPlayground } from "livecodes";
const playground = await createPlayground("#container");
const codeWatcher = playground.watch("code", ({ code, config }) => {
// Only log changes to JavaScript
if (code.script.language === 'javascript') {
console.log("JavaScript changed:", code.script.content);
}
// Alert on errors in console
// (This would need to be in a console watcher)
});
const consoleWatcher = playground.watch("console", ({ method, args }) => {
// Only show errors and warnings
if (method === 'error' || method === 'warn') {
showNotification(method, args);
}
});
Event Types
"load" Event
Fired when the playground iframe loads and initializes.
playground.watch("load", () => {
// No data passed
console.log("Playground UI loaded");
});
"ready" Event
Fired when a project is loaded and ready to run (including imports).
playground.watch("ready", ({ config }) => {
console.log("Config:", config);
});
"code" Event
Fired when code changes in any editor, or when languages, external resources, or custom settings change.
playground.watch("code", ({ code, config }) => {
console.log("Code:", code);
console.log("Config:", config);
});
"console" Event
Fired on every console method call from the result page.
playground.watch("console", ({ method, args }) => {
// method: "log", "info", "warn", "error", "table", etc.
// args: array of arguments passed to console method
});
"tests" Event
Fired when tests complete running.
playground.watch("tests", ({ results, error }) => {
if (error) {
console.error("Test error:", error);
} else {
console.log("Test results:", results);
}
});
"destroy" Event
Fired when the playground is destroyed.
playground.watch("destroy", () => {
// No data passed
console.log("Playground destroyed");
});
Notes
- Watchers automatically notify the playground that you want to receive events, so the playground knows to send data.
- When all watchers for an event are removed, the playground stops sending that event’s data.
- The
code event provides the same data structure as getCode().
- Console events are only sent when you have a console watcher active.
- Test events are only sent when you have a tests watcher active.
- Always call
remove() on watchers you no longer need to prevent memory leaks.
getCode() - Get current code (same structure as code event data)
getConfig() - Get current config (same structure as ready event data)
destroy() - Destroy the playground (triggers destroy event)