11

I'm unable to get a minimal Angular 2 application using RxJS off the ground. I'm using Typescript (tsc 1.6.2) and systemjs for module loading. How do I get systemjs to load the Rx module correctly? I've run out of ideas to try and I'd appreciate any pointer to what I'm doing wrong. Module loading is a bit of magic to me. Very frustrating.

index.html:

<!DOCTYPE html>
<html>
<head>
    <title>Title</title>
    <script src="../node_modules/es6-shim/es6-shim.js"></script>
    <script src="../node_modules/systemjs/dist/system.src.js"></script>
    <script src="../node_modules/rx/dist/rx.lite.js"></script>
    <script src="../node_modules/angular2/bundles/angular2.dev.js"></script>
</head>

<body>
    <app>App loading...</app>
    <script>
        System.config({
            packages: { 'app': { defaultExtension: 'js' } }
        });
        System.import('app/app');
    </script>
</body>
</html>

app.ts:

/// <reference path="../../node_modules/rx/ts/rx.all.d.ts" />
import { bootstrap, Component, View } from 'angular2/angular2';
import * as Rx from 'rx';

@Component({
    selector: 'app'
})
@View({
        template: `Rx Test`
})
export class App {
    subject: Rx.Subject<any> = new Rx.Subject<any>();
}
bootstrap(App);

SystemJS attempts to load a file that does not exist:

enter image description here

As soon as I comment out the subject in the code above, everything runs fine as there'll be no attempt to load the non-existent file (and no rx is loaded).

3 Answers 3

9

Update angular2 beta 0

Angular2 is no longer bundling RxJS within Angular2 itself. Now you must import the operators individually. This was an important breaking change which I answered here. So please refer to that answer since this one is obsolete and no longer applies.

Update 12/11/2015

Alpha46 is using RxJS alpha 0.0.7 (soon to be 0.0.8). Since this ng2 alpha version you need no more the solution below, you can now import Observable, Subject among others directly from angular2/angular, so the original answer can be discarded

import {Observable, Subject} from 'angular2/angular2';

=====================================

Angular2 is not longer using the old RxJS, they moved to the new RxJS 5 (aka RxJS Next) so it will collide with Http and EventEmitter.

So first remove the import and the script to rx.lite.js.

Instead you have to do (you need no scripts nor mapping in your config)

Edit

This line is to make it work in a plnkr, but in my projects I just have to add something else

Plnkr version

import Subject from '@reactivex/rxjs/dist/cjs/Subject';

Offline version

import * as Subject from '@reactivex/rxjs/dist/cjs/Subject';

Note about offline version

If you try the first approach for plnkr in your local projects you'll probably get this message error

TypeError: Subject_1.default is not a function

So for your local (offline) version you should use the second approach (with the asterisk).

Note

There's no bracket in Subject and that's explained in this conversation (I had the same problem, lol)

Here's a plnkr not failing.

I hope it helps. If I missed something just tell me ;)

Sign up to request clarification or add additional context in comments.

9 Comments

Eric, thank you for taking your time to reply! That solved part of the mystery for me. Sorry for taking so long to get back to you, I've spent most of today trying to get the same project working off-line (without any real success I must say). I am using VSC and Typescript 1.6.2, the same transpiler that is used in your example. The code generated from app.ts in the "online" version has a slightly different header which seems to make all the difference (it calls System.register(...)). Have you had any success compiling and running this locally with VSC/tsc?
Are you getting any error? In fact, In my offline version (my own project) I have import * as Subject from '...' (a little bit different than my answer. Do you have something else? How different is your online versus your offline version?
So you are getting errors at runtime? Or it fails silently? Are you using some tool like JSPM, Webpack, or something? Can you create a repo so I can clone it and see it?
No errors, transpiling is ok, intellisense works (I've added @reactivex alpha 4 in npm_modules for that, same as angular uses). It fails at runtime (TypeError: Subject_1.default is not a function) as it does not seem to load the rx module/types. I changed config.js to load "app.js" and default ext 'js' and removed the reference to typescript.js in index.html. It's driving me nuts.
Ok that is interesting. The compiler complains but the generated output is identical to what is generated in the online version - and it works in runtime. So apart from the tsc output (src/app.ts(11,14): error TS2304: Cannot find name 'Subject'. src/app.ts(11,29): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.) it's all ok. Thank you so much for your help. Next beer is on me :).
|
8

For angular2 alpha52 uses rxjs 5alpha.14

<script>
System.config({
  map: { rxjs: 'node_modules/rxjs' },
  packages: {
    rxjs: { defaultExtension: 'js' },
    'app': {defaultExtension: 'js'}
  }
});
System.import('app/app');
</script>

but you have to import each operator individually like this example

import { Subject } from 'rxjs/Subject';
import { Observable } from 'rxjs/Observable';

require('rxjs/add/operator/map');
require('rxjs/add/operator/scan');
require('rxjs/add/operator/mergemap');  //for flatmap
require('rxjs/add/operator/share');
require('rxjs/add/operator/combinelatest-static'); //for combinelatest

Comments

2

Posting this answer after Angular 4 release. Try to load bare minimum from Rxjs, since Angular prod build even with AOT is going 300kb

Hope it helps.

import { Injectable } from '@angular/core';
import {Http} from "@angular/http";
import {Observable} from "rxjs/Observable";
import 'rxjs/add/operator/map';// load this in main.ts

import {AllUserData} from "../../../shared/to/all-user-data";

@Injectable()
export class ThreadsService {

  constructor(private _http: Http) { }

  loadAllUserData(): Observable<AllUserData> {
    return this._http.get('/api/threads')
      .map(res => res.json());
  }

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.