Skip to main content

@myop/angular

Official Angular bindings for embedding Myop components in your Angular applications.

Myop components are framework-agnostic UI components that can be updated in real-time without redeploying your application. Build once, embed anywhere, and iterate instantly. Perfect for teams that need to ship UI changes fast, A/B test components, or empower non-developers to customize the interface. Myop is also the safest way to adopt AI-generated components in your application—whether created by developers or non-developers—with built-in sandboxing and controlled integration.

npm version License: MIT Discord

Website | Documentation | Dashboard | Discord

Installation

npm install @myop/angular
yarn add @myop/angular
pnpm add @myop/angular

Auto-Generated Angular Components

Myop automatically generates a typed Angular component package for every component you create in the dashboard. Install it directly via npm:

npm install https://cloud.myop.dev/npm/{component-id}/angular

Setup (One-Time Configuration)

Add node_modules/@myop to your TypeScript compilation in tsconfig.app.json:

{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app"
},
"include": [
"src/**/*.d.ts",
"src/**/*.ts",
"node_modules/@myop/**/*.ts"
]
}

This allows Angular to compile the auto-generated component packages alongside your application code.

Usage

Import and use the generated component directly. For example, if you created a table component called "users-table" in the dashboard:

import { Component } from "@angular/core";
import { UsersTableComponent, UsersTableCtaPayloads, CtaEvent } from "@myop/users-table";

@Component({
selector: "app-root",
standalone: true,
imports: [UsersTableComponent],
template: `
<users-table
[data]="{ rows: users }"
(cta)="onCta($event)"
/>
`,
})
export class AppComponent {
users = [
{ id: 1, name: "Alice", email: "alice@example.com", role: "Admin" },
{ id: 2, name: "Bob", email: "bob@example.com", role: "User" },
{ id: 3, name: "Charlie", email: "charlie@example.com", role: "User" },
];

onCta(event: CtaEvent<UsersTableCtaPayloads>) {
switch (event.action) {
case "rowClicked":
console.log("Selected user:", event.payload.rowData);
break;
case "deleteClicked":
this.deleteUser(event.payload.userId);
break;
case "exportRequested":
this.exportToFormat(event.payload.format);
break;
}
}
}

Why this is powerful:

  • Fully typed — The generated package includes complete TypeScript types for your component's data interface and all CTA event payloads
  • Auto loaded — Components are fetched and rendered automatically, no manual setup required
  • Not in your code — The actual component implementation lives on Myop and is loaded at runtime. Update your component in the dashboard and it's instantly live—no rebuild, no redeploy
  • Zero bundle impact — The entire @myop/angular package costs only ~6KB gzipped—and that's the total cost whether you use 1, 2, or 1,000 components. Auto-generated component packages are just thin typed wrappers. The actual component implementations are loaded at runtime, meaning your Myop components can be as complex, feature-rich, and heavy as you need without adding a single byte to your application bundle. Consider typical bundle costs: a chart library (~60KB), a map component (~200KB), a data grid (~150KB), a rich text editor (~100KB), or a chat widget with emoji picker (~80KB). With Myop, all of these cost ~0KB to your bundle—they load on-demand when needed

Environment options:

Set the default environment for all components using setEnvironment:

import { setEnvironment } from "@myop/angular";

// Set default environment for all component loads
setEnvironment("staging");

You can also override the environment directly on a specific component:

<myop-users-table
[data]="{ rows: users }"
[preview]="true"
environment="staging"
/>

Environments are fully configurable in the dashboard, allowing you to test changes in staging before publishing to production.

For more details on auto-generated packages, see the Auto-Generated Packages documentation.

Requirements

  • Angular 17.0+

Quick Start

import { Component } from "@angular/core";
import { MyopComponent } from "@myop/angular";

@Component({
selector: "app-root",
standalone: true,
imports: [MyopComponent],
template: `
<myop-component
[componentId]="'your-component-id'"
[style]="{ width: '600px', height: '400px' }"
(action)="onAction($event)"
/>
`,
})
export class AppComponent {
onAction(event: { action: string; payload: any }) {
console.log("Action:", event.action, "Payload:", event.payload);
}
}

Components

myop-component

The main component for embedding Myop components.

import { Component } from "@angular/core";
import { MyopComponent } from "@myop/angular";

@Component({
selector: "app-dashboard",
standalone: true,
imports: [MyopComponent],
template: `
<myop-component
[componentId]="'abc123'"
[data]="{ items: items }"
(rowClicked)="onRowClicked($event)"
(load)="onLoad($event)"
(error)="onError($event)"
/>
`,
})
export class DashboardComponent {
items = [
{ id: 1, name: "Item 1" },
{ id: 2, name: "Item 2" },
];

onRowClicked(payload: any) {
console.log("Row clicked:", payload);
}

onLoad(component: any) {
console.log("Loaded!", component);
}

onError(error: string) {
console.error("Error:", error);
}
}

Inputs

InputTypeDescription
componentIdstringThe ID of the Myop component to load
dataobjectData to pass to the component via myop_init_interface
styleobjectCSS styles for the container
fadeDurationnumberLoader fade-out duration in ms (default: 200)
environmentstringLoad from a specific environment (e.g., "staging", "prod")
previewbooleanLoad the unpublished preview version of the component

Outputs

OutputTypeDescription
(action)EventEmitter<{action, payload}>Generic handler for all CTA events
([actionName])EventEmitter<payload>Handler for specific actions (e.g., (rowClicked))
(load)EventEmitter<component>Called when the component finishes loading
(error)EventEmitter<string>Called when loading fails

Inputs for Loading/Fallback

InputTypeDescription
loaderTemplateRefLoading indicator template (default: null - no loader). Use MyopLoader for default Myop loader
fallbackTemplateRefError fallback template (default: built-in MyopFallback). Override with custom template

Environments & Preview

Myop supports multiple environments, allowing you to test changes before going live:

<!-- Production (default) -->
<myop-component [componentId]="'abc123'" />

<!-- Load from staging environment -->
<myop-component [componentId]="'abc123'" environment="staging" />

<!-- Load unpublished preview version (for testing before publishing) -->
<myop-component [componentId]="'abc123'" [preview]="true" />

<!-- Combine both: preview version in staging -->
<myop-component [componentId]="'abc123'" environment="staging" [preview]="true" />

Environments are configured in the dashboard. Use [preview]="true" to test unpublished changes before making them live.

myop-container (Legacy)

The legacy container component. Use myop-component for new projects.

import { Component } from "@angular/core";
import { MyopContainerComponent } from "@myop/angular";

@Component({
selector: "app-root",
standalone: true,
imports: [MyopContainerComponent],
template: `
<myop-container
[componentId]="'abc123'"
(componentReady)="onReady($event)"
/>
`,
})
export class AppComponent {
onReady(component: any) {
console.log("Ready!", component);
}
}

Type-Safe Event Handlers

Define your CTA payloads for fully typed event handlers:

import { Component } from "@angular/core";
import { MyopComponent } from "@myop/angular";

// Define your component's data and CTA payload types
interface MyData {
items: { id: string; name: string }[];
}

interface RowClickedPayload {
rowIndex: number;
rowData: any;
}

interface ItemSelectedPayload {
itemId: string;
}

interface ExportRequestedPayload {
format: "csv" | "json";
}

@Component({
selector: "app-dashboard",
standalone: true,
imports: [MyopComponent],
template: `
<myop-component
[componentId]="'dashboard-component'"
[data]="data"
(rowClicked)="onRowClicked($event)"
(itemSelected)="onItemSelected($event)"
(action)="onAction($event)"
/>
`,
})
export class DashboardComponent {
data: MyData = {
items: [
{ id: "1", name: "Item 1" },
{ id: "2", name: "Item 2" },
],
};

onRowClicked(payload: RowClickedPayload) {
console.log("Row clicked:", payload.rowIndex);
}

onItemSelected(payload: ItemSelectedPayload) {
console.log("Item selected:", payload.itemId);
}

onAction(event: { action: string; payload: any }) {
console.log(event.action, event.payload);
}
}

Configuration

Preloading Components

Preload components for faster rendering:

import { preloadComponents, isPreloaded } from "@myop/angular";

// Preload multiple components
await preloadComponents(["component-1", "component-2"]);

// Check if a component is preloaded
if (isPreloaded("component-1")) {
console.log("Component is cached and ready");
}

Custom Repository URL

import { setCloudRepositoryUrl } from "@myop/angular";

// Point to a custom Myop server
setCloudRepositoryUrl("https://your-custom-server.com");

Environment Configuration

import { setEnvironment } from "@myop/angular";

// Set default environment for all component loads
setEnvironment("staging");

Local Development

import { enableLocalDev } from "@myop/angular";

// Connect to local Myop development server (localhost:9292)
enableLocalDev();

Advanced: Custom Repository

import { setCloudRepository, getCloudRepository } from "@myop/angular";
import { CloudRepository } from "@myop/sdk/helpers";

// Set a custom CloudRepository instance
const customRepo = new CloudRepository("https://custom-url.com");
setCloudRepository(customRepo);

// Get the current repository
const repo = getCloudRepository();

Loading & Error States

By default, no loader is shown while the component loads. The Myop-branded fallback is displayed automatically on error.

Using the Default Myop Loader

import { Component } from "@angular/core";
import { MyopComponent, MyopLoader } from "@myop/angular";

@Component({
selector: "app-example",
standalone: true,
imports: [MyopComponent, MyopLoader],
template: `
<myop-component [componentId]="'my-component'" [loader]="loaderTpl" [fadeDuration]="300">
</myop-component>

<ng-template #loaderTpl>
<myop-loader></myop-loader>
</ng-template>
`,
})
export class ExampleComponent {}

Custom Loading State

@Component({
selector: "app-example",
standalone: true,
imports: [MyopComponent],
template: `
<myop-component [componentId]="'my-component'" [loader]="loaderTpl" [fadeDuration]="300">
</myop-component>

<ng-template #loaderTpl>
<div class="custom-loader">
<app-spinner />
<p>Loading component...</p>
</div>
</ng-template>
`,
})
export class ExampleComponent {}

Custom Error Fallback

import { Component } from "@angular/core";
import { MyopComponent, MyopFallback } from "@myop/angular";

@Component({
selector: "app-example",
standalone: true,
imports: [MyopComponent, MyopFallback],
template: `
<myop-component [componentId]="'my-component'" [fallback]="fallbackTpl">
</myop-component>

<!-- Custom fallback -->
<ng-template #fallbackTpl>
<div class="error-state">
<p>Failed to load component</p>
<button (click)="retry()">Retry</button>
</div>
</ng-template>

<!-- Or use default Myop fallback explicitly -->
<ng-template #myopFallbackTpl>
<myop-fallback></myop-fallback>
</ng-template>
`,
})
export class ExampleComponent {
retry() {
window.location.reload();
}
}

Using in NgModules

If you're not using standalone components, import in your module:

import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { MyopComponent } from "@myop/angular";
import { AppComponent } from "./app.component";

@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, MyopComponent],
bootstrap: [AppComponent],
})
export class AppModule {}

API Reference

Exports

ExportDescription
MyopComponentMain component for embedding Myop components
MyopLoader / MyopLoaderComponentDefault Myop-branded loading indicator (opt-in)
MyopFallback / MyopFallbackComponentDefault Myop-branded error fallback
preloadComponentsPreload components for faster rendering
isPreloadedCheck if a component is cached
enableLocalDevEnable local development mode
setCloudRepositoryUrlSet custom server URL
setCloudRepositorySet custom CloudRepository instance
getCloudRepositoryGet current CloudRepository instance
setEnvironmentSet default environment

License

MIT