3

I have angular app v6 and I'm using latest version of mobx and mobx-angular (You can see in dependency). I'm coming from ngrx, ngxs background so it is tough to understand mobx flow because it more or less angular-service approach with something extra (with performance also).

I have few question asked in stackblitz example. I hope somebody to give guidance on them.

DEMO APP

store.ts

@Injectable()
export class Store {

    @observable counter: number = 0;

    constructor() { }

    @action count() {
        this.counter ++;
    }
}

app.component.ts

export class AppComponent  {

  _counter:number=0;

  constructor(private store:Store){}

  ngOnInit(){
    // how to subscribe to updated value of counter from service and assign it to this._counter ????

    this._counter = this.store.counter;
  }
}

app.component.html

    <div *mobxAutorun>Counter : {{store.counter}}<br /></div>

______________________________________________

<div>Counter : {{store.counter}}<br /></div>

______________________________________________


<div>how to subscribe to updated value form 'counter' variable to '_counter' local variable????</div><br />

<div> {{_counter}} </div>

<button (click)="store.count()">Count</button>
micronyks
  • 54,797
  • 15
  • 112
  • 146

1 Answers1

3

You can set an RxJs subscription in ngOnInit.

ngOnInit() {
  this.store.toRx(this.store, 'counter')
    .subscribe(val => this._counter = val)
}

toRx is a convenience function which can be added to the store.
It uses the Mobx observe() function which just activates a callback each time the specified item changes.

import { Injectable } from '@angular/core';
import { action, observable, observe } from 'mobx';
import { Observable } from 'rxjs';

@Injectable()
export class Store {
  ...
  toRx(obj, prop) {
    return Observable.create(observer =>
      observe(obj, prop, (change) => observer.next(change.newValue), true)
    );
  }
}

If you have deeply nested property you want to subscribe to, e.g

@Injectable()
export class Store {
  ...    
  @observable counterWrapper = { counter: 0 };

just change the first parameter of toRx

this.store.toRx(this.store.counterWrapper, 'counter')
  .subscribe(val => this._counter = val)
Richard Matsen
  • 20,671
  • 3
  • 43
  • 77
  • its a great solution. Sorry for taking time to approve it ! – micronyks Oct 04 '18 at 05:58
  • The problem with second approach is : Even if I change counter variable, it will trigger subscription for counterWrapper object as you are using `'state' (static name)` in `select` function. Is there any way to make it dynamic? – micronyks Oct 04 '18 at 06:41
  • OR is there any way that we can stop the subscription for counterWrapper when change is made to only counter variable? – micronyks Oct 04 '18 at 06:52
  • I took the code for the `select` method above from the ngrx source [here](https://github.com/ngrx/platform/blob/master/modules/store/src/store.ts), lines 196-199. I did think at the time that it didn't look very efficient. Will take another look and see if it can be improved. – Richard Matsen Oct 04 '18 at 08:21
  • Yes I feel like it can be improved a lot. I'm also looking into it. – micronyks Oct 04 '18 at 08:39
  • The problem you mentioned of `counterWrapper` subscription firing when only `counter` is updated could be solved with a `distinctUntilChanged` operator after the `map` operator. – Richard Matsen Oct 05 '18 at 00:36
  • However, it turns out mobx does not observe deep properties, at least in the context I gave. This means the `select` version does not work when `counterWrapper.counter` is updated. I have therefore removed the `select()` version as it is misleading. My bad for not testing all paths. – Richard Matsen Oct 05 '18 at 00:39
  • In any case, the `toRx` method works fine for simple and nested properties and the difference from the component pov is just syntax. – Richard Matsen Oct 05 '18 at 00:40
  • But can you avoid writting string in toRx function???? Can you make it little dynamic or more generic??? – micronyks Oct 05 '18 at 01:23
  • See mobx's `observe` [method](https://mobx.js.org/refguide/observe.html#observe), the second param is a string with the property name. You can drop this param, but then if the first param (object) has more than one property you must pass the whole change object to the subscription and check if it is the property you are interested in. Much more cumbersome, and you are still checking strings anyway. I think this is a javascript limitation, not a mobx limitation. – Richard Matsen Oct 05 '18 at 01:42
  • Okay I see !!! But I must thank you for nice efforts, help and guidance. – micronyks Oct 05 '18 at 04:25