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).

Oleksii Pavlenko
  • 1,327
  • 1
  • 11
  • 25
Toby
  • 175
  • 1
  • 1
  • 7

3 Answers3

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 ;)

Community
  • 1
  • 1
Eric Martinez
  • 31,277
  • 9
  • 92
  • 91
  • 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? – Toby Oct 28 '15 at 20:58
  • 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? – Eric Martinez Oct 28 '15 at 21:06
  • 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? – Eric Martinez Oct 28 '15 at 21:17
  • 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. – Toby Oct 28 '15 at 21:19
  • I edited my answer a few mins ago. Try the second approach `import * as Subject` (with the asterisk), that should work, I got the same error. – Eric Martinez Oct 28 '15 at 21:20
  • 1
    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 :). – Toby Oct 28 '15 at 21:41
  • @Toby note that this is being refactored, so in future releases it should be fixed (regarding typings), so I'll try to update this answer when the fixes arrive (I hope I remember to update the answer, so don't make yourself false hopes :P) – Eric Martinez Oct 30 '15 at 13:44
  • @EricMartinez Perhaps you could update this again now that angular2/angular2 is gone and RxJS5 is no longer included by default in Angular2.0.0-beta.0 – Michael Oryl Dec 21 '15 at 20:00
  • @MichaelOryl you're absolutely right. Update incoming... Thanks for the suggestion! – Eric Martinez Dec 21 '15 at 20:02
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
Murhaf Sousli
  • 12,622
  • 20
  • 119
  • 185
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());
  }

}
STEEL
  • 8,955
  • 9
  • 67
  • 89