@angular-extensions/model

中文文档
12.0.0发布于 2021/09/21MITTypeScriptESM + CJS近 30 天下载 5165

Angular Model - Simple state management with minimalistic API, one way data flow, multiple model support and immutable data exposed as RxJS Observable.

原始使用文档
文档目录7 节
  1. Documentation
  2. Getting started in Angular CLI projects
  3. Model API
  4. Model Schematics API
  5. Getting started without Angular CLI
  6. Relationship to older Angular Model Pattern and ngx-model l…
  7. Contributing

Angular Model - @angular-extensions/model

by @tomastrajan

npm npm npm Build Status codecov Conventional Commits Twitter Follow

Simple state management with minimalistic API, one way data flow, multiple model support and immutable data exposed as RxJS Observable.

Documentation

@angular-extensions/model dataflow diagram

Getting started in Angular CLI projects

  1. Install @angular-extensions/model library

    ng add @angular-extensions/model
    
  2. Generate model service

    ng g @angular-extensions/model:model examples/todo --items
    
  3. Use model service in your component. Let's generate new todo component

    ng g component examples/todo --inline-template
    

    And then adjust component implementation as in the example below

    import { Component } from '@angular/core';
    import { TodoService } from './todo.service';
    
    @Component({
      selector: 'app-todo',
      template: `
        <!-- template subscription to todos using async pipe -->
        <ng-container *ngIf="todoService.todos$ | async as todos">
          <h1>Todos ({{ todos.length }})</h1>
          <ul>
            <li *ngFor="let todo of todos">
              {{ todo.prop }}
            </li>
          </ul>
          <button (click)="addTodo()">Add todo</button>
        </ng-container>
      `,
      styleUrls: ['./todo.component.css']
    })
    export class TodoComponent {
      constructor(public todoService: TodoService) {}
    
      addTodo() {
        this.todoService.addTodo({ prop: 'New todo!' });
      }
    }
    
  4. Use our new <app-todo></app-todo> component in the template of the app.component.html

Please mind that you might be using different application prefix than app- so adjust accordingly.

Model API

The model has a small API that as shown in in the illustration above.

  • get(): T - returns current model value
  • set(data: T): void - sets new model value
  • data$: Observable<T> - observable of the model data, every call set(newData) will push new model state to to this observable (the data is immutable by default but this can be changed using one of the other provided factory functions as described below)

Check out generated todo.service.ts to see an example of how the model should be used. In general, the service will implement methods in which it will retrieve current model state, mutate it and set new state back to the model. Model will then take care of pushing immutable copies of the new state to all components which are subscribed using data$.

Available Model Factories

Models are created using model factory as shown in example todo.service.ts, check line this.model = this.modelFactory.create(initialData);. Multiple model factories are provided out of the box to support different use cases:

  • create(initialData: T): Model<T> - create basic model which is immutable by default (JSON cloning)
  • createMutable(initialData: T): Model<T> - create model with no immutability guarantees (you have to make sure that model consumers don't mutate and corrupt model state) but much more performance because whole cloning step is skipped
  • createMutableWithSharedSubscription(initialData: T): Model<T> - gain even more performance by skipping both immutability and sharing subscription between all consumers (eg situation in which many components are subscribed to single model)
  • createWithCustomClone(initialData: T, clone: (data: T) => T) - create immutable model by passing your custom clone function (JSON cloning doesn't support properties containing function or regex so custom cloning functionality might be needed)
  • createWithConfig(config) - create model by passing in config object with values of all configuration properties (initialData: T, immutable: boolean, sharedSubscription: boolean, clone: (data: T) => T)

Model Schematics API

Model services are generated using Angular CLI. It is a 3rd party schematics so we have to specify it when running ng g command like this ng g @angular-extensions/model:<schematics-name> <schematics parameters>. The schematics currently contains only one schematic called model.

Basic usage

ng g @angular-extensions/model:model example/todo

Supported options

  • --items - creates service for collection of items (it will expose todos$: Observable<Todo[]>; instead of todo$: Observable<Todo>)
  • --flat - generates service file directly in theexamples folder without creating folder with the name todos (default: false)
  • --spec - generate service test file (default: true)
  • --module - will decide how to register service into Angular dependency injection context (service will use providedIn: 'root' when no module was provided, module can be provided as a path to module relative to the location of generated service, eg ng g @angular-extensions/model:model examples/auth --module ../app.module.ts)
  • --project - project in which to generate the service (for multi project Angular CLI workspaces, will generate service in the first project by default, when no project was provided)

@angular-extensions/schematics

Getting started without Angular CLI

It is also possible to use @angular-extensions/model in Angular project which do not use Angular CLI.

  1. Install @angular-extensions/model library

    npm i -S @angular-extensions/model
    
  2. Create new model service in src/app/examples/todo/todo.service.ts

    import { Injectable } from '@angular/core';
    import { Model, ModelFactory } from '@angular-extensions/model';
    import { Observable } from 'rxjs';
    
    const initialData: Todo[] = [];
    
    @Injectable({
      providedIn: 'root'
    })
    export class TodoService {
      private model: Model<Todo[]>;
    
      todos$: Observable<Todo[]>;
    
      constructor(private modelFactory: ModelFactory<Todo[]>) {
        this.model = this.modelFactory.create(initialData);
        this.todos$ = this.model.data$;
      }
    
      addTodo(todo: Todo) {
        const todos = this.model.get();
    
        todos.push(todo);
    
        this.model.set(todos);
      }
    }
    
    export interface Todo {
      prop: string;
    }
    
  3. Use new model service in some of your components as described in point 3 and above in Getting started in Angular CLI projects section

Relationship to older Angular Model Pattern and ngx-model library

This is a new enhanced version of older library called ngx-model which was in turn implementation of Angular Model Pattern. All the original examples and documentation are still valid. The only difference is that you can add @angular-extensions/model with ng add instead of installing ngx-model or having to copy model pattern implementation to your project manually.

One of the changes compared to ngx-model is that the @angular-extensions/model uses new providedIn: 'root' syntax (since Angular 6) so that we don't need to import NgxModelModule or anything similar to register ModelFactory into Angular dependency injection (DI) context. All we have to do is to import ModelFactory in the constructor of at least one service in our application like this constructor(private modelFactory: ModelFactory<SomeType[]>) {} and we're good to go. This new feature is called tree-shakeable providers:

There is now a new, recommended, way to register a provider, directly inside the @Injectable() decorator, using the new providedIn attribute. It accepts 'root' as a value or any module of your application. When you use 'root', your injectable will be registered as a singleton in the application, and you don’t need to add it to the providers of the root module. Similarly, if you use providedIn: UsersModule, the injectable is registered as a provider of the UsersModule without adding it to the providers of the module (source)

Migration from ngx-model

Migration should be rather simple, please follow these steps:

  1. remove dependency to ngx-model
  2. install npm i -S @angular-extensions/model
  3. remove NgxModelModule from imports of your @NgModule in App or Core module based on where you added it
  4. search and replace imports from ngx-model and replace them with @angular-extensions/model
  5. this should be it! The API didn't change so this should be all that it takes to migrate to the new package
  6. (optional) refactor your existing model services to use @Injectable({ providedIn: 'root' }) (or other module instead of root) instead of @Injectable() and remove them from @NgModule({ providers: [MyModelService] }) of your modules

The 6th step depends on your preferences, it is still possible to use new @angular-extensions/model with classic providers, just use --module <relative-path-to-module> flag when generating new model services using schematics

Contributing

Please, feel free to submit and issue or feature request using project GitHub repository.

版本与发布记录

@angular-extensions/model 共发布 26 个版本,首次发布于 2018/09/28;过去 12 个月发布了 0 个版本。

版本发布日期距今
12.0.0latest2021/09/215 年前
11.0.02021/09/205 年前
10.0.12020/07/306 年前
10.0.02020/07/306 年前
9.0.02020/07/306 年前
8.1.02019/07/197 年前

关于 @angular-extensions/model 的常见问题

@angular-extensions/model 是什么?

Angular Model - Simple state management with minimalistic API, one way data flow, multiple model support and immutable data exposed as RxJS Observable.

如何安装 @angular-extensions/model?

在项目目录运行 npm install @angular-extensions/model,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@angular/core(^12.0.0)、@angular/cli(^12.0.0)、rxjs(^6.6.0)、typescript(~4.3.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@angular-extensions/model 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@angular-extensions/model 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@angular-extensions/model 可以商用吗?

@angular-extensions/model 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@angular-extensions/model 的下载量有多少?

根据 npm 官方下载统计,@angular-extensions/model 在 2026/10/06 – 2026/11/04 这 30 天内被下载 5,165 次,日均约 172 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@angular-extensions/model 还在维护吗?

最新版本 12.0.0 发布于 2021/09/21(5 年前);至今共发布 26 个版本,其中过去 12 个月发布了 0 个;首次发布于 2018/09/28。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。