Code Monkey home page Code Monkey logo

mobx-angular's People

Contributors

adamkleingit avatar bb avatar chuckv01 avatar corentinleberre avatar davidpodhola avatar dependabot[bot] avatar evasive avatar famoser avatar kubk avatar lehoczky avatar lexzhukov avatar mgechev avatar mohsen1 avatar omergronich avatar returnlytom avatar sagarchikane avatar shairez avatar simonmckinsey avatar stepanzarubin avatar theoklitosbam7 avatar westonganger 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mobx-angular's Issues

Compatibility with pipes

Hi,

I was trying to pass an array to angular's standard slice pipe.
That array is a part of a data store service which is injected into that particular component, and is defined with @observable decorator.

So when I try to run this array through the slice pipe, (passing the array, a start index and an end index) I get this:

Invalid argument '[object Object],[object Object],[object Object]' for pipe 'SlicePipe'

The pipe works properly if I remove the @observable decoration.
Please check.


Update:

Strange. As part of code changes which I did later on, I'm now getting the same error even when the @observable decorator is not present.

Do you have an example of how to properly use arrays marked with @observable in conjunction with pipes?

Thanks,
Gideon

ERROR in Ng2MobxModule is not an NgModule

After upgrading all the packages in the TodoMVC example I get the error ERROR in Ng2MobxModule is not an NgModule when starting the application. As far as I can tell the most common solution to this issue is to downgrade from TypeScript 2.1 to 2.0, but that doesn't fix this issue.

Here are the versions of the packages that I am using:

"dependencies": {
  "@angular/common": "2.4.4",
  "@angular/compiler": "2.4.4",
  "@angular/core": "2.4.4",
  "@angular/forms": "2.4.4",
  "@angular/http": "2.4.4",
  "@angular/platform-browser": "2.4.4",
  "@angular/platform-browser-dynamic": "2.4.4",
  "@angular/router": "3.4.4",
  "core-js": "2.4.1",
  "mobx": "3.0.2",
  "ng2-mobx": "1.2.2",
  "rxjs": "5.0.3",
  "todomvc-app-css": "2.0.6",
  "todomvc-common": "1.0.3",
  "ts-helpers": "1.1.2",
  "zone.js": "0.7.6"
},
"devDependencies": {
  "@angular/compiler-cli": "2.4.4",
  "@types/jasmine": "2.5.41",
  "@types/node": "7.0.4",
  "angular-cli": "1.0.0-beta.26",
  "codelyzer": "2.0.0-beta.4",
  "jasmine-core": "2.5.2",
  "jasmine-spec-reporter": "3.2.0",
  "karma": "1.4.0",
  "karma-chrome-launcher": "2.0.0",
  "karma-cli": "1.0.1",
  "karma-jasmine": "1.1.0",
  "karma-remap-istanbul": "0.4.0",
  "protractor": "5.0.0",
  "ts-node": "2.0.0",
  "tslint": "4.3.1",
  "typescript": "2.0.10",
  "webdriver-manager": "11.1.1"
}

console.log('detach') in NPM package

I have angular-tree-component which has these dependencies:

+-- [email protected]
| +-- [email protected]
| `-- [email protected]

When I expand a node in my tree view, I see "detach" logs from the console.

Looking where it comes from, it points me to node_modules/mobx-angular/dist/directives/mobx-autorun.directive.js.

The code inside:

MobxAutorunDirective.prototype.autoDetect = function (view) {
        if (!this.mobxAutorun || !this.mobxAutorun.dontDetach) {
            console.log('detach');
            view.detach();
        }
        var autorunName = view._view.component
            ? view._view.component.constructor.name + ".detectChanges()" // angular 4+
            : view._view.parentView.context.constructor.name + ".detectChanges()"; // angular 2
        this.dispose = autorun(autorunName, function () { return view['detectChanges'](); });
    };

There's an extra block that logs and call to view.detach that isn't in the actual code on github

Not sure where it comes from. Maybe the repository wasn't clean when it got published to NPM?

Thanks!

Host Directive or base Component

It would be super nice to get rid of the wrapping component (which includes the mobx directive) and just extend a base component or add a directive to a host in order to support MobX.

When it comes to a directive for the host component, angular has this issue: angular/angular#8785

However, having a component that you extend to add MobX support should work. It would be kind of like the "onbserver" decorator in mobx-react.

When will you switch to Angular 5 for better performance?

To bypass zones, bootstrap your application with ‘noop’ as your ngZone for better performance.

platformBrowserDynamic().bootstrapModule(AppModule, {ngZone: 'noop'}).then( ref => {} );

And why do you write in the description "MobX connector to Angular 2"? After all, now you just need to write Angular (MobX connector to Angular).

mobxAutorun not working with onPush without @Input

I'm trying to use the mobx in my angular project.
When I use the *mobxAutorun directive together with OnPush detection, the component does not re-render on changes unless I pass the @computed value from the store as an @Input.
If I inject the store into the component's constructor and refer to the @computed value from the store object in my view - the changes do not reflect the view.

document-list.ts

//works!!!
@Component({
  selector: 'dc-list-preview',
  template: `
  	<ion-list *mobxAutorun>
           <dc-preview *ngFor="let document of documents"
             [document]="document">
           </dc-preview>
        </ion-list>
  	`,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class DocumentListPreview {

  @Input() documents;
}
//doesn't work!!!!
@Component({
  selector: 'dc-list-preview',
  template: `
  	<ion-list *mobxAutorun>
            <dc-preview *ngFor="let document of store.documents"
                [document]="document"
                (select)="store.selectDoc(document.id)">
            </dc-preview>
        </ion-list>
  	`,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class DocumentListPreview {

  constructor(private store: DocumentsStore) {}
}

store.ts

@Injectable()
  export class DocumentsStore {

  @observable documentsObj: {[key: string]: Order} = {};

  @computed get documents(): Order[] {
      return Object.keys(this.documentsObj).map(key => this.documentsObj[key]);
    }

  @action fetch() {
      asyncFetch.then(this,insert)
    }

  @action insert = (data) => {
      data.forEach(doc=> {
        this.documentsObj[doc.id] = doc;
      })
    }
}

What am I doing wrong?

MobX cannot be used with AoT

This is kind of a deal breaker for using MobX with Angular. It turns out that MobX's decorators cause Angular's AoT to fail:

ERROR in Error encountered resolving symbol values statically. Only initialized variables and constants can be referenced because the value of this variable is needed by the template compiler (position 77:13 in the original .ts file), resolving symbol action

Maybe this should be added to the README.md or maybe there is some other way to fix the problem that I am unaware of.

2 x *mobxAutorun directive(s) in todos template

This is a very simple question for someone who is very familiar with mobx-angular but for me is that not clear at first glance why there are 2 x *mobxAuto directive(s) in the todos template !

Questions:

  • Because of performance reasons?

  • Because of separation the renderings sections?
    -- what does this line do in the mobxAuto directive library ? What they receive, the html section of html-section and html-footer or the whole component template?

  • when it is recommended to use several *mobxAuto(s)

Unexpected token import (Angular Universal, cli)

Is it possible to make mobx-angular play nicely with an Angular-CLI Universal app?

I guess it's got something to do with how mobx-angular is compiled, and there're ES6 imports left around.

Tried some workarounds mentioned elsewhere, but didn't help:

  • Repack my apps main bundle again with webpack for server, targeting node. No good: Imports are gone but then "Zone already started" or something. Other meaningless errors if I don't require zone.js/dist/zone-node in my Express app.
  • Require('import-export'): Some other weird error like "Unexpected string".

node_modules\mobx-angular\dist\directives\mobx-autorun.directive.js:10
import { Directive, ViewContainerRef, TemplateRef, Renderer } from '@angular/core';
^^^^^^

SyntaxError: Unexpected token import
at createScript (vm.js:74:10)
at Object.runInThisContext (vm.js:116:10)
at Module._compile (module.js:533:28)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:503:32)
at tryModuleLoad (module.js:466:12)
at Function.Module._load (module.js:458:3)
at Module.require (module.js:513:17)
at require (internal/module.js:11:18)
at Object.xKKB (C:\Duunit\dia-log\functions\dist-server\main.f67f166eccdf77f620c3.bundle.js:1:915114)

mobxAngularDebug(true) disables rxJs stream

this stops working as soon as debug is set to true:

from(toStream( () => this.otherTitle = this.getTitle(), true)).subscribe(l => console.log(l));

(toStream is from mobx-utils)

Subscribe (React) in TypeScript

#How can I subscribe (react) in the compontent type script file without the autorun directive in the html file?
Like a normal subscribe with a normal observable...

Like
this.myStore.isVisible.subscribe()

Unexpected token: Jest testing

src/app/playground/counter/counter.component.pug: Unexpected token (1:4)
      > 1 | div(*mobxAutorun='{ dontDetach: true }')
          |     ^
        2 |   p Clicked: {{ counter.value }} times, value is {{ counter.evenOrOdd }}.
        3 |
        4 |   div

{
  "jest": {
    "transform": {
      "\\.(pug)$": "<rootDir>/node_modules/pug-jest"
    }
  }
}

Using `@observable.ref` and others

From reading through the issues, #13 seems to suggest that I should be importing observable, computed, etc. from angular-mobx rather than from mobx in order to allow AoT.

However, this seems to prohibit the use of @observable.ref, @observable.shallow, and all other variants. When using @observable.ref TypeScript complains with:

TS2339: Property 'ref' does not exist on type '(...args: any[]) => any'

I haven't gotten to the point where I need to worry about AoT just yet, as such I'll simply import from mobx directly for now, but I thought this was an issue worth mentioning.

Thank you for your work!

multiple mobx instances active

After update to 1.6.0 we got error on tests:

WARN: '[mobx] Warning: there are multiple mobx instances active. This might lead to unexpected results. See https://github.com/mobxjs/mobx/issues/1082WARN: '[mobx] Warning: there are multiple mobx instances active. This might lead to unexpected results. See https://github.com/mobxjs/mobx/issues/1082
 for details.'

And test failed on autorun waiting. It's because npm install mobx twice: in project and inside mobx-angular
selection_005
After manual deleting mobx from mobx-angular everything work fine.

Detaching CD breaks `ng-touched` classes on ngModel input

This might be intended behavior, but detaching CD breaks the adding of ng-touched class on the input with ngModel binding. As an example you can see the example/todo app - the input for todos does not change it's classes after being touched (or changed to dirty).

If I use *mobxAutorun="{ dontDetach: true }" the "problem" goes away.

Maybe the example should be changed or this somehow should be documented? Or maybe this is really a Angular issue/behavior?

Injectable stores with DI?

I have two @Injectable() stores - DataStore and a UiStore.

How can I use the Angular DI to pass the UiStore into the DataStore?
This doesn't seem to work...

@Injectable()
@remotedev({onlyActions: true, global: true})
export class DataStore {
  constructor(private uiStore: UiStore) {}

Thanks

mobxAngularDebug(true) disables console.log

I have a simple component that logs to the console in an autorun.
It works. I see the messages in the console of Chrome (version 63.0.3239.108)
After mobxAngularDebug(true), my messages don't appear anymore.
The mobxAngular messages appear: "updated '[email protected]': hello......".

Is there a way to keep the normal log?

import { Component, OnInit } from '@angular/core';
import { observable, autorun } from 'mobx';

@Component({
  selector: 'app-test',
  template:`
    <div>
     <div>{{str}}</div>
     <button (click)="str = str + '.'">add</button>
    </div>
`
})
export class TestComponent  {
  @observable str:string = "hello";
  constructor() {
     autorun(()=> console.log(this.str));
   }
}

chromeconsole

Integration of mobx with remotedev for inspect state in the redux devtools

Hi @Jonatthu, i'm not sure this could be an issue of mobx-angular, but i'm not able to put this working and i saw a similar issue in this repo (#17) but didn't help me.

I just grab your bank example, then:

  • npm install
  • npm install --save mobx-remotedev
  • change code in file: account.store.ts to
import { Injectable } from '@angular/core';
import { observable, autorun, computed, action, reaction, when, toJS, useStrict } from 'mobx';
import { sum } from 'lodash';
import remotedev from 'mobx-remotedev'; //added this line

useStrict(true);


@remotedev({name: 'MY STORE', global: true}) //added this line
@Injectable()
export class Account {
  @observable transactions: number[] = [];

  constructor() {
    if (localStorage.savedTransactions) {
      this.transactions = JSON.parse(localStorage.savedTransactions);
...

then i run ng serve and i open the redux console in browser, refresh the page i can't see the store.

Any tip on this? Thanks in advance.

"Not collapsing log in debug" from 2.0.2 is making debug info not readable

Can anyone explain the reson of not collapsing the logs in debug? I have updated the version to 2.1.0 and when I run my app (with MobX in debug mode, I cannot find any usefull information as the whole console is fullfiled with open stacktraces almost 100 lines each...). Any way of disabling it?

New debug utils breaks Nativescript usage

Love the simplicity of the plugin and it would be great if core features could remain usable in non-browser environments. The new debug options look useful, but for usage in native environments such as Nativescript with Angular the debug options break everything due to the assumption of the existence of "window".

I'm pretty sure a temp-fix would be to simply check for window's existence as well (with debugging unfortunately forced off for native use). For example below, wrapping the function being set on the window with a window check, and then adding "window &&" to the start of isDebugOn. Maybe future could add support for native debugging as well.

// function for turning debug on / off
if (window) {
  window['ng2MobxDebug'] = (value) => {
    if (value) window['localStorage']['ng2-mobx-debug'] = true;
    else delete window['localStorage']['ng2-mobx-debug'];
  }
}

function isDebugOn() {
  return window && window['localStorage'] && window['localStorage']['ng2-mobx-debug'];
}

For now just set myself to use 1.2.0 which looks to be last build before the debug options were added.

Option to disable the MobxAngularDebug utility in production builds

MobxAngularDebug is very helpful during the development process. But per Can I Use, approximately ~5% of users are running browsers that do not support Web Storage. Subsequently, every so often I receive a notification via Sentry that my production app crashed during an instantiation of an observable (which was ultimately triggered by the lack of localStorage support).

Thus, it would be great if there was a build time flag we could use to disable including this utility with the production bundle.

Upgrade from 1.3.0 to 1.4.1 failing

When I was on 1.3.0 everything was working fine but with the latest version is failing and giving me the next error:

ng:///AppModule/AppComponent.ngfactory.js:1429 ERROR CONTEXT DebugContext_
View_AppComponent_0 @ ng:///AppModule/AppComponent.ngfactory.js:1429
polyfills.bundle.js:7134 Unhandled Promise rejection: Cannot read property 'context' of undefined ; Zone: <root> ; Task: Promise.then ; Value: TypeError: Cannot read property 'context' of undefined
    at MobxAutorunDirective.autoDetect (vendor.bundle.js:73005)
    at MobxAutorunDirective.ngOnInit (vendor.bundle.js:73001)
    at checkAndUpdateDirectiveInline (vendor.bundle.js:10971)
    at checkAndUpdateNodeInline (vendor.bundle.js:12349)
    at checkAndUpdateNode (vendor.bundle.js:12317)
    at debugCheckAndUpdateNode (vendor.bundle.js:12946)
    at debugCheckDirectivesFn (vendor.bundle.js:12887)
    at Object.eval [as updateDirectives] (ng:///AppModule/AppComponent.ngfactory.js:1439)
    at Object.debugUpdateDirectives [as updateDirectives] (vendor.bundle.js:12872)
    at checkAndUpdateView (vendor.bundle.js:12284)
    at callViewAction (vendor.bundle.js:12599)
    at execComponentViewsAction (vendor.bundle.js:12545)
    at checkAndUpdateView (vendor.bundle.js:12290)
    at callWithDebugContext (vendor.bundle.js:13272)
    at Object.debugCheckAndUpdateView [as checkAndUpdateView] (vendor.bundle.js:12812) TypeError: Cannot read property 'context' of undefined
    at MobxAutorunDirective.autoDetect (http://localhost:4200/vendor.bundle.js:73005:114)
    at MobxAutorunDirective.ngOnInit (http://localhost:4200/vendor.bundle.js:73001:14)
    at checkAndUpdateDirectiveInline (http://localhost:4200/vendor.bundle.js:10971:19)
    at checkAndUpdateNodeInline (http://localhost:4200/vendor.bundle.js:12349:17)
    at checkAndUpdateNode (http://localhost:4200/vendor.bundle.js:12317:16)
    at debugCheckAndUpdateNode (http://localhost:4200/vendor.bundle.js:12946:59)
    at debugCheckDirectivesFn (http://localhost:4200/vendor.bundle.js:12887:13)
    at Object.eval [as updateDirectives] (ng:///AppModule/AppComponent.ngfactory.js:1439:5)
    at Object.debugUpdateDirectives [as updateDirectives] (http://localhost:4200/vendor.bundle.js:12872:21)
    at checkAndUpdateView (http://localhost:4200/vendor.bundle.js:12284:14)
    at callViewAction (http://localhost:4200/vendor.bundle.js:12599:17)
    at execComponentViewsAction (http://localhost:4200/vendor.bundle.js:12545:13)
    at checkAndUpdateView (http://localhost:4200/vendor.bundle.js:12290:5)
    at callWithDebugContext (http://localhost:4200/vendor.bundle.js:13272:42)
    at Object.debugCheckAndUpdateView [as checkAndUpdateView] (http://localhost:4200/vendor.bundle.js:12812:12)
consoleError @ polyfills.bundle.js:7134
polyfills.bundle.js:7136 Error: Uncaught (in promise): TypeError: Cannot read property 'context' of undefined
TypeError: Cannot read property 'context' of undefined
    at MobxAutorunDirective.autoDetect (vendor.bundle.js:73005)
    at MobxAutorunDirective.ngOnInit (vendor.bundle.js:73001)
    at checkAndUpdateDirectiveInline (vendor.bundle.js:10971)
    at checkAndUpdateNodeInline (vendor.bundle.js:12349)
    at checkAndUpdateNode (vendor.bundle.js:12317)
    at debugCheckAndUpdateNode (vendor.bundle.js:12946)
    at debugCheckDirectivesFn (vendor.bundle.js:12887)
    at Object.eval [as updateDirectives] (ng:///AppModule/AppComponent.ngfactory.js:1439)
    at Object.debugUpdateDirectives [as updateDirectives] (vendor.bundle.js:12872)
    at checkAndUpdateView (vendor.bundle.js:12284)
    at callViewAction (vendor.bundle.js:12599)
    at execComponentViewsAction (vendor.bundle.js:12545)
    at checkAndUpdateView (vendor.bundle.js:12290)
    at callWithDebugContext (vendor.bundle.js:13272)
    at Object.debugCheckAndUpdateView [as checkAndUpdateView] (vendor.bundle.js:12812)
    at MobxAutorunDirective.autoDetect (vendor.bundle.js:73005)
    at MobxAutorunDirective.ngOnInit (vendor.bundle.js:73001)
    at checkAndUpdateDirectiveInline (vendor.bundle.js:10971)
    at checkAndUpdateNodeInline (vendor.bundle.js:12349)
    at checkAndUpdateNode (vendor.bundle.js:12317)
    at debugCheckAndUpdateNode (vendor.bundle.js:12946)
    at debugCheckDirectivesFn (vendor.bundle.js:12887)
    at Object.eval [as updateDirectives] (ng:///AppModule/AppComponent.ngfactory.js:1439)
    at Object.debugUpdateDirectives [as updateDirectives] (vendor.bundle.js:12872)
    at checkAndUpdateView (vendor.bundle.js:12284)
    at callViewAction (vendor.bundle.js:12599)
    at execComponentViewsAction (vendor.bundle.js:12545)
    at checkAndUpdateView (vendor.bundle.js:12290)
    at callWithDebugContext (vendor.bundle.js:13272)
    at Object.debugCheckAndUpdateView [as checkAndUpdateView] (vendor.bundle.js:12812)
    at resolvePromise (polyfills.bundle.js:7277) [<root>]
    at :4200/polyfills.bundle.js:7203:17 [<root>]
    at :4200/polyfills.bundle.js:7219:33 [<root>]
    at Zone.run (polyfills.bundle.js:6690) [<root> => <root>]
    at :4200/polyfills.bundle.js:7325:57 [<root>]
    at Zone.runTask (polyfills.bundle.js:6730) [<root> => <root>]
    at drainMicroTaskQueue (polyfills.bundle.js:7158) [<root>]
consoleError @ polyfills.bundle.js:7136

Versions:
Angular: 4
Mobx: 2.1.8
mobx-angular: 1.4.1

Example fails to start

ERROR in [default] \mobx\ng2-mobx\example\src\app\app.module.ts:7:9
Module '"/mobx/ng2-mobx/example/node_modules/ng2-mobx/dist/ng2-mobx"' has no exported member 'Ng2MobxModule'.

Getting "Error encountered resolving symbol values statically. Function calls are not supported. Consider replacing the function or lambda with a reference to an exported function"

I'm using angular-tree-component that have dependency on mobx-angular(v1.5.0)
With angular 4.2.6 everything works fine, but with 4.3.0 i keep getting error:

ERROR in Error encountered resolving symbol values statically. Function calls are not supported. Consider replacing the function or lambda with a reference to an exported function (position 194:50 in the original .ts file), resolving symbol NgModule in project/node_modules/mobx-angular/node_modules/@angular/core/core.d.ts, resolving symbol MobxAngularModule in project/node_modules/mobx-angular/dist/mobx-angular.d.ts, resolving symbol MobxAngularModule in project/node_modules/mobx-angular/dist/mobx-angular.d.ts

mobx 2.7.0

When installing ng2-mobx with npm, it also installs mobx 2.6.0.
Mobx 2.7.0 is already released, and it includes quite a few bug fixes and features.

Please update the mobx dependency

2.1.0 release not deployed to npm correctly?

Just upgraded to v2.1.0 (from previous 2.0.2) and it appears as if it has the behaviour of the 2.X release where the *mobxAutorun directive would detach the CD by default.

The code in my npm modules node_modules/mobx-angular/dist/directives/mobx-autorun.directive.js seems to verify the 2.X behaviour:

MobxAutorunDirective.prototype.shouldDetach = function () { return !this.mobxAutorun || !this.mobxAutorun.dontDetach; };

I have blown away my node_modules directory and refetched from npm just to make sure, the behaviour still persists.

Anyone else seeing this?

ng2MobxDebug?

Where is there documentation or even a simple example of how to use it?

Thanks

Integrating mobx-remotedev

https://github.com/zalmoxisus/mobx-remotedev

When...

import { Injectable } from '@angular/core';
import { action, observable, computed } from 'mobx';
import remotedev from 'mobx-remotedev/lib/dev';
import { SearchStore, ClientStore } from 'store';
import { ClientsService } from 'services/api';

@Injectable()
@remotedev({name: 'MAPWORDS STORE', global: true})
export class Store {

  @observable
  public id: number = 1;

  constructor(
    private _searchStore: SearchStore,
    private _clientStore: ClientStore,
    private _clientsService: ClientsService
  ) {
    console.log(this._searchStore, this._clientStore, this._clientsService);
  }

  @action
  public a() {

  }

}

Angular does not inject the properties to the constructor but if I just remove the decorator of remote dev is now working, any tip for this?

Export `action` from mobx?

Hi! Thanks for an amazing module!

I have a small problem with using it with AoT compiler though.
Saw #13 and importing observable and computed directly from ng2-mobx works perfect, but I also need to import action to decorate methods that change a bunch of observables, but ng2-mobx doesn't export it.

Maybe use export * from 'mobx' instead of exporting proxies or AoT will fail in this case as well?

combine mobx with Rxjs

I've read the following here

RxJs helps you deal with events, MobX helps you deal with values (again, like a spreadsheet). You will find that the latter works more intuitively and high-level in most cases. (but combining both is also a very powerful combination)

Since its known that Rxjs Observables are first class citizens in Angular, I wonder if there is a way to combine them together with Mobx's state management?

What are the benefits from doing so? What use cases? Does anyone have a working example?

Automatic async actions

@adamkleingit would you be interested in adding an action decorator that automatically wraps async operations in an action. I realized this could be done using zone.js to get a callback whenever something async happens.

I built a proof of concept for how this could work here: https://plnkr.co/edit/1S4UIt5LJ0VbVkYgsyei?p=preview

Basically you can annotate a function like this

@asyncAction
getDataWithHttpClient() {
  this.http.get('https://jsonplaceholder.typicode.com/posts/1')
    .map((data) => data.title)
    .subscribe((title) => this.httpClientTitle = title)
}

And the @asyncAction Will automatically wrap the callbacks in an action.

With mobxAngularDebug turned on my initial attempt was very verbose. Every .then() triggers a "microTask" in zone.js and was being wrapped in it's own action even if it wasn't doing anything async. I found that I could improve this by forking mobx, exporting startAction() and endAction() and using them to bundle together "microTasks" into a single action. This approach would need some work though as I think it currently breaks some of the spying functionality of mobx. @mweststrate what do you think about exposing some way of adding functions to a pending action?

Anyway let me know if you are interested. I'd be happy to clean this up and send a PR. Here's what I currently have for the implementation of @asyncAction

import {action, endAction, runInAction, startAction} from 'mobx';

declare const Zone;

const asyncAction = function (target, prop: string, descriptor) {
  let pendingAction;
  let finishedInitialSyncAction = false;

  //Create a zone that will wrap all async tasks in an action
  let actionZone = Zone.current.fork({
    name: `mobxActionZone:${prop}`,

    onInvokeTask(delegate, currentZone, targetZone, task, ...args) {
      if (task.type === 'macroTask' || task.type === 'eventTask') {
        return runInAction(`${prop}:async`, () => delegate.invokeTask(targetZone, task, ...args));
      } else {
        return delegate.invokeTask(targetZone, task, ...args);
      }
    },
    
    onHasTask(parentZoneDelegate, currentZone, targetZone, hasTaskState) {
      if (hasTaskState.change === 'microTask' && finishedInitialSyncAction) {
        if (hasTaskState.microTask) {
          pendingAction = startAction(`${prop}:async`, () => {}, null);
        } else if (pendingAction) {
          endAction(pendingAction);
          pendingAction = undefined;
        }
      }

    }
  });


  //Modify the annotated function so that it runs in the actionZone
  let origFunc = descriptor.value;
  descriptor.value = function (...args) {
    return actionZone.run(() => {
      finishedInitialSyncAction = false;
      let result = origFunc.call(this, ...args);
      finishedInitialSyncAction = true;
      return result;
    });
  };

  return action(target, prop, descriptor);
};

export default asyncAction;

Model driven forms?

Is it it possible to enhance ng2-mobx to make it work in a model driven template environment?

Debug mode logs observables set in a constructor

If I enable debug mode with mobxAngularDebug(true); then it is individually logging out every observable I set in a constructor. Does this mean that mobX is pushing out those updates individually? Do I need to wrap my updates in an action instead of having them in the constructor?

e.g. if I have the following code:

import {observable} from 'mobx';

class MyClass {
    @observable val1 = 1;
    @observable val2;
    @observable val3;

    constructor(val2, val3) {
        this.val2 = val2;
        this.val3 = val3;
    }
}

mobxAngularDebug(true);
let myClass = new MyClass(2,3);

it will log out:

MobxAutorunDirective throws a TypeError when used with a Pipe

First of all, thanks for this lib, it's been very useful in refactoring a spaghetti mess of state manipulation into something easier to reason about and maintain.

When using mobx + ng2-mobx, found a reproducible issue when using a Pipe. Here's an example stack trace:

TypeError: Cannot read property 'transform' of undefined
    at View_App1.createInternal (/AppModule/App/component.ngfactory.js:32)
    at View_App1.AppView.create (VM329 core.umd.js:11878)
    at View_App1.DebugAppView.create (VM329 core.umd.js:12282)
    at TemplateRef_.createEmbeddedView (VM329 core.umd.js:8897)
    at ViewContainerRef_.createEmbeddedView (VM329 core.umd.js:9117)
    at new MobxAutorunDirective (VM337 ng2-mobx.umd.js:289)
    at new Wrapper_MobxAutorunDirective (/Ng2MobxModule/MobxAutorunDirective/wrapper.ngfactory.js:7)
    at CompiledTemplate.proxyViewClass.View_App0.createInternal (/AppModule/App/component.ngfactory.js:93)
    at CompiledTemplate.proxyViewClass.AppView.create (VM329 core.umd.js:11878)
    at CompiledTemplate.proxyViewClass.DebugAppView.create (VM329 core.umd.js:12282)
    at CompiledTemplate.proxyViewClass.View_App_Host0.createInternal (/AppModule/App/host.ngfactory.js:16)
    at CompiledTemplate.proxyViewClass.AppView.createHostView (VM329 core.umd.js:11891)
    at CompiledTemplate.proxyViewClass.DebugAppView.createHostView (VM329 core.umd.js:12299)
    at ComponentFactory.create (VM329 core.umd.js:7288)
    at ApplicationRef_.bootstrap (VM329 core.umd.js:8257)

Here is a link to a plunk with the issue (check out the console):

http://plnkr.co/edit/dUFlmCZN80gaodTJt31m?p=preview

And, by accident I discovered this workaround as a temporary fix (wrap with an *ngIf="true"):

http://plnkr.co/edit/sISR7m1pTmgtwRIyvnMB?p=preview

Moving from mobx 3.2.2 to 3.3.1 broke something

I'm using mobx in an ionic project. My Deps:

"@angular/common": "5.0.0",
       "@angular/compiler": "5.0.0",
       "@angular/compiler-cli": "5.0.0",
       "@angular/core": "5.0.0",
       "@angular/forms": "5.0.0",
       "@angular/http": "5.0.0",
       "@angular/platform-browser": "5.0.0",
       "@angular/platform-browser-dynamic": "5.0.0",
       "@compodoc/compodoc": "1.0.4",
       "@ionic-native/app-version": "4.4.2",
       "@ionic-native/core": "4.4.2",
       "@ionic-native/device": "4.4.2",
       "@ionic-native/local-notifications": "4.4.2",
       "@ionic-native/social-sharing": "4.4.2",
       "@ionic-native/splash-screen": "4.4.2",
       "@ionic-native/status-bar": "4.4.2",
       "@ionic/storage": "2.1.3",
        ...
       "core-js": "^2.4.1",
       "date-fns": "1.29.0",
       "es6-promise-plugin": "4.1.1",
       "ionic-angular": "3.9.2",
       "ionicons": "3.0.0",
       "lodash-es": "4.17.4",
       "mobx": "3.3.1",
       "mobx-angular": "1.9.0",
       "mobx-remotedev": "0.2.8",
       "pouchdb": "6.3.4",
       "raven-js": "3.20.1",
       "rxjs": "5.5.2",
       "sw-toolbox": "3.6.0",
       "waaclock": "0.5.3",
       "zone.js": "0.8.18"

After upgrading mobx 3.2.2 to 3.3.1, 7 tests of the 203 unit tests in my app are broken. An example of broken test after the upgrade:


 it('Should return 1 after first answer', () => {
            exerciseModel.questions[0].answer = 'p2';
            exerciseModel.questions[1].answer = 'p1';
            expect(exerciseModel.questions[0].hasAnswer).toBeTruthy();
            expect(exerciseModel.lastQuestionAnswered).toBe(1);
        });

export class ExerciseModel implements Exercise {
    @observable public questions: QuestionModel[];
    @computed
    public get lastQuestionAnswered(): number {
        const result = findLastIndex(this.questions, 'hasAnswer');
        return result === -1 ? 0 : result;
    }
   //....
}

export class QuestionModel {
    @observable public hasAnswer: boolean = false;
    @observable public isOpen: boolean;
    @observable private _answer: any = null;
   //....
@computed
    public get answer(): any {
        if (this._answer == null) {
            switch (this.answerType) {
                case 'textarea':
                    this._answer = '';
                    break;
                case 'range':
                    this._answer = 5;
                    break;
                case 'none':
                    this._answer = '';
                    break;
                default:
                    this._answer = '';
            }
        }

        return this._answer;
    }

    public set answer(val: any) {
        if (val != null) {
            this._answer = val;
            this.hasAnswer = true;
        }
    }
}

EXCEPTION: Uncaught (in promise): Error: Error in :0:0 caused by: [mobx] Invariant failed: no observable property 'someProperty' found on the observable object 'DomainStore@1'

In my ngOnInit, I am calling observe(this.store, "currentGreeting") to react to the greeting value changing in my store. However, I am getting this error:

Error: Uncaught (in promise): Error: Error in :0:0 caused by: [mobx] Invariant failed: no observable property 'currentGreeting' found on the observable object 'DomainStore@1'
    at resolvePromise (polyfills.dll.js:18122)
    at polyfills.dll.js:18099
    at ZoneDelegate.invoke (polyfills.dll.js:17896)
    at Object.onInvoke (vendor.dll.js:26246)
    at ZoneDelegate.invoke (polyfills.dll.js:17895)
    at Zone.run (polyfills.dll.js:17789)
    at polyfills.dll.js:18155
    at ZoneDelegate.invokeTask (polyfills.dll.js:17929)
    at Object.onInvokeTask (vendor.dll.js:26237)
    at ZoneDelegate.invokeTask (polyfills.dll.js:17928)

Unhandled Promise rejection: Error in :0:0 caused by: [mobx] Invariant failed: no observable property 'currentGreeting' found on the observable object 'DomainStore@1' ; Zone: angular ; Task: Promise.then ; Value: ViewWrappedError {_nativeError: Error: Error in :0:0 caused by: [mobx] Invariant failed: no observable property 'currentGreeting' f…, originalError: Error: [mobx] Invariant failed: no observable property 'currentGreeting' found on the observable ob…, context: DebugContext} Error: [mobx] Invariant failed: no observable property 'currentGreeting' found on the observable object 'DomainStore@1'
    at invariant (eval at ./node_modules/mobx/lib/mobx.js (http://localhost/js/bundle.js:718:1), <anonymous>:2577:15)
    at getAtom (eval at ./node_modules/mobx/lib/mobx.js (http://localhost/js/bundle.js:718:1), <anonymous>:2407:13)
    at getAdministration (eval at ./node_modules/mobx/lib/mobx.js (http://localhost/js/bundle.js:718:1), <anonymous>:2424:34)
    at observeObservableProperty (eval at ./node_modules/mobx/lib/mobx.js (http://localhost/js/bundle.js:718:1), <anonymous>:498:12)
    at Object.observe (eval at ./node_modules/mobx/lib/mobx.js (http://localhost/js/bundle.js:718:1), <anonymous>:478:16)
    at EventComponent.ngOnInit (eval at ./src/components/event.component.ts (http://localhost/js/bundle.js:838:1), <anonymous>:32:16)
    at Wrapper_EventComponent.ngDoCheck (/AppModule/EventComponent/wrapper.ngfactory.js:22:53)
    at CompiledTemplate.proxyViewClass.View_EventComponent_Host0.detectChangesInternal (/AppModule/EventComponent/host.ngfactory.js:28:32)
    at CompiledTemplate.proxyViewClass.AppView.detectChanges (http://localhost/js/vendor.dll.js:51989:14)
    at CompiledTemplate.proxyViewClass.DebugAppView.detectChanges (http://localhost/js/vendor.dll.js:52082:44)
consoleError @ polyfills.dll.js:18048
_loop_1 @ polyfills.dll.js:18075
drainMicroTaskQueue @ polyfills.dll.js:18079
ZoneTask.invoke @ polyfills.dll.js:18001
polyfills.dll.js:18050 Error: Uncaught (in promise): Error: Error in :0:0 caused by: [mobx] Invariant failed: no observable property 'currentGreeting' found on the observable object 'DomainStore@1'
    at resolvePromise (polyfills.dll.js:18122)
    at polyfills.dll.js:18099
    at ZoneDelegate.invoke (polyfills.dll.js:17896)
    at Object.onInvoke (vendor.dll.js:26246)
    at ZoneDelegate.invoke (polyfills.dll.js:17895)
    at Zone.run (polyfills.dll.js:17789)
    at polyfills.dll.js:18155
    at ZoneDelegate.invokeTask (polyfills.dll.js:17929)
    at Object.onInvokeTask (vendor.dll.js:26237)
    at ZoneDelegate.invokeTask (polyfills.dll.js:17928)

Here is my DomainStore:

import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import 'shared/rxjs-small';
import { Observable } from 'rxjs/Observable';
import { observable, computed, action, autorun } from 'mobx';

import { plainToClass, Type } from "class-transformer";
import { UserModel } from 'models';
import { ApiService } from 'services';

@Injectable()
export class DomainStore {
      version = '<{version}>';

      @Type(() => UserModel)
      @observable users: UserModel[] = [];

      @observable currentUserId: number;
      @observable currentGreeting;

      @observable initialLoadComplete;
      @observable refresh = { events: false, config: false };

      constructor(private apiService: ApiService, private router: Router) {
            autorun("getUsers", () => {
                  let self = this;

                  if (self.refresh.events || self.users.length === 0) {
                        return self.apiService.get("users")
                              .subscribe(tables => {
                                    self.users = tables.users;
                              });
                  };
            });            
      }

      @computed get isLoggedIn() {
            return this.currentUser && this.currentUser.token && this.currentUser.token.length > 0;
      }

      @computed get currentUser() {
            return this.users.find(u => u.id === this.currentUserId);
      }
}

Here is my WelcomeComponent that calls observe from ngOnInit:

import { Component, OnInit, ChangeDetectionStrategy, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Router, ActivatedRoute, Params } from '@angular/router';
import { observe } from 'mobx';

import { DomainStore } from 'stores';
import 'shared/rxjs-small';
declare var $: any;

@Component({
      selector: 'welcome',
      templateUrl: 'welcome.html',
      changeDetection: ChangeDetectionStrategy.OnPush
})
export class WelcomeComponent implements OnInit {
      constructor(private router: Router, private route: ActivatedRoute, public store: DomainStore) { }

      ngOnInit() {
            let self = this;

            this.route.params.subscribe((params: any) => {
                  this.store.changeCurrentEvent(params["site"]);
                  if (!this.store.currentEvent) {
                        this.router.navigate(["home"]);
                  }
            });
            
                        observe(this.store, "currentGreeting", change => {
                              if (change.newValue) {
                                    alert("Your greeting has changed.");
                                    $("#myModal").modal("hide");
                              }
                        });
      }
}

I have all of my components wrapped in <div class="jumbotron" *mobxAutorun>...</div> and they all have changeDetection: ChangeDetectionStrategy.OnPush set. I'm not sure why it is not detecting that the property is decorated with @observable. Am I missing a step?

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.