mobxjs / mobx-angular Goto Github PK
View Code? Open in Web Editor NEWThe MobX connector for Angular.
License: MIT License
The MobX connector for Angular.
License: MIT License
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
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"
}
Is ChangeDetectionStrategy.OnPush required or can I leave it off.
If I can leave it off, What are the pros/cons to turning it on or leaving it off?
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!
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.
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).
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?
The library is compiled to es2015, which is problematic for running tests on PhantomJS prior to 2.5 beta, see here:
ariya/phantomjs#14506
Could you also make a build targeted to es5?
Some developers might not appreciate having a console warning imposed on them.
The build for this library does not seem to conform to the Package Format 5.0. Please update to conform to the spec so all applications can benefit from this project.
https://docs.google.com/document/d/1CZC2rcpxffTDfRDs6p1cfbmKNLA6x5O-NtkJglDaBVs/preview
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.
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)
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:
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)
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)
Is there any plan to implement something like this?
After upgrading to v.2.0.1, Angular Material input can not focus.
#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()
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"
}
}
}
Now it depends on Angular 2.
Can we loose restriction to >= 2.3
or ^2.3 || ^4
?
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!
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
After manual deleting mobx from mobx-angular everything work fine.
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?
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
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));
}
}
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:
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.
I am try the Todo example from this project and see that computed functions in mobx store is called twice every time when one 1 observable change.
Is this a normal?
Also i see this in my own project.
If i remove *mobxAutorun it will be called only once. Example and my own app still works.
http://prntscr.com/e9oois
But now function is called every time i type in input.
http://prntscr.com/e9opxs
How can I do something like this:
@observable.ref
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?
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.
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.
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
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'.
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
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
I must be missing something obvious and I know I use this issue selfishly to get help.
If I add *mobxAutorun
on the top of tags.component.html
, the whole component is not rendered. If I remove it, it is rendered on the bottom of the page, but the the code reflecting to the commonStore.isLoadingTags
is not processed correctly.
Thanks for your suggestions!
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?
Where is there documentation or even a simple example of how to use it?
Thanks
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?
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?
Hey,
I wanted to play with ng2-mobx, so I used plunker and added the unpkg.com cdn url:
https://unpkg.com/[email protected]
but this returns the code with only references to the directive files, they are not bundled.
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?
@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;
Per https://github.com/mobxjs/mobx/releases, seems like 3.x is stable
Is it it possible to enhance ng2-mobx to make it work in a model driven template environment?
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:
set '[email protected]': 01
set '[email protected]': 02
set '[email protected]': 03
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"
):
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;
}
}
}
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?
Mobx 3 has been released, this should be added in the milestones :D
@adamkleingit any chance you can grant permissions to a few users to help maintain this repo?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.