Singleton service system for managing application-wide state and functionality with dependency injection.
Base class for creating singleton services that persist across the application lifecycle.
/**
* Base class for creating singleton services that persist across the application lifecycle
*/
class Service {
/**
* Create new service class with additional properties
* @param properties - Service properties and methods
* @returns New Service subclass
*/
static extend(properties?: object): typeof Service;
/**
* Initialize service when first accessed
*/
init(): void;
/**
* Destroy service and clean up resources
*/
destroy(): void;
/** Whether service is being destroyed */
isDestroying: boolean;
/** Whether service has been destroyed */
isDestroyed: boolean;
}Decorators and functions for injecting services into objects.
/**
* Modern decorator for injecting services
* @param serviceName - Name of service to inject (optional, defaults to property name)
* @returns Property decorator
*/
function service(serviceName?: string): PropertyDecorator;
/**
* Legacy service injection object with named injection methods
*/
interface ServiceInjection {
/**
* Inject service by name
* @param serviceName - Name of service to inject (optional)
* @returns Injected service property
*/
(serviceName?: string): any;
}
/** Legacy service injection helper */
declare const inject: {
service: ServiceInjection;
};Usage Examples:
import Service, { service } from "@ember/service";
import { tracked } from "@glimmer/tracking";
import { action } from "@ember/object";
// Create a service
export default class SessionService extends Service {
@tracked currentUser = null;
@tracked isAuthenticated = false;
@action
async login(username, password) {
try {
const response = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password })
});
if (response.ok) {
this.currentUser = await response.json();
this.isAuthenticated = true;
return true;
}
return false;
} catch (error) {
console.error('Login failed:', error);
return false;
}
}
@action
logout() {
this.currentUser = null;
this.isAuthenticated = false;
}
}
// Use service in component
import Component from "@glimmer/component";
import { service } from "@ember/service";
import { action } from "@ember/object";
export default class LoginComponent extends Component {
@service session;
@service router;
@action
async handleLogin(event) {
event.preventDefault();
const formData = new FormData(event.target);
const username = formData.get('username');
const password = formData.get('password');
const success = await this.session.login(username, password);
if (success) {
this.router.transitionTo('dashboard');
}
}
get isLoggedIn() {
return this.session.isAuthenticated;
}
}
// Legacy injection syntax
import Component from "@ember/component";
import { inject as service } from "@ember/service";
export default Component.extend({
session: service(),
notifications: service('notification-manager'),
actions: {
logout() {
this.session.logout();
this.notifications.success('Logged out successfully');
}
}
});Core services provided by Ember.js framework.
/**
* Router service for programmatic navigation
*/
class RouterService extends Service {
transitionTo(routeName: string, ...models: any[]): Transition;
replaceWith(routeName: string, ...models: any[]): Transition;
urlFor(routeName: string, ...models: any[]): string;
isActive(routeName: string, ...models: any[]): boolean;
currentURL: string;
currentRouteName: string;
}
/**
* Store service for data management (when using Ember Data)
*/
class StoreService extends Service {
findRecord(modelName: string, id: string | number): Promise<any>;
findAll(modelName: string): Promise<any[]>;
createRecord(modelName: string, properties?: object): any;
deleteRecord(record: any): void;
}Functions for registering custom services with the dependency injection container.
/**
* Register a service with the application container
* @param application - Application instance
* @param name - Service name
* @param serviceClass - Service class to register
*/
function registerService(application: Application, name: string, serviceClass: typeof Service): void;
/**
* Lookup a service instance from the container
* @param owner - Container owner
* @param serviceName - Name of service to lookup
* @returns Service instance
*/
function lookupService(owner: Owner, serviceName: string): Service;Usage Examples:
// Register service during application initialization
import Application from "@ember/application";
import ApiService from "./services/api";
const App = Application.create();
// Register service
App.register('service:api', ApiService);
// Or register in an initializer
export function initialize(application) {
application.register('service:analytics', AnalyticsService);
// Inject into all routes
application.inject('route', 'analytics', 'service:analytics');
// Inject into all components
application.inject('component', 'analytics', 'service:analytics');
}
export default {
name: 'analytics',
initialize
};Service lifecycle management and cleanup.
/**
* Service lifecycle hooks
*/
interface ServiceLifecycle {
/**
* Called when service is first accessed
*/
init(): void;
/**
* Called when application is being destroyed
*/
willDestroy(): void;
/**
* Called after service is destroyed
*/
destroy(): void;
}Usage Examples:
import Service from "@ember/service";
import { tracked } from "@glimmer/tracking";
export default class WebSocketService extends Service {
@tracked isConnected = false;
socket = null;
init() {
super.init();
this.connect();
}
connect() {
this.socket = new WebSocket('ws://localhost:8080');
this.socket.onopen = () => {
this.isConnected = true;
console.log('WebSocket connected');
};
this.socket.onclose = () => {
this.isConnected = false;
console.log('WebSocket disconnected');
};
}
send(message) {
if (this.isConnected) {
this.socket.send(JSON.stringify(message));
}
}
willDestroy() {
super.willDestroy();
if (this.socket) {
this.socket.close();
}
}
}interface ServiceDefinition {
/** Service class constructor */
new (): Service;
}
interface InjectedService {
/** Injected service instance */
[key: string]: Service;
}
interface ServiceRegistry {
/** Register service type */
[serviceName: string]: ServiceDefinition;
}