i searching inter webs examples of signalr used beta version of angular2? cannot seem find examples using beta version.
one main question have how manually run change detection on beta version of angular 2?
thanks in advance
i wrote article demonstrates 1 way integrate angular 2 , signalr using "channel/event" model:
https://blog.sstorie.com/integrating-angular-2-and-signalr-part-2-of-2/
i don't think linking site considered appropriate, here's core of angular 2 service exposes signalr:
import {injectable, inject} "angular2/core"; import rx "rxjs/rx"; /** * when signalr runs add functions global $ variable * use create connections hub. however, in * class won't want depend on global variables, * class provides abstraction away using $ directly in here. */ export class signalrwindow extends window { $: any; } export enum connectionstate { connecting = 1, connected = 2, reconnecting = 3, disconnected = 4 } export class channelconfig { url: string; hubname: string; channel: string; } export class channelevent { name: string; channelname: string; timestamp: date; data: any; json: string; constructor() { this.timestamp = new date(); } } class channelsubject { channel: string; subject: rx.subject<channelevent>; } /** * channelservice wrapper around functionality signalr * provides expose ideas of channels , events. service * can subscribe specific channels (or groups in signalr speak) , * use observables react specific events sent out on channels. */ @injectable() export class channelservice { /** * starting$ observable available know if signalr * connection ready or not. on successful connection * stream emit value. */ starting$: rx.observable<any>; /** * connectionstate$ provides current state of underlying * connection observable stream. */ connectionstate$: rx.observable<connectionstate>; /** * error$ provides stream of error messages occur on * signalr connection */ error$: rx.observable<string>; // these used feed public observables // private connectionstatesubject = new rx.subject<connectionstate>(); private startingsubject = new rx.subject<any>(); private errorsubject = new rx.subject<any>(); // these used track internal signalr state // private hubconnection: any; private hubproxy: any; // internal array track channel subscriptions exist // private subjects = new array<channelsubject>(); constructor( @inject(signalrwindow) private window: signalrwindow, @inject("channel.config") private channelconfig: channelconfig ) { if (this.window.$ === undefined || this.window.$.hubconnection === undefined) { throw new error("the variable '$' or .hubconnection() function not defined...please check signalr scripts have been loaded properly"); } // set our observables // this.connectionstate$ = this.connectionstatesubject.asobservable(); this.error$ = this.errorsubject.asobservable(); this.starting$ = this.startingsubject.asobservable(); this.hubconnection = this.window.$.hubconnection(); this.hubconnection.url = channelconfig.url; this.hubproxy = this.hubconnection.createhubproxy(channelconfig.hubname); // define handlers connection state events // this.hubconnection.statechanged((state: any) => { let newstate = connectionstate.connecting; switch (state.newstate) { case this.window.$.signalr.connectionstate.connecting: newstate = connectionstate.connecting; break; case this.window.$.signalr.connectionstate.connected: newstate = connectionstate.connected; break; case this.window.$.signalr.connectionstate.reconnecting: newstate = connectionstate.reconnecting; break; case this.window.$.signalr.connectionstate.disconnected: newstate = connectionstate.disconnected; break; } // push new state on our subject // this.connectionstatesubject.next(newstate); }); // define handlers errors // this.hubconnection.error((error: any) => { // push error on our subject // this.errorsubject.next(error); }); this.hubproxy.on("onevent", (channel: string, ev: channelevent) => { //console.log(`onevent - ${channel} channel`, ev); // method acts broker incoming messages. // check interal array of subjects see if 1 exists // channel came in on, , emit event // on it. otherwise ignore message. // let channelsub = this.subjects.find((x: channelsubject) => { return x.channel === channel; }) channelsubject; // if found subject emit event on // if (channelsub !== undefined) { return channelsub.subject.next(ev); } }); } /** * start signalr connection. starting$ stream emit * event if connection established, otherwise emit * error. */ start(): void { // want connection started once, have special // starting$ observable clients can subscribe know know if // if startup sequence done. // // if mapped start() promise observable, time // client subscried start sequence triggered // again since it's cold observable. // this.hubconnection.start() .done(() => { this.startingsubject.next(); }) .fail((error: any) => { this.startingsubject.error(error); }); } /** * observable contain data associated specific * channel * */ sub(channel: string): rx.observable<channelevent> { // try find observable created requested // channel // let channelsub = this.subjects.find((x: channelsubject) => { return x.channel === channel; }) channelsubject; // if have 1 event, return // if (channelsub !== undefined) { console.log(`found existing observable ${channel} channel`) return channelsub.subject.asobservable(); } // // if we're here don't have observable provide // caller, need call server method join channel // , create observable caller can use received // messages. // // create our internal object can track subject // in case else wants // channelsub = new channelsubject(); channelsub.channel = channel; channelsub.subject = new rx.subject<channelevent>(); this.subjects.push(channelsub); // signalr asynchronous, need ensure connection // established before call server methods. we'll subscribe // starting$ stream since won't emit value until connection // ready // this.starting$.subscribe(() => { this.hubproxy.invoke("subscribe", channel) .done(() => { console.log(`successfully subscribed ${channel} channel`); }) .fail((error: any) => { channelsub.subject.error(error); }); }, (error: any) => { channelsub.subject.error(error); }); return channelsub.subject.asobservable(); } // not quite sure how handle (if @ all) since there // more 1 caller subscribed observable created // // unsubscribe(channel: string): rx.observable<any> { // this.observables = this.observables.filter((x: channelobservable) => { // return x.channel === channel; // }); // } /** publish provides way calles emit events on channel. in * production app server ensure authorized clients can * emit message, here we're not concerned that. */ publish(ev: channelevent): void { this.hubproxy.invoke("publish", ev); } }
then component use service subscribing (not in rxjs sense...) specific channel, , reacting specific events emitted:
import {component, oninit, input} "angular2/core"; import {http, response} "angular2/http"; import rx "rxjs/rx"; import {channelservice, channelevent} "./services/channel.service"; class statusevent { state: string; percentcomplete: number; } @component({ selector: 'task', template: ` <div> <h4>task component bound '{{eventname}}'</h4> </div> <div class="commands"> <textarea class="console" cols="50" rows="15" disabled [value]="messages"></textarea> <div class="commands__input"> <button (click)="callapi()">call api</button> </div> </div> ` }) export class taskcomponent implements oninit { @input() eventname: string; @input() apiurl: string; messages = ""; private channel = "tasks"; constructor( private http: http, private channelservice: channelservice ) { } ngoninit() { // observable events emitted on channel // this.channelservice.sub(this.channel).subscribe( (x: channelevent) => { switch (x.name) { case this.eventname: { this.appendstatusupdate(x); } } }, (error: any) => { console.warn("attempt join channel failed!", error); } ) } private appendstatusupdate(ev: channelevent): void { // prepend messages string shown in textarea // let date = new date(); switch (ev.data.state) { case "starting": { this.messages = `${date.tolocaletimestring()} : starting\n` + this.messages; break; } case "complete": { this.messages = `${date.tolocaletimestring()} : complete\n` + this.messages; break; } default: { this.messages = `${date.tolocaletimestring()} : ${ev.data.state} : ${ev.data.percentcomplete} % complete\n` + this.messages; } } } callapi() { this.http.get(this.apiurl) .map((res: response) => res.json()) .subscribe((message: string) => { console.log(message); }); } }
i tried map signalr concepts observables, i'm still learning how use rxjs. in case hope helps show how might work in context of angular 2 app.
Comments
Post a Comment