Giter Site home page Giter Site logo

tomastrajan / ngx-model Goto Github PK

View Code? Open in Web Editor NEW
132.0 12.0 11.0 136 KB

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

Home Page: https://tomastrajan.github.io/angular-model-pattern-example

License: MIT License

TypeScript 100.00%
angular rxjs-observable data-flow model state-management rxjs5 ngx-model

ngx-model's Introduction

⚠️ IMPORTANT

THIS REPO / PACKAGE HAS BEEN DEPRECATED

Please use new @angular-extensions/modelpackage / repo which is a combination of both the model library and related schematics which renders this package uselsess. On the other hand, feel free to keep using ngx-model if it suits your needs, it will not be deleted, but there will be no further development. Please, have a look into migration section in the new documentation.

The Angular Model - ngx-model

by @tomastrajan

npm npm npm Build Status Twitter Follow

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

Documentation

ngx-model dataflow diagram

Getting started

  1. Install ngx-model

    npm install --save ngx-model
    

    or

    yarn add ngx-model
    
  2. Import and use NgxModelModule in you AppModule (or CoreModule)

    import { NgxModelModule } from 'ngx-model';
        
    @NgModule({
      imports: [
        NgxModelModule
      ]
    })
    export class CoreModule {}
  3. Import and use Model and ModelFactory in your own services.

    import { Injectable } from '@angular/core';
    import { Observable } from 'rxjs';
    import { ModelFactory, Model } from 'ngx-model';
        
    @Injectable()
    export class TodosService {
            
      private model: Model<Todo[]>;
      
      todos$: Observable<Todo[]>;
            
      constructor(private modelFactory: ModelFactory<Todo[]>) {
        this.model = this.modelFactory.create([]); // create model and pass initial data
        this.todos$ = this.model.data$; // expose model data as named public property
      }
        
      toggleTodo(id: string) {
        // retrieve raw model data
        const todos = this.model.get();
            
        // mutate model data
        todos.forEach(t => {
          if (t.id === id) {
            t.done = !t.done;
          }
        });
            
        // set new model data (after mutation)
        this.model.set(todos);
      }
        
    }
  4. Use service in your component. Import and inject service into components constructor. Subscribe to services data in template todosService.todos$ | async or explicitly this.todosService.todos$.subscribe(todos => { /* ... */ })

    import { Component, OnInit, OnDestroy } from '@angular/core';
    import { Subject } from 'rxjs';
    
    import { TodosService, Todo } from './todos.service';
    
    @Component({
      selector: 'ngx-model-todos',
      templateUrl: `
        /* ... */
        <h1>Todos ({{count}})</h1>
        <ul>
          <!-- template subscription to todos using async pipe -->
          <li *ngFor="let todo of todosService.todos$ | async" (click)="onTodoClick(todo)">
            {{todo.name}}
          </li>
        </ul>
      `,
    })
    export class TodosComponent implements OnInit, OnDestroy {
    
      private unsubscribe$: Subject<void> = new Subject<void>();
      
      count: number;
     
      constructor(public todosService: TodosService) {}
    
      ngOnInit() {
        // explicit subscription to todos to get count
        this.todosService.todos
          .pipe(
            takeUntil(this.unsubscribe$) // declarative unsubscription
          )
          .subscribe(todos => this.count = todos.length);
      }
      
      ngOnDestroy(): void {
        // for declarative unsubscription
        this.unsubscribe$.next();
        this.unsubscribe$.complete();
      }
    
      onTodoClick(todo: Todo) {
        this.todosService.toggleTodo(todo.id);
      }
    
    }

Available Model Factories

Models are created using model factory as shown in above example this.model = this.modelFactory.create([]);. 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)

Relationship to Angular Model Pattern

This is a library version of Angular Model Pattern. All the original examples and documentation are still valid. The only difference is that you can install ngx-model from npm instead of having to copy model pattern implementation to your project manually.

Check out the Blog Post and Advanced Usage Patterns for more how-tos and examples.

Getting started with Schematics

  1. make sure you're using this in project generated with Angular CLI.
  2. install dependency with npm i -D @angular-extensions/schematics
  3. generate model services with ng g @angular-extensions/schematics:model --name path/my-model
  4. or with ng g @angular-extensions/schematics:model --name path/my-model-collection --items form model of collection of items
  5. add your own model service methods and tests

Generating model using schematics

ngx-model's People

Contributors

splincode avatar tomastrajan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ngx-model's Issues

npm package contains files with last-modified-date 0

This may not be a big deal for most users of the module, but in our case it is producing errors because for some reason our web-server does not want to serve the files because the last-modified date is 0 (1 Jan 1970) which makes no sense, I'd expect it to be the day when the npm release was created.

Can you please take a look at this?

~/my-project (master) $ ls -lh node_modules/ngx-model
total 888
-rw-r--r--  1 my-user  1100429709   1.0K Jan  1  1970 LICENSE
-rw-r--r--  1 my-user  1100429709   6.5K Jan  1  1970 README.md
drwxr-xr-x  6 jmy-user  1100429709   192B Apr 17 08:55 bundles
-rw-r--r--  1 my-user  1100429709    72B Jan  1  1970 index.d.ts
drwxr-xr-x  3 my-user  1100429709    96B Apr 17 08:55 lib
-rw-r--r--  1 my-user  1100429709    77B Jan  1  1970 ngx-model.d.ts
-rw-r--r--  1 my-user  1100429709    82K Jan  1  1970 ngx-model.es5.js
-rw-r--r--  1 my-user  1100429709   127K Jan  1  1970 ngx-model.es5.js.map
-rw-r--r--  1 my-user  1100429709    79K Jan  1  1970 ngx-model.js
-rw-r--r--  1 my-user  1100429709   121K Jan  1  1970 ngx-model.js.map
-rw-r--r--  1 my-user  1100429709   1.4K Jan  1  1970 ngx-model.metadata.json
-rw-r--r--  1 my-user  1100429709   1.7K Jan  1  1970 package.json

StaticInjectorError(Platform: core)[PlanService -> ModelFactory]

I've created a simple PlanService which is only declared in a component but when the component renders (even though it doesn't use the service, yet), I get this:

Error: StaticInjectorError(AppModule)[PlanService -> ModelFactory]: 
  StaticInjectorError(Platform: core)[PlanService -> ModelFactory]: 
    NullInjectorError: No provider for ModelFactory!
    at NullInjector.push../node_modules/@angular/core/fesm5/core.js.NullInjector.get (core.js:1062)
    at resolveToken (core.js:1300)
    at tryResolveToken (core.js:1244)
    at StaticInjector.push../node_modules/@angular/core/fesm5/core.js.StaticInjector.get (core.js:1141)
    at resolveToken (core.js:1300)
    at tryResolveToken (core.js:1244)
    at StaticInjector.push../node_modules/@angular/core/fesm5/core.js.StaticInjector.get (core.js:1141)
    at resolveNgModuleDep (core.js:8369)
    at _createClass (core.js:8414)
    at _createProviderInstance (core.js:8386)
    at NullInjector.push../node_modules/@angular/core/fesm5/core.js.NullInjector.get (core.js:1062)
    at resolveToken (core.js:1300)
    at tryResolveToken (core.js:1244)
    at StaticInjector.push../node_modules/@angular/core/fesm5/core.js.StaticInjector.get (core.js:1141)
    at resolveToken (core.js:1300)
    at tryResolveToken (core.js:1244)
    at StaticInjector.push../node_modules/@angular/core/fesm5/core.js.StaticInjector.get (core.js:1141)
    at resolveNgModuleDep (core.js:8369)
    at _createClass (core.js:8414)
    at _createProviderInstance (core.js:8386)
    at resolvePromise (zone.js:814)
    at resolvePromise (zone.js:771)
    at zone.js:873
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:421)
    at Object.onInvokeTask (core.js:3811)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:420)
    at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:188)
    at drainMicroTaskQueue (zone.js:595)
defaultErrorLogger @ core.js:1673
push../node_modules/@angular/core/fesm5/core.js.ErrorHandler.handleError @ core.js:1719
next @ core.js:4311
schedulerFn @ core.js:3551
push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.__tryOrUnsub @ Subscriber.js:196
push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.next @ Subscriber.js:134
push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber._next @ Subscriber.js:77
push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next @ Subscriber.js:54
push../node_modules/rxjs/_esm5/internal/Subject.js.Subject.next @ Subject.js:47
push../node_modules/@angular/core/fesm5/core.js.EventEmitter.emit @ core.js:3535
(anonymous) @ core.js:3842
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:388
push../node_modules/zone.js/dist/zone.js.Zone.run @ zone.js:138
push../node_modules/@angular/core/fesm5/core.js.NgZone.runOutsideAngular @ core.js:3779
onHandleError @ core.js:3842
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.handleError @ zone.js:392
push../node_modules/zone.js/dist/zone.js.Zone.runGuarded @ zone.js:154
_loop_1 @ zone.js:677
api.microtaskDrainDone @ zone.js:686
drainMicroTaskQueue @ zone.js:602
Promise.then (async)
scheduleMicroTask @ zone.js:578
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:410
push../node_modules/zone.js/dist/zone.js.Zone.scheduleTask @ zone.js:232
push../node_modules/zone.js/dist/zone.js.Zone.scheduleMicroTask @ zone.js:252
scheduleResolveOrReject @ zone.js:862
ZoneAwarePromise.then @ zone.js:962
push../node_modules/@angular/core/fesm5/core.js.PlatformRef.bootstrapModule @ core.js:4345
./src/main.ts @ main.ts:13
__webpack_require__ @ bootstrap:78
0 @ main.ts:14
__webpack_require__ @ bootstrap:78
checkDeferredModules @ bootstrap:45
webpackJsonpCallback @ bootstrap:32
(anonymous) @ main.js:1

to get it to work, I have to add:

@NgModule({
...
  providers: [
    ModelFactory,
    PlanService
  ],
...
})
export class AppModule { }

TS90010 error: Type 'Observable<foo>' is not assignable to type 'Observable<foo>'. Two different types with this name exists, but they are unrelated.

Hi

First of all, thanks for an excellent write up of Angular Model Pattern. I love it!

I just switched to using the npm module instead of just having a single file in my code, and now I'm getting this typescript error (followed the tutorial to the point). Anyone know's whats up?

private userModel: Model<Person>;
  public user$: Observable<Person>;


  constructor(private modelFactory: ModelFactory<Person>) {
    this.userModel = modelFactory.create(
      {
        id: null,
        createdAt: null,
        firstName: null,
        fullName: null,
        lastName: null,
        updatedAt: null
      }
    );
    this.user$ = this.userModel.data$;
  }

image

Build fails when using angular-cli 1.5.0

If I upgrade my angular-cli version from 1.4.3 to 1.5.0 during ng serve I get the following error:

ERROR in ./node_modules/ngx-model/index.ts
Module build failed: Error: /Users/ub/Playground/mobility/consumer/web/manager/node_modules/ngx-model/index.ts is not part of the compilation output. Please check the other error messages for details.
    at AngularCompilerPlugin.getCompiledFile (/Users/ub/Playground/mobility/consumer/web/manager/node_modules/@ngtools/webpack/src/angular_compiler_plugin.js:629:23)
    at plugin.done.then (/Users/ub/Playground/mobility/consumer/web/manager/node_modules/@ngtools/webpack/src/loader.js:467:39)
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:188:7)
 @ ./src/app/core/core.module.ts 17:0-43
 @ ./src/app/app.module.ts
 @ ./src/main.ts
 @ multi webpack-dev-server/client?http://0.0.0.0:0 ./src/main.ts

Looks like the comment over here is related. It reads

You have TS files in your node_modules. This really goes against how libraries should be packaged: libraries should never ship their source .ts files.

The reason for this rule is that the TypeScript version your app isn't necessarily the same as the TS version your library uses. Different versions of TS can produce different output, and give different errors for the same input. They don't even support the same language features. So packaging libraries with TS sources will always break someone's project.

In case anyone else is affected, a temporary workaround is to modify tsconfig.app.json:

  "include": [
    "../src/**/*",
    "../node_modules/ngx-model/**/*.ts"
  ],
  "exclude": [
    "../node_modules/ngx-model/**/*.test.ts"
  ]

A similar change is needed to be done to tsconfig.spec.json

When 'noImplicitAny' enabled ts doesn't compile

Hello,

I have an application in which I use ngx-model. My application has the following in tsconfig.json:

"strict": true,
"skipLibCheck": true

strict enables noImplicitAny. When I try to use ngx-model in this setup, I get the following error:

ERROR in /node_modules/ngx-model/lib/model.ts (39,41): Parameter 'clone' implicitly has an 'any' type.

While trying to find solution I saw this, which explains why I get this error.

Is it possible to publish d.ts files?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.