| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
by @tomastrajan
Simple state management with minimalistic API, one way data flow, multiple model support and immutable data exposed as RxJS Observable.
Install @angular-extensions/model library
ng add @angular-extensions/model
Generate model service
ng g @angular-extensions/model:model examples/todo --items
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!' });
}
}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.
The model has a small API that as shown in in the illustration above.
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$.
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:
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.
ng g @angular-extensions/model:model example/todo
It is also possible to use @angular-extensions/model in Angular project which do not use Angular CLI.
Install @angular-extensions/model library
npm i -S @angular-extensions/model
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;
}Use new model service in some of your components as described in point 3 and above in Getting started in Angular CLI projects section
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 should be rather simple, please follow these steps:
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
Please, feel free to submit and issue or feature request using project GitHub repository.
| Back | FazBrowse Home | New Git URL |