mobxjs / mobx-angular

The MobX connector for Angular.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Importing observable from mobx-angular doesn't allow shallow or other attributes

some1awesome opened this issue · comments

If you import observable from mobx-angular instead of mobx you lose some of the available properties. For my specific use case I want to make a shallow observable.

When using mobx i can do the following:

@observable.shallow rows = [];

But when I try to import it through mobx-angular (which I need to do because i am doing this inside a component or it will fail in aot builds) then it says: Property 'shallow' does not exist on type '(...args: any[]) => any'.

I made a stack blitz that has the error in it: https://stackblitz.com/edit/angular-2xjhvq?file=app/app.service.ts. I think something is just wrong with the typings.

@some1awesome If you have a look into the code-examples, they also use the definitions from mobx and not mobx-angular
import { observable, computed, action, autorun, toJS } from 'mobx';
I'm still new to mobx and built a app with using only mobx. Just for the directives I am importing and using the mobx-angular things. Why it's not working in your case when you use mobx instead of mobx-angular? I did not understand the issue you get.

@some1awesome If you have a look into the code-examples, they also use the definitions from mobx and not mobx-angular
import { observable, computed, action, autorun, toJS } from 'mobx';
I'm still new to mobx and built a app with using only mobx. Just for the directives I am importing and using the mobx-angular things. Why it's not working in your case when you use mobx instead of mobx-angular? I did not understand the issue you get.

I have to import observable from 'mobx-angular' because i am using it inside a component. Inside a component importing directly from 'mobx' will fail when running an aot build. The solution I found online for that problem was to import from 'mobx-angular' instead, but when I do that I don't get access to some of the features of observable like shallow.

@some1awesome This is weird. I deploy my whole App with AOT too and don‘t have issues like this. So you mean you are using the @observable in a component, which is not part of a @Injectable and causes the issue? I can try it out if it applies to your issue. I am using for example the autorun inside a component and imported it from mobx without any problem.

@some1awesome
I could reproduce the issue you have. With the annotation it's not working. But the question is, what you try to reach? Do you like to have a reaction inside your component, when something changes? this can be made without the @observable annotation. Have a look to the documentation here:
https://mobx.js.org/refguide/reaction.html
So instead using the annotation, you create a variable with type observable (but the mobx one, not rxjs one) and then you can react to it with a reaction or an autorun. I just tested it out and it worked. But I don't know your use case.

the property in the component
observableTest = observable({ test: 'juppi' });

a function called by a button click
testit() { this.observableTest.test = Math.random().toString(); }

the reaction with an autorun
autorun( () => console.log(this.observableTest.test) );

So after every click the autorun was kicked and printed out the new value. In your case it would be
observableTest = observable.shallow(xxx);

commented

@some1awesome, yes, there are restrictions in the components because of AOT https://github.com/mobxjs/mobx-angular#aot
In the services is not this restriction and in our project, we made a workaround through the local injectable service-state.
for example

import { observable, action } from "mobx";
class AppState {
  @observable.shallow items = [];
  @action add() {
    this.items.push('value');
  }
}
----
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ],
  providers: [AppState]
})
export class AppComponent  {
  constructor(public state: AppState){
  }
}

Need to assign all other properties from MobX observable/action/computed to the proxied ones exported from here:

export function action(...args) {

Anybody wants to make a PR?

commented

@adamkleingit, it will be very useful functionality and I want to make a PR, but don't know how to realize it. Can you give some sample code?

I would try to do something like this:

Object.assign(action, mobxAction)
Object.assign(computed, mobxComputed)
etc.

But it might not work because of binding, so need to check.

Would be very much appreciated

@mweststrate do you know of the top of your head will that work (for observable/action/computed)?

import {action as mobxAction} from 'mobx';

export function action(...args) {
  return mobxAction(...args);
}
Object.assign(action, mobxAction);

Does any of the modifiers of observable/action/computed use 'this' inside? Or are they already bound?

Thanks

I pushed to master, but still not published.
@some1awesome can you use the version from master and try it?

commented

@adamkleingit, if I just use an Object.assign typescript compilator returns error to decorators @observable.shallow, ...

It is correct to add decorator interfaces from mobx?

function observableInternal(...args) {
  return (mobxObservable as any)(...args);
}

export const observable: IObservableFactory & IObservableFactories & {
  enhancer: IEnhancer<any>;
} = Object.assign(observableInternal, mobxObservable) as any;

@ildarnm I ended up using typeof.
Published 3.1.0