受试者对 Angular 8 中的过滤数据没有反应
Subject not reacting to filtered datas in Angular 8
首先,我不是前端开发人员。我更擅长后端开发。但是,我必须用 Angular 做一个应用程序(我选择 Angular 8)。
在之前的工作中,我使用了Angular。但这是我第一次必须从头开始创建 Angular 应用程序。
我必须读取、添加、修改和删除对象(称为订阅)。这一切都很好。
除非我希望使用表单进行过滤...
为了在代码中更多,我的页面 HTML 是这样构建的:
subscription.component.html
<div id="subscription-filter">
<app-subscription-filter></app-subscription-filter>
</div>
<div id="subscription-view">
<app-subscription-view></app-subscription-view>
</div>
我遇到问题的地方是 app-subscription-filter 和 app-subscription-view
订阅过滤器部分:
subscription-filter.component.html
<div class="row col-12">
<div class="row col-11">
<label class="col-1" for="selectCRNA">{{filterLabel}} </label>
<select class="col-11 form-control" [(ngModel)]="selectedCRNA">
<option *ngFor="let crna of filterSelection">
{{crna.name}}
</option>
</select>
</div>
<div class="col-1">
<button type="submit" class="btn"><i class="fas fa-search fa-lg" (click)="filterOnCRNAOnly()"></i></button>
</div>
</div>
...
subscription-filter.component.ts
import { Component, OnInit, ViewChild } from '@angular/core';
import { Observable } from 'rxjs';
import { SubscriptionService } from '../../shared/service/subscription.service';
@Component({
selector: 'app-subscription-filter',
templateUrl: './subscription-filter.component.html',
styleUrls: ['./subscription-filter.component.css']
})
export class SubscriptionFilterComponent implements OnInit {
filterLabel: string;
filterSelection: any[];
selectedCRNA: string;
selectedCRNALabel: string;
addSubscriptionForm : FormGroup;
@ViewChild('closebutton', {static: false}) closebutton;
constructor (protected subscriptionService: SubscriptionService) {
}
ngOnInit() {
this.filterLabel = "Filtrer sur le tableau de résultat :";
this.filterSelection = [
{ name: "Tous CRNA", value: "All" },
{ name: "CRNA NORD", value: "CRNA NORD" },
{ name: "CRNA SUD", value: "CRNA SUD" },
{ name: "CRNA EST", value: "CRNA EST" },
{ name: "CRNA OUEST", value: "CRNA OUEST" },
{ name: "CRNA SUD-OUEST", value: "CRNA SUD-OUEST" }
];
}
/**
* Method to filter on CRNA selected
*/
filterOnCRNAOnly() {
console.log(this.selectedCRNA);
this.subscriptionService.onlyCRNAFilterForSubject(this.selectedCRNA);
this.selectedCRNALabel = this.selectedCRNA;
}
}
...
订阅-查看部分:
subscription-view.html
<table class="table table-responsive table-hover" *ngIf="!!subscriptions || isLoadingResults">
<thead>
<tr>
<th *ngFor='let col of tableHeaders'>
{{col.header}}
</th>
</tr>
</thead>
<tbody>
<tr *ngFor='let sub of (subscriptions)'>
<td scope='row'>{{sub.status}}</td>
<td>{{sub.region}}</td>
<td>{{sub.provider}}</td>
<td>{{sub.host}}</td>
<td>{{sub.consumer}}</td>
<td>{{sub.alias}}</td>
<td>{{sub.filters}}</td>
<td>
<i class="fas fa-play mx-1" data-toggle="tooltip" title="Start subscription" (click)="startSubscription(sub, sub.id)"></i>
<i class="fas fa-times mx-1" data-toggle="tooltip" title="Stop subscription" (click)="stopSubscription(sub, sub.id)"></i>
<i class="fas fa-trash mx-1" data-toggle="tooltip" title="Delete subscription" (click)="deleteSubscription(sub.id)"></i>
</td>
<td></td>
</tr>
</tbody>
</table>
subscription-component.ts
import { Component, OnInit } from '@angular/core';
import { SubscriptionModel } from '../../shared/model/subscription.model';
import { SubscriptionService } from '../../shared/service/subscription.service';
@Component({
selector: 'app-subscription-view',
templateUrl: './subscription-view.component.html',
styleUrls: ['./subscription-view.component.less']
})
export class SubscriptionViewComponent implements OnInit {
subscriptions: SubscriptionModel[] = [];
tableHeaders: any[];
isLoadingResults = true;
copiedSubscription: SubscriptionModel;
constructor(protected subscriptionService: SubscriptionService) { }
ngOnInit() {
this.tableHeaders = [
{field: 'status', header: 'Status'},
{field: 'region', header: 'Region'},
{field: 'provider', header: 'Fournisseur'},
{field: 'host', header: 'Bus'},
{field: 'consumer', header: 'Consommateur'},
{field: 'alias', header: 'Alias'},
{field: 'filters', header: 'Abonnement'},
{field: '', header: 'Actions'},
{field: '', header: 'Selections'}
];
this.copiedSubscription = new SubscriptionModel();
this.loadAll();
}
/**
* Method to load all subscriptions
*/
loadAll() {
this.subscriptionService.initializeSubscriptions().subscribe((res: any) => {
this.subscriptions = res;
this.isLoadingResults = false;
})
}
/**
* Method to start a subscription
* @param sub
* @param id
*/
startSubscription(sub: SubscriptionModel, id: string) {
if (sub.status !== "OK") {
this.subscriptionService.changeSubscriptionStatus(id, "ON");
}
}
/**
* Method to stop a subscription
* @param sub
* @param id
*/
stopSubscription(sub: SubscriptionModel, id: string) {
if (sub.status === "OK") {
this.subscriptionService.changeSubscriptionStatus(id, "Off");
}
}
/**
* Method to delete a subscription
* @param id
*/
deleteSubscription(id: string) {
this.subscriptionService.deleteSubscription(id);
}
}
我(目前)没有任何服务器调用。我所有的数据都用 JSON 文件模拟。
而必须显示的数据是test$;
subscription.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpResponse } from '@angular/common/http';
import { Subject, Observable, of } from 'rxjs';
import { tap, filter, map, catchError } from 'rxjs/operators';
import { History } from '../model/history.model';
import { SubscriptionModel } from '../model/subscription.model';
import { Hosting } from '../model/hosting.model';
@Injectable({
providedIn: 'root'
})
export class SubscriptionService {
mockHostingUrl: string = 'assets/jsontests/hostmockdata.json';
mockSubscribeUrl: string = 'assets/jsontests/subscriptionsmockdata.json';
private test$: Subject<SubscriptionModel[]> = new Subject<SubscriptionModel[]>();
private subsTest: SubscriptionModel[] = [];
copiedSub: SubscriptionModel;
crnaSelected: string = "Tous CRNA";
constructor(private http: HttpClient) { }
private handleError<T>(operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
// TODO: send the error to remote logging infrastructure
console.error(error); // log to console instead
// Let the app keep running by returning an empty result.
return of(result as T);
};
}
/**
* Method to initialize subscriptions
*/
initializeSubscriptions() : Observable<SubscriptionModel[]> {
return this.http.get<SubscriptionModel[]>(this.mockSubscribeUrl).pipe(tap((subs => {
this.subsTest = subs;
this.test$.next(this.subsTest);
})));
}
/**
* Method for adding a new subscription
* @param sub
*/
addSubscription(sub: SubscriptionModel) {
this.subsTest.push(sub);
this.test$.next(this.subsTest);
}
/**
* Method for changing subscription's status
* @param id
* @param changeStatus
*/
changeSubscriptionStatus(id: string, changeStatus: string) {
this.subsTest.find(element => {
if (element.id === id) {
element.status = changeStatus;
}
});
this.test$.next(this.subsTest);
}
/**
* Method to delete a subscription
* @param id
*/
deleteSubscription(id: string) {
this.subsTest.splice(this.subsTest.findIndex(element => element.id === id), 1);
this.test$.next(this.subsTest);
}
/**
* Method where there is the problem. It must filter and sending
* @param crnaSelected
*/
onlyCRNAFilterForSubject(crnaSelected: string) {
console.log("dans onlyCRNAFilter");
this.crnaSelected = crnaSelected;
if (crnaSelected !== "Tous CRNA") {
/*
var temp = this.subsTest.filter(element => {
element.region.includes(crnaSelected)
});
*/
console.log(this.subsTest);
var temp: SubscriptionModel[] = [];
this.subsTest.filter(
element => {
console.log("---");
console.log(element);
if (element.region.includes(crnaSelected)) {
temp.push(element);
console.log("dedans!");
}
}
);
console.log("apres fonction");
console.log(temp);
this.test$.next(temp);
} else {
console.log(this.subsTest);
this.test$.next(this.subsTest);
}
}
}
当我尝试过滤我的 table 时,我确实有正确的数据,但我的 HTML 没有刷新正确的数据
Logger for debug
我必须承认我不知道该怎么做了...所以,一点帮助将不胜感激。
提前致谢。
(对不起我的英语,这不是我的母语)
update, this solution works only if the two components are not rendered in the same time
在订阅视图组件中,你只在服务中订阅初始化方法
因此,如果服务中的 onlyCRNAFilterForSubject 方法发生了一些变化,您将不会意识到
我们可以在服务中添加一个布尔值属性来指示我们是否处于过滤模式,并在我们调用服务时在订阅过滤器组件中设置这个属性
因此,如果我们处于过滤模式,我们可以订阅 test$ observable,而不是一直订阅 initialize 方法
所以在服务中我们需要像那样定义一个新的布尔值 属性
isFilteringMode: Boolean = false; // set it initailly to false, to get all the data once the component is loaded at the first time
并且在订阅过滤器组件中,一旦某些 CRNA selected
,我们需要将此 属性 设置为 true
filterOnCRNAOnly() {
console.log(this.selectedCRNA);
this.subscriptionService.isFilteringMode = true; // enable the filtering mode
this.subscriptionService.onlyCRNAFilterForSubject(this.selectedCRNA);
this.selectedCRNALabel = this.selectedCRNA;
}
在订阅视图组件中,在初始化模式下,我们会订阅returns整个数组的服务函数,当某些CRNA被selected(过滤模式)时,我们可以订阅到 test$ observable,
所以在订阅视图组件中,它会是这样的
ngOnInit() {
this.tableHeaders = [
{ field: 'status', header: 'Status' },
{ field: 'region', header: 'Region' },
{ field: 'provider', header: 'Fournisseur' },
{ field: 'host', header: 'Bus' },
{ field: 'consumer', header: 'Consommateur' },
{ field: 'alias', header: 'Alias' },
{ field: 'filters', header: 'Abonnement' },
{ field: '', header: 'Actions' },
{ field: '', header: 'Selections' }
];
this.copiedSubscription = new SubscriptionModel();
this.loadAll();
}
/**
* Method to load all subscriptions
*/
loadAll() {
if (this.subscriptionService.isFilteringMode) {
// we are in the filtering mode
// here we will subscribe to test$ observable to get the filtered data
this.subscriptionService.test$.subscribe((res: any) => {
this.subscriptions = res;
this.isLoadingResults = false;
});
} else {
// we are not in the filtering mode
// so get all the data
this.subscriptionService.initializeSubscriptions().subscribe((res: any) => {
this.subscriptions = res;
this.isLoadingResults = false;
})
}
}
Update, here is a similar mini-project like your one
这里我们有一个列表组件,它列出了一些用户,还有一个过滤器组件,用于select一些状态来过滤列表组件中的候选人
我们可以使用 BehaviorSubject
将 selected 状态从过滤器组件传送到列表组件
BehaviorSubject
在这种情况下非常有用,因为它拥有一个初始值,我们不需要等到订阅它才能获得值
在这里你可以找到不同之处
这是文件
app.component.html
<div class="row container">
<div class=" row col-md-12">
<div id="subscription-filter">
<app-candidates-filter></app-candidates-filter>
</div>
</div>
<div class="row col-md-12" style="margin-top: 30px;">
<div id="subscription-view">
<app-candidates-list></app-candidates-list>
</div>
</div>
</div>
候选人-list.component.ts
import { Component, OnInit } from '@angular/core';
import { SharedService } from '../shared.service';
import { User } from '../user.model';
@Component({
selector: 'app-candidates-list',
templateUrl: './candidates-list.component.html',
styleUrls: ['./candidates-list.component.css']
})
export class CandidatesListComponent implements OnInit {
originalCandidatesList: User[];
candidatesList: User[];
constructor(private sharedService: SharedService) { }
ngOnInit() {
console.log('in candidates list component');
this.sharedService.selectedStatusObs.subscribe((selectedStatus: number) => { // subscribe to the selected status first
console.log(selectedStatus);
if (!selectedStatus) {
// no status has been selected
console.log('no status selected');
this.sharedService.getAllCandidatesV2().subscribe((res: User[]) => { // get all the users from the service
// console.log(res);
// console.log(typeof(res));
this.originalCandidatesList = res;
this.candidatesList = res;
});
} else {
// some status has been selected
console.log('some status selected >>> ', this.sharedService.statuses);
const selectedStatusObj = this.sharedService.statuses.find(item => item.code === +selectedStatus);
console.log('selectedStatusObj >>> ', selectedStatusObj);
// just getting the selected status candidates
this.candidatesList = this.originalCandidatesList.filter(item => item.status === selectedStatusObj.name);
}
});
}
}
候选人-list.component.html
<table class="table table-responsive table-hover">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email Address</th>
<th>Age</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr *ngFor='let can of candidatesList'>
<td>{{ can.firstName }}</td>
<td>{{ can.lastName }}</td>
<td>{{ can.emailAddress }}</td>
<td>{{ can.age }} years</td>
<td>{{ can.status }}</td>
</tr>
</tbody>
</table>
候选人-filter.component.ts
import { Component, OnInit } from '@angular/core';
import { SharedService } from '../shared.service';
@Component({
selector: 'app-candidates-filter',
templateUrl: './candidates-filter.component.html',
styleUrls: ['./candidates-filter.component.css']
})
export class CandidatesFilterComponent implements OnInit {
statuses = [];
selectedStatus: number;
constructor(private sharedService: SharedService) { }
ngOnInit() {
console.log('in candidates filter component');
this.statuses = this.sharedService.statuses;
}
filterCandidates() {
console.log(this.selectedStatus);
this.sharedService.selectedStatusObs.next(this.selectedStatus);
};
resetFilters() {
// emil null to the selectedStatus Observable
this.sharedService.selectedStatusObs.next(null);
}
}
候选人-filter.component.html
<div class="row col-xs-12">
<div class="row col-xs-8">
<label class="col-xs-3">Select Status </label>
<select class="col-xs-9 form-control" [(ngModel)]="selectedStatus">
<option *ngFor="let status of statuses" [value]="status.code">
{{ status.name }}
</option>
</select>
</div>
<div class="col-xs-4" style="margin-top: 25px;">
<button type="submit" class="btn btn-primary" (click)="filterCandidates()">Search</button>
<button type="submit" class="btn btn-default" (click)="resetFilters()">Reset</button>
</div>
</div>
shared.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject, of } from 'rxjs';
import { User } from './user.model';
@Injectable({ providedIn: 'root' })
export class SharedService {
selectedStatusObs = new BehaviorSubject<number>(null); // this is the observable to watch the selected status in the filter component
candidates: User[] = [ // a list of users
{
firstName: 'Thierry',
lastName: 'Henry',
emailAddress: 'henry@test.com',
age: 1,
status: 'Active'
},
{
firstName: 'Alexis',
lastName: 'Sanchez',
emailAddress: 'sanchez@test.com',
age: 28,
status: 'Idle'
},
{
firstName: 'Denis',
lastName: 'Bergkamp',
emailAddress: 'Bbrgkamp@test.com',
age: 29,
status: 'Active'
},
{
firstName: 'Jerman',
lastName: 'Defoe',
emailAddress: 'defoe@test.com',
age: 22,
status: 'Active'
},
{
firstName: 'Kun',
lastName: 'Aguero',
emailAddress: 'aguero@test.com',
age: 25,
status: 'Offline'
},
];
statuses = [
{
code: 1,
name: 'Active'
},
{
code: 2,
name: 'Offline'
},
{
code: 3,
name: 'Idle'
}
]
getAllCandidatesV2() {
return of(this.candidates); // trying to mock the HTTP request via this 'of' observable
}
}
user.model.ts
export class User {
constructor(
public firstName: String,
public lastName: String,
public emailAddress: String,
public age: Number,
public status: String
) { }
}
首先,我不是前端开发人员。我更擅长后端开发。但是,我必须用 Angular 做一个应用程序(我选择 Angular 8)。 在之前的工作中,我使用了Angular。但这是我第一次必须从头开始创建 Angular 应用程序。
我必须读取、添加、修改和删除对象(称为订阅)。这一切都很好。
除非我希望使用表单进行过滤...
为了在代码中更多,我的页面 HTML 是这样构建的:
subscription.component.html
<div id="subscription-filter">
<app-subscription-filter></app-subscription-filter>
</div>
<div id="subscription-view">
<app-subscription-view></app-subscription-view>
</div>
我遇到问题的地方是 app-subscription-filter 和 app-subscription-view
订阅过滤器部分:
subscription-filter.component.html
<div class="row col-12">
<div class="row col-11">
<label class="col-1" for="selectCRNA">{{filterLabel}} </label>
<select class="col-11 form-control" [(ngModel)]="selectedCRNA">
<option *ngFor="let crna of filterSelection">
{{crna.name}}
</option>
</select>
</div>
<div class="col-1">
<button type="submit" class="btn"><i class="fas fa-search fa-lg" (click)="filterOnCRNAOnly()"></i></button>
</div>
</div>
...
subscription-filter.component.ts
import { Component, OnInit, ViewChild } from '@angular/core';
import { Observable } from 'rxjs';
import { SubscriptionService } from '../../shared/service/subscription.service';
@Component({
selector: 'app-subscription-filter',
templateUrl: './subscription-filter.component.html',
styleUrls: ['./subscription-filter.component.css']
})
export class SubscriptionFilterComponent implements OnInit {
filterLabel: string;
filterSelection: any[];
selectedCRNA: string;
selectedCRNALabel: string;
addSubscriptionForm : FormGroup;
@ViewChild('closebutton', {static: false}) closebutton;
constructor (protected subscriptionService: SubscriptionService) {
}
ngOnInit() {
this.filterLabel = "Filtrer sur le tableau de résultat :";
this.filterSelection = [
{ name: "Tous CRNA", value: "All" },
{ name: "CRNA NORD", value: "CRNA NORD" },
{ name: "CRNA SUD", value: "CRNA SUD" },
{ name: "CRNA EST", value: "CRNA EST" },
{ name: "CRNA OUEST", value: "CRNA OUEST" },
{ name: "CRNA SUD-OUEST", value: "CRNA SUD-OUEST" }
];
}
/**
* Method to filter on CRNA selected
*/
filterOnCRNAOnly() {
console.log(this.selectedCRNA);
this.subscriptionService.onlyCRNAFilterForSubject(this.selectedCRNA);
this.selectedCRNALabel = this.selectedCRNA;
}
}
...
订阅-查看部分:
subscription-view.html
<table class="table table-responsive table-hover" *ngIf="!!subscriptions || isLoadingResults">
<thead>
<tr>
<th *ngFor='let col of tableHeaders'>
{{col.header}}
</th>
</tr>
</thead>
<tbody>
<tr *ngFor='let sub of (subscriptions)'>
<td scope='row'>{{sub.status}}</td>
<td>{{sub.region}}</td>
<td>{{sub.provider}}</td>
<td>{{sub.host}}</td>
<td>{{sub.consumer}}</td>
<td>{{sub.alias}}</td>
<td>{{sub.filters}}</td>
<td>
<i class="fas fa-play mx-1" data-toggle="tooltip" title="Start subscription" (click)="startSubscription(sub, sub.id)"></i>
<i class="fas fa-times mx-1" data-toggle="tooltip" title="Stop subscription" (click)="stopSubscription(sub, sub.id)"></i>
<i class="fas fa-trash mx-1" data-toggle="tooltip" title="Delete subscription" (click)="deleteSubscription(sub.id)"></i>
</td>
<td></td>
</tr>
</tbody>
</table>
subscription-component.ts
import { Component, OnInit } from '@angular/core';
import { SubscriptionModel } from '../../shared/model/subscription.model';
import { SubscriptionService } from '../../shared/service/subscription.service';
@Component({
selector: 'app-subscription-view',
templateUrl: './subscription-view.component.html',
styleUrls: ['./subscription-view.component.less']
})
export class SubscriptionViewComponent implements OnInit {
subscriptions: SubscriptionModel[] = [];
tableHeaders: any[];
isLoadingResults = true;
copiedSubscription: SubscriptionModel;
constructor(protected subscriptionService: SubscriptionService) { }
ngOnInit() {
this.tableHeaders = [
{field: 'status', header: 'Status'},
{field: 'region', header: 'Region'},
{field: 'provider', header: 'Fournisseur'},
{field: 'host', header: 'Bus'},
{field: 'consumer', header: 'Consommateur'},
{field: 'alias', header: 'Alias'},
{field: 'filters', header: 'Abonnement'},
{field: '', header: 'Actions'},
{field: '', header: 'Selections'}
];
this.copiedSubscription = new SubscriptionModel();
this.loadAll();
}
/**
* Method to load all subscriptions
*/
loadAll() {
this.subscriptionService.initializeSubscriptions().subscribe((res: any) => {
this.subscriptions = res;
this.isLoadingResults = false;
})
}
/**
* Method to start a subscription
* @param sub
* @param id
*/
startSubscription(sub: SubscriptionModel, id: string) {
if (sub.status !== "OK") {
this.subscriptionService.changeSubscriptionStatus(id, "ON");
}
}
/**
* Method to stop a subscription
* @param sub
* @param id
*/
stopSubscription(sub: SubscriptionModel, id: string) {
if (sub.status === "OK") {
this.subscriptionService.changeSubscriptionStatus(id, "Off");
}
}
/**
* Method to delete a subscription
* @param id
*/
deleteSubscription(id: string) {
this.subscriptionService.deleteSubscription(id);
}
}
我(目前)没有任何服务器调用。我所有的数据都用 JSON 文件模拟。 而必须显示的数据是test$;
subscription.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpResponse } from '@angular/common/http';
import { Subject, Observable, of } from 'rxjs';
import { tap, filter, map, catchError } from 'rxjs/operators';
import { History } from '../model/history.model';
import { SubscriptionModel } from '../model/subscription.model';
import { Hosting } from '../model/hosting.model';
@Injectable({
providedIn: 'root'
})
export class SubscriptionService {
mockHostingUrl: string = 'assets/jsontests/hostmockdata.json';
mockSubscribeUrl: string = 'assets/jsontests/subscriptionsmockdata.json';
private test$: Subject<SubscriptionModel[]> = new Subject<SubscriptionModel[]>();
private subsTest: SubscriptionModel[] = [];
copiedSub: SubscriptionModel;
crnaSelected: string = "Tous CRNA";
constructor(private http: HttpClient) { }
private handleError<T>(operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
// TODO: send the error to remote logging infrastructure
console.error(error); // log to console instead
// Let the app keep running by returning an empty result.
return of(result as T);
};
}
/**
* Method to initialize subscriptions
*/
initializeSubscriptions() : Observable<SubscriptionModel[]> {
return this.http.get<SubscriptionModel[]>(this.mockSubscribeUrl).pipe(tap((subs => {
this.subsTest = subs;
this.test$.next(this.subsTest);
})));
}
/**
* Method for adding a new subscription
* @param sub
*/
addSubscription(sub: SubscriptionModel) {
this.subsTest.push(sub);
this.test$.next(this.subsTest);
}
/**
* Method for changing subscription's status
* @param id
* @param changeStatus
*/
changeSubscriptionStatus(id: string, changeStatus: string) {
this.subsTest.find(element => {
if (element.id === id) {
element.status = changeStatus;
}
});
this.test$.next(this.subsTest);
}
/**
* Method to delete a subscription
* @param id
*/
deleteSubscription(id: string) {
this.subsTest.splice(this.subsTest.findIndex(element => element.id === id), 1);
this.test$.next(this.subsTest);
}
/**
* Method where there is the problem. It must filter and sending
* @param crnaSelected
*/
onlyCRNAFilterForSubject(crnaSelected: string) {
console.log("dans onlyCRNAFilter");
this.crnaSelected = crnaSelected;
if (crnaSelected !== "Tous CRNA") {
/*
var temp = this.subsTest.filter(element => {
element.region.includes(crnaSelected)
});
*/
console.log(this.subsTest);
var temp: SubscriptionModel[] = [];
this.subsTest.filter(
element => {
console.log("---");
console.log(element);
if (element.region.includes(crnaSelected)) {
temp.push(element);
console.log("dedans!");
}
}
);
console.log("apres fonction");
console.log(temp);
this.test$.next(temp);
} else {
console.log(this.subsTest);
this.test$.next(this.subsTest);
}
}
}
当我尝试过滤我的 table 时,我确实有正确的数据,但我的 HTML 没有刷新正确的数据
Logger for debug
我必须承认我不知道该怎么做了...所以,一点帮助将不胜感激。
提前致谢。
(对不起我的英语,这不是我的母语)
update, this solution works only if the two components are not rendered in the same time
在订阅视图组件中,你只在服务中订阅初始化方法
因此,如果服务中的 onlyCRNAFilterForSubject 方法发生了一些变化,您将不会意识到
我们可以在服务中添加一个布尔值属性来指示我们是否处于过滤模式,并在我们调用服务时在订阅过滤器组件中设置这个属性
因此,如果我们处于过滤模式,我们可以订阅 test$ observable,而不是一直订阅 initialize 方法
所以在服务中我们需要像那样定义一个新的布尔值 属性
isFilteringMode: Boolean = false; // set it initailly to false, to get all the data once the component is loaded at the first time
并且在订阅过滤器组件中,一旦某些 CRNA selected
,我们需要将此 属性 设置为 truefilterOnCRNAOnly() {
console.log(this.selectedCRNA);
this.subscriptionService.isFilteringMode = true; // enable the filtering mode
this.subscriptionService.onlyCRNAFilterForSubject(this.selectedCRNA);
this.selectedCRNALabel = this.selectedCRNA;
}
在订阅视图组件中,在初始化模式下,我们会订阅returns整个数组的服务函数,当某些CRNA被selected(过滤模式)时,我们可以订阅到 test$ observable,
所以在订阅视图组件中,它会是这样的
ngOnInit() {
this.tableHeaders = [
{ field: 'status', header: 'Status' },
{ field: 'region', header: 'Region' },
{ field: 'provider', header: 'Fournisseur' },
{ field: 'host', header: 'Bus' },
{ field: 'consumer', header: 'Consommateur' },
{ field: 'alias', header: 'Alias' },
{ field: 'filters', header: 'Abonnement' },
{ field: '', header: 'Actions' },
{ field: '', header: 'Selections' }
];
this.copiedSubscription = new SubscriptionModel();
this.loadAll();
}
/**
* Method to load all subscriptions
*/
loadAll() {
if (this.subscriptionService.isFilteringMode) {
// we are in the filtering mode
// here we will subscribe to test$ observable to get the filtered data
this.subscriptionService.test$.subscribe((res: any) => {
this.subscriptions = res;
this.isLoadingResults = false;
});
} else {
// we are not in the filtering mode
// so get all the data
this.subscriptionService.initializeSubscriptions().subscribe((res: any) => {
this.subscriptions = res;
this.isLoadingResults = false;
})
}
}
Update, here is a similar mini-project like your one
这里我们有一个列表组件,它列出了一些用户,还有一个过滤器组件,用于select一些状态来过滤列表组件中的候选人
我们可以使用 BehaviorSubject
将 selected 状态从过滤器组件传送到列表组件
BehaviorSubject
在这种情况下非常有用,因为它拥有一个初始值,我们不需要等到订阅它才能获得值
在这里你可以找到不同之处
这是文件
app.component.html
<div class="row container">
<div class=" row col-md-12">
<div id="subscription-filter">
<app-candidates-filter></app-candidates-filter>
</div>
</div>
<div class="row col-md-12" style="margin-top: 30px;">
<div id="subscription-view">
<app-candidates-list></app-candidates-list>
</div>
</div>
</div>
候选人-list.component.ts
import { Component, OnInit } from '@angular/core';
import { SharedService } from '../shared.service';
import { User } from '../user.model';
@Component({
selector: 'app-candidates-list',
templateUrl: './candidates-list.component.html',
styleUrls: ['./candidates-list.component.css']
})
export class CandidatesListComponent implements OnInit {
originalCandidatesList: User[];
candidatesList: User[];
constructor(private sharedService: SharedService) { }
ngOnInit() {
console.log('in candidates list component');
this.sharedService.selectedStatusObs.subscribe((selectedStatus: number) => { // subscribe to the selected status first
console.log(selectedStatus);
if (!selectedStatus) {
// no status has been selected
console.log('no status selected');
this.sharedService.getAllCandidatesV2().subscribe((res: User[]) => { // get all the users from the service
// console.log(res);
// console.log(typeof(res));
this.originalCandidatesList = res;
this.candidatesList = res;
});
} else {
// some status has been selected
console.log('some status selected >>> ', this.sharedService.statuses);
const selectedStatusObj = this.sharedService.statuses.find(item => item.code === +selectedStatus);
console.log('selectedStatusObj >>> ', selectedStatusObj);
// just getting the selected status candidates
this.candidatesList = this.originalCandidatesList.filter(item => item.status === selectedStatusObj.name);
}
});
}
}
候选人-list.component.html
<table class="table table-responsive table-hover">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email Address</th>
<th>Age</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr *ngFor='let can of candidatesList'>
<td>{{ can.firstName }}</td>
<td>{{ can.lastName }}</td>
<td>{{ can.emailAddress }}</td>
<td>{{ can.age }} years</td>
<td>{{ can.status }}</td>
</tr>
</tbody>
</table>
候选人-filter.component.ts
import { Component, OnInit } from '@angular/core';
import { SharedService } from '../shared.service';
@Component({
selector: 'app-candidates-filter',
templateUrl: './candidates-filter.component.html',
styleUrls: ['./candidates-filter.component.css']
})
export class CandidatesFilterComponent implements OnInit {
statuses = [];
selectedStatus: number;
constructor(private sharedService: SharedService) { }
ngOnInit() {
console.log('in candidates filter component');
this.statuses = this.sharedService.statuses;
}
filterCandidates() {
console.log(this.selectedStatus);
this.sharedService.selectedStatusObs.next(this.selectedStatus);
};
resetFilters() {
// emil null to the selectedStatus Observable
this.sharedService.selectedStatusObs.next(null);
}
}
候选人-filter.component.html
<div class="row col-xs-12">
<div class="row col-xs-8">
<label class="col-xs-3">Select Status </label>
<select class="col-xs-9 form-control" [(ngModel)]="selectedStatus">
<option *ngFor="let status of statuses" [value]="status.code">
{{ status.name }}
</option>
</select>
</div>
<div class="col-xs-4" style="margin-top: 25px;">
<button type="submit" class="btn btn-primary" (click)="filterCandidates()">Search</button>
<button type="submit" class="btn btn-default" (click)="resetFilters()">Reset</button>
</div>
</div>
shared.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject, of } from 'rxjs';
import { User } from './user.model';
@Injectable({ providedIn: 'root' })
export class SharedService {
selectedStatusObs = new BehaviorSubject<number>(null); // this is the observable to watch the selected status in the filter component
candidates: User[] = [ // a list of users
{
firstName: 'Thierry',
lastName: 'Henry',
emailAddress: 'henry@test.com',
age: 1,
status: 'Active'
},
{
firstName: 'Alexis',
lastName: 'Sanchez',
emailAddress: 'sanchez@test.com',
age: 28,
status: 'Idle'
},
{
firstName: 'Denis',
lastName: 'Bergkamp',
emailAddress: 'Bbrgkamp@test.com',
age: 29,
status: 'Active'
},
{
firstName: 'Jerman',
lastName: 'Defoe',
emailAddress: 'defoe@test.com',
age: 22,
status: 'Active'
},
{
firstName: 'Kun',
lastName: 'Aguero',
emailAddress: 'aguero@test.com',
age: 25,
status: 'Offline'
},
];
statuses = [
{
code: 1,
name: 'Active'
},
{
code: 2,
name: 'Offline'
},
{
code: 3,
name: 'Idle'
}
]
getAllCandidatesV2() {
return of(this.candidates); // trying to mock the HTTP request via this 'of' observable
}
}
user.model.ts
export class User {
constructor(
public firstName: String,
public lastName: String,
public emailAddress: String,
public age: Number,
public status: String
) { }
}