Topic:
md-table ui that implements the cdk-table in Angular Material 2
Problem:
unable to get connect to emit after a user-invoked http call returns a response
Approach:
create a hot observable out of a behavior subject in a service. parent component invokes a method in the service that feeds an array of objects into the behavior subject. the child component subscribes to the behavior subject's hot observable in it's constructor. the child component recreates the reference to the datasource in the subscription method with the newly received array of objects
Expected Behavior:
each time the behavior subject is fed new data via .next(), connect should fire
Observed Behavior:
the connect method fires only on initialization of the child component
Parent Component:
import { Component } from '@angular/core';
import { InboundMessagesService } from '../messages/services/inbound/inbound.service';
import { Message } from '../messages/model/message';
@Component({
selector: 'search-bar',
templateUrl: './search-bar.component.html',
styleUrls: [ './search-bar.component.css'],
providers: [ InboundMessagesService ]
})
export class SearchBarComponent {
hac: string = "";
constructor( private inboundMessagesService: InboundMessagesService ) { }
onSubmit( event: any ): void {
this.hac = event.target.value;
this.inboundMessagesService.submitHac( this.hac );
}
}
Service:
import { Injectable } from '@angular/core';
import { Headers,
Http,
RequestMethod,
RequestOptions,
Response } from '@angular/http';
import { HttpErrorResponse } from "@angular/common/http";
import { Observable } from 'rxjs/Rx';
import { Subject } from 'rxjs/Subject';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { ReplaySubject } from 'rxjs/ReplaySubject';
import { Subscription } from 'rxjs/Subscription';
import "rxjs/add/operator/mergeMap";
import { Message } from '../../model/message';
import { LookupService } from '../../../lookup/lookup.service';
@Injectable()
export class InboundMessagesService {
dataChange: BehaviorSubject<Message[]> = new BehaviorSubject<Message[]>([]);
dataChangeObservable = Observable.from( this.dataChange ).publish();
messages: Message[];
get data(): Message[] {
return this.dataChange.value;
}
baseUrl: string = 'http://foobar/query?parameter=';
headers = new Headers();
options = new RequestOptions({ headers: this.headers });
response: Observable<Response>;
constructor( private http: Http,
private lookupService: LookupService ) {
console.log( "inboundService constructor - dataChange: ", this.dataChange );
this.dataChangeObservable.connect()
}
submitHac( hac: string ) {
console.log( "submitHac received: ", hac );
this.getMessages( hac )
.subscribe( ( messages: any ) => {
this.dataChange.next( messages )
}),
( err: HttpErrorResponse ) => {
if ( err.error instanceof Error ) {
// A client-side or network error occurred. Handle it accordingly.
console.log( 'An error occurred:', err.error.message );
} else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
console.log( `Backend returned code ${ err.status }, body was: ${ err.error }` );
console.log( "full error: ", err );
}
};
}
getMessages( hac: string ) {
console.log( "inboundService.getMessages( hac ) got: ", hac );
return this.lookupService
.getMailboxUuids( hac )
.switchMap(
( mailboxUuidsInResponse: Response ) => {
console.log( "lookup service returned: ", mailboxUuidsInResponse );
return this.http.get( this.baseUrl + mailboxUuidsInResponse.json(), this.options )
})
.map(
( messagesInResponse: any ) => {
console.log( "request returned these messages: ", messagesInResponse );
messagesInResponse.forEach(
(message: any ) => {
this.messages.push(
this.createMessage( message )
)});
return this.messages;
})
}
createMessage( message: any ): Message {
return new Message(
message.name,
message.type,
message.contentType,
message.state,
message.source,
message.target,
message.additionalData
)
}
}
Child Component:
import { Component } from '@angular/core';
import { HttpErrorResponse } from "@angular/common/http";
import { DataSource, CdkTable } from '@angular/cdk';
import { Observable } from 'rxjs/Observable';
import { Message } from '../../../messages/model/message';
import { InboundMessagesService } from '../../../messages/services/inbound/inbound.service';
import { SearchBarComponent } from '../../../search_bar/search-bar.component';
@Component({
selector: 'inbound-messages',
templateUrl: './../inbound-messages.component.html',
styleUrls: [
'app/mailboxes/mailboxes-layout.css',
'./../inbound-messages.component.css'
],
providers: [ InboundMessagesService ]
})
export class InboundMessagesComponent {
dataSource: InboundDataSource | null;
displayedColumns = [ 'name', 'type', 'contentType', 'state', 'source', 'target', 'additionalData' ];
constructor( private inboundMessagesService: InboundMessagesService ) {
console.log( "inbound component constructor (this): ", this );
this.inboundMessagesService.dataChangeObservable.connect();
}
ngOnInit() {
console.log( "inbound component ngOnInit()" );
this.dataSource = new InboundDataSource( this.inboundMessagesService );
}
}
export class InboundDataSource extends DataSource<Message> {
constructor( private inboundMessagesService: InboundMessagesService ) {
super();
console.log( "InboundDataSource constructor" );
}
connect(): Observable<Message[]> {
console.log( "CONNECT called" );
return this.inboundMessagesService.dataChangeObservable
}
disconnect() {}
}