Angular 2 table 调用连接函数
Angular 2 table invoke connect function
主题:
md-table ui 实现了 Angular Material 2
中的 cdk-table
问题:
在用户调用 http 调用后无法连接发出 returns 响应
方法:
根据服务中的行为主题创建热可观察对象。父组件调用服务中的方法,将对象数组提供给行为主体。子组件在其构造函数中订阅行为主体的热可观察对象。子组件使用新接收的对象数组重新创建对订阅方法中数据源的引用
预期行为:
每次通过 .next() 向行为主体提供新数据时,连接应该触发
观察到的行为:
connect 方法仅在子组件初始化时触发
父组件:
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 );
}
}
服务:
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
)
}
}
子组件:
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() {}
}
我已经简化了一些特定于您的应用程序的细节,但是这
显示如何使用空数据集立即呈现 table,然后获取新数据
在 SearchBarComponent
.
中调用 onSubmit
时来自服务的数据
搜索组件
@Component({ ... })
export class SearchBarComponent {
constructor(private inboundMessagingService: InboundMessagingService) { }
onSubmit(event): void {
this.inboundMessagingService.submitHac(event.target.value);
}
}
服务
@Injectable()
export class InboundMessagingService {
messageDataSubject$ = new BehaviorSubject<Message[]>([]);
get data$(): Observable<Message[]> {
return this.messageDataSubject$.asObservable();
}
constructor(
private http: Http,
private addressBookService: AddressBookService
) { }
submitHac(hac: string): void {
this.getMessages(hac)
.subscribe((messages: Message[]) => this.messageDataSubject$.next(messages));
}
getMessages(hac: string): Observable<Message[]> {
return this.addressBookService
.getMailboxUuids(hac)
.switchMap(x => this.http.get(x))
.map(messagesInResponse => messagesInResponse.map(m => this.createMessage(m)))
}
}
Table分量
@Component({ ... })
export class InboundMessagesComponent {
dataSource: InboundDataSource | null;
displayedColumns = [ ... ];
constructor(private inboundMessagesService: InboundMessagesService) { }
ngOnInit() {
this.dataSource = new InboundDataSource(this.inboundMessagesService);
}
}
export class InboundDataSource extends DataSource<Message> {
constructor(private inboundMessagesService: InboundMessagesService) { }
/**
* This is only called once, when `dataSource` is provided to the md/cdk-table. To
* update the table rows, you must make sure the source observable emits again.
* The way it is setup, this will emit whenever `messageDataSubject$.next()` is called
* in the service.
*/
connect(): Observable<Message[]> {
// Since messageDataSubject$ is a behavior subject, it will immediately emit an empty array
// when subscribed to. This will show as an empty table.
return this.inboundMessagesService.data$;
}
diconnect() { }
}
其他说明
- 很多人喜欢在可观察变量名的末尾加上
$
来区分它们。我有
在这里使用该约定。
- 由于您要将
InboundMessagesService
添加到每个组件提供程序,因此您将
最终得到服务的多个实例。您应该在模块级别提供此服务,
如果您想确保此服务在应用程序的生命周期内只存在 一次,请将其添加到
根模块提供商。
主题:
md-table ui 实现了 Angular Material 2
中的 cdk-table问题:
在用户调用 http 调用后无法连接发出 returns 响应
方法:
根据服务中的行为主题创建热可观察对象。父组件调用服务中的方法,将对象数组提供给行为主体。子组件在其构造函数中订阅行为主体的热可观察对象。子组件使用新接收的对象数组重新创建对订阅方法中数据源的引用
预期行为:
每次通过 .next() 向行为主体提供新数据时,连接应该触发
观察到的行为:
connect 方法仅在子组件初始化时触发
父组件:
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 );
}
}
服务:
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
)
}
}
子组件:
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() {}
}
我已经简化了一些特定于您的应用程序的细节,但是这
显示如何使用空数据集立即呈现 table,然后获取新数据
在 SearchBarComponent
.
onSubmit
时来自服务的数据
搜索组件
@Component({ ... })
export class SearchBarComponent {
constructor(private inboundMessagingService: InboundMessagingService) { }
onSubmit(event): void {
this.inboundMessagingService.submitHac(event.target.value);
}
}
服务
@Injectable()
export class InboundMessagingService {
messageDataSubject$ = new BehaviorSubject<Message[]>([]);
get data$(): Observable<Message[]> {
return this.messageDataSubject$.asObservable();
}
constructor(
private http: Http,
private addressBookService: AddressBookService
) { }
submitHac(hac: string): void {
this.getMessages(hac)
.subscribe((messages: Message[]) => this.messageDataSubject$.next(messages));
}
getMessages(hac: string): Observable<Message[]> {
return this.addressBookService
.getMailboxUuids(hac)
.switchMap(x => this.http.get(x))
.map(messagesInResponse => messagesInResponse.map(m => this.createMessage(m)))
}
}
Table分量
@Component({ ... })
export class InboundMessagesComponent {
dataSource: InboundDataSource | null;
displayedColumns = [ ... ];
constructor(private inboundMessagesService: InboundMessagesService) { }
ngOnInit() {
this.dataSource = new InboundDataSource(this.inboundMessagesService);
}
}
export class InboundDataSource extends DataSource<Message> {
constructor(private inboundMessagesService: InboundMessagesService) { }
/**
* This is only called once, when `dataSource` is provided to the md/cdk-table. To
* update the table rows, you must make sure the source observable emits again.
* The way it is setup, this will emit whenever `messageDataSubject$.next()` is called
* in the service.
*/
connect(): Observable<Message[]> {
// Since messageDataSubject$ is a behavior subject, it will immediately emit an empty array
// when subscribed to. This will show as an empty table.
return this.inboundMessagesService.data$;
}
diconnect() { }
}
其他说明
- 很多人喜欢在可观察变量名的末尾加上
$
来区分它们。我有 在这里使用该约定。 - 由于您要将
InboundMessagesService
添加到每个组件提供程序,因此您将 最终得到服务的多个实例。您应该在模块级别提供此服务, 如果您想确保此服务在应用程序的生命周期内只存在 一次,请将其添加到 根模块提供商。