or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

behaviors.mdcollection-views.mdindex.mdobjects-and-application.mdregions.mdutilities.mdviews.md
tile.json

objects-and-application.mddocs/

Objects and Applications

Base object classes and application management for organizing global application state, Radio communication, and top-level view management.

Capabilities

MnObject Class

The base object class that provides common functionality including lifecycle management, event handling, and Backbone.Radio integration.

/**
 * Base object class with common functionality and Radio integration
 * @param options - Configuration options for the object
 */
const MnObject: {
  new (options?: MnObjectOptions): MnObject;
  extend(properties: object, classProperties?: object): typeof MnObject;
};

interface MnObject {
  /** Initialize the object (noop method for overriding) */
  initialize(): void;
  
  /** Check if the object has been destroyed */
  isDestroyed(): boolean;
  
  /** Destroy the object and clean up resources */
  destroy(options?: DestroyOptions): this;
  
  /** Get the Radio channel for this object */  
  getChannel(): RadioChannel;
  
  /** Unique identifier for the object */
  cid: string;
}

interface MnObjectOptions {
  /** Channel name for Backbone.Radio */
  channelName?: string;
  
  /** Hash of Radio event handlers */
  radioEvents?: RadioEventsHash;
  
  /** Hash of Radio request handlers */
  radioRequests?: RadioRequestsHash;
}

Usage Examples:

import { MnObject } from "backbone.marionette";

// Basic object
class MyService extends MnObject {
  initialize() {
    console.log('Service initialized');
  }
  
  doSomething() {
    console.log('Doing something...');
  }
  
  onDestroy() {
    console.log('Service destroyed');
  }
}

// Object with Radio integration
class DataService extends MnObject {
  channelName: 'data'
  
  radioRequests() {
    return {
      'fetch:user': 'fetchUser',
      'save:user': 'saveUser'
    };
  }
  
  radioEvents() {
    return {
      'user:updated': 'onUserUpdated'
    };
  }
  
  fetchUser(id) {
    // Fetch user logic
    return { id, name: 'John Doe' };
  }
  
  saveUser(userData) {
    // Save user logic
    console.log('Saving user:', userData);
  }
  
  onUserUpdated(user) {
    console.log('User updated:', user);
  }
}

// Usage
const service = new DataService();
const channel = service.getChannel();

// Make requests
const user = channel.request('fetch:user', 123);
channel.request('save:user', { id: 123, name: 'Jane Doe' });

// Trigger events
channel.trigger('user:updated', user);

Application Class

The main application class that extends MnObject and provides global application management, including a root region for displaying views.

/**
 * Main application class for global state and view management
 * @param options - Configuration options for the application
 */
class Application extends MnObject {
  constructor(options?: ApplicationOptions): Application;
  
  /** Start the application with options */
  start(options?: object): this;
  
  /** Get the application's root region */
  getRegion(): Region;
  
  /** Show a view in the application's root region */
  showView(view: View, ...args: any[]): View;
  
  /** Get the current view from the application's root region */
  getView(): View | undefined;
}

interface ApplicationOptions extends MnObjectOptions {
  /** Region definition for the application's root region */
  region?: string | RegionDefinition;
  
  /** Region class to use for the root region */
  regionClass?: typeof Region;
}

Usage Examples:

import { Application, View } from "backbone.marionette";

// Basic application
class MyApplication extends Application {
  region: '#app'
  
  onStart(options) {
    console.log('Application started with options:', options);
    
    // Show initial view
    const homeView = new HomeView();
    this.showView(homeView);
  }
}

// Application with Radio integration
class ChatApplication extends Application {
  region: '#chat-app'
  channelName: 'chat'
  
  radioRequests() {
    return {
      'show:conversation': 'showConversation',
      'show:contacts': 'showContacts'
    };
  }
  
  radioEvents() {
    return {
      'user:login': 'onUserLogin',
      'user:logout': 'onUserLogout'
    };
  }
  
  onStart() {
    // Initialize application
    this.showView(new LoginView());
  }
  
  showConversation(conversationId) {
    const conversationView = new ConversationView({ 
      model: new Conversation({ id: conversationId }) 
    });
    this.showView(conversationView);
  }
  
  showContacts() {
    const contactsView = new ContactsView();
    this.showView(contactsView);
  }
  
  onUserLogin(user) {
    console.log('User logged in:', user);
    this.showView(new DashboardView({ model: user }));
  }
  
  onUserLogout() {
    console.log('User logged out');
    this.showView(new LoginView());
  }
}

// Start the application
const app = new ChatApplication();
app.start({ environment: 'production' });

// Navigate using Radio
const chatChannel = app.getChannel();
chatChannel.request('show:conversation', 'conv-123');

Object Lifecycle Management

Methods for managing object lifecycle and state.

/**
 * Initialize the object (called automatically by constructor)
 * Override this method to add custom initialization logic
 */
initialize(): void;

/**
 * Check if the object has been destroyed
 * @returns True if object is destroyed
 */
isDestroyed(): boolean;

/**
 * Destroy the object and clean up all resources
 * @param options - Destroy options
 * @returns The object instance for chaining
 */
destroy(options?: DestroyOptions): this;

Usage Examples:

// Custom initialization
class ConfiguredService extends MnObject {
  initialize(options = {}) {
    this.config = _.defaults(options.config || {}, {
      timeout: 5000,
      retries: 3
    });
    
    this.setupEventHandlers();
  }
  
  setupEventHandlers() {
    // Setup custom event handlers
  }
  
  onDestroy() {
    // Custom cleanup
    this.config = null;
  }
}

// Usage
const service = new ConfiguredService({
  config: { timeout: 10000 }
});

// Later...
service.destroy(); // Triggers cleanup
console.log(service.isDestroyed()); // true

Radio Communication

Methods for integrating with Backbone.Radio for decoupled communication.

/**
 * Get the Radio channel for this object
 * @returns Backbone.Radio channel instance
 */
getChannel(): RadioChannel;

Usage Examples:

// Service communication
class UserService extends MnObject {
  channelName: 'users'
  
  radioRequests() {
    return {
      'current:user': 'getCurrentUser',
      'login': 'loginUser',
      'logout': 'logoutUser'
    };
  }
  
  getCurrentUser() {
    return this.currentUser;
  }
  
  loginUser(credentials) {
    // Login logic
    this.currentUser = { id: 1, name: 'John' };
    this.getChannel().trigger('user:logged:in', this.currentUser);
    return this.currentUser;
  }
  
  logoutUser() {
    const user = this.currentUser;
    this.currentUser = null;
    this.getChannel().trigger('user:logged:out', user);
  }
}

// Another service listening to user events
class NotificationService extends MnObject {
  channelName: 'users'
  
  radioEvents() {
    return {
      'user:logged:in': 'onUserLogin',
      'user:logged:out': 'onUserLogout'
    };
  }
  
  onUserLogin(user) {
    this.showWelcomeMessage(user);
  }
  
  onUserLogout(user) {
    this.showGoodbyeMessage(user);
  }
}

// Usage across the application
const userChannel = Radio.channel('users');
const user = userChannel.request('current:user');
userChannel.request('login', { username: 'john', password: '123' });

Properties

/** Unique identifier prefix for objects */
cidPrefix: 'mno'; // for MnObject

/** Unique identifier prefix for applications */
cidPrefix: 'mna'; // for Application

/** Default region class for applications */
regionClass: typeof Region; // Application only

/** Unique identifier for the object instance */
cid: string;

Object Lifecycle Events

Objects trigger events during their lifecycle:

// Destroy lifecycle
object.on('before:destroy', (object, options) => { /* ... */ });
object.on('destroy', (object, options) => { /* ... */ });

// Application start lifecycle
app.on('before:start', (app, options) => { /* ... */ });
app.on('start', (app, options) => { /* ... */ });

Usage Examples:

// Global lifecycle monitoring
const app = new MyApplication();

app.on('before:start', (app, options) => {
  console.log('Application starting...');
  // Setup analytics, logging, etc.
});

app.on('start', (app, options) => {
  console.log('Application started!');
  // Application is ready
});

// Object cleanup monitoring
const service = new MyService();

service.on('destroy', (service) => {
  console.log('Service destroyed');
  // Notify other parts of the system
});

Advanced Usage Patterns

Service Layer Architecture

// Base service class
class BaseService extends MnObject {
  channelName: 'services'
  
  radioRequests() {
    return {
      [`${this.serviceName}:start`]: 'start',
      [`${this.serviceName}:stop`]: 'stop',
      [`${this.serviceName}:status`]: 'getStatus'
    };
  }
  
  start() {
    this.isRunning = true;
    this.getChannel().trigger(`${this.serviceName}:started`, this);
  }
  
  stop() {
    this.isRunning = false;
    this.getChannel().trigger(`${this.serviceName}:stopped`, this);
  }
  
  getStatus() {
    return {
      name: this.serviceName,
      running: this.isRunning
    };
  }
}

// Specific services
class EmailService extends BaseService {
  serviceName: 'email'
  
  sendEmail(to, subject, body) {
    // Email sending logic
  }
}

class LoggingService extends BaseService {
  serviceName: 'logging'
  
  log(level, message) {
    // Logging logic
  }
}

Application with Service Management

class ServiceManagedApplication extends Application {
  initialize() {
    this.services = new Map();
    this.initializeServices();
  }
  
  initializeServices() {
    // Register services
    this.registerService('email', new EmailService());
    this.registerService('logging', new LoggingService());
  }
  
  registerService(name, service) {
    this.services.set(name, service);
    
    // Start service
    const channel = Radio.channel('services');
    channel.request(`${name}:start`);
  }
  
  onStart() {
    // All services started, show main view
    this.showView(new MainView());
  }
  
  onDestroy() {
    // Stop all services
    for (const [name, service] of this.services) {
      service.destroy();
    }
    this.services.clear();
  }
}

Type Definitions

interface RadioEventsHash {
  [eventName: string]: string | ((...args: any[]) => any);
}

interface RadioRequestsHash {
  [requestName: string]: string | ((...args: any[]) => any);
}

interface RadioChannel {
  request(requestName: string, ...args: any[]): any;
  trigger(eventName: string, ...args: any[]): void;
  on(eventName: string, callback: (...args: any[]) => any): void;
  off(eventName?: string, callback?: (...args: any[]) => any): void;
  stopListening(): void;
}

interface RegionDefinition {
  el: string;
  regionClass?: typeof Region;
  replaceElement?: boolean;
}