问题
My app has listing of tiles that when clicked on will display in a dashboard. In the dashboard, when a tile is clicked, the tile details show below the dashboard (not unlike tour-of-heroes).
I’m using RxJS Subject in a service to communicate successfully between Component A (available snippets), Component B (the dashboard), and the Component C (snippet details).
The problem is that when I click on the one of the listings on component A, not only does it populate the dashboard like it should but also populates the details (Component C). I only want the details to be populated when the tile is clicked on in the dashboard - yes, the details do successfully populate when a dashboard tile is clicked.
All 3 components are siblings residing in app.component.html.
I do not want parent-child relationships - hence using Subject
instead of @Inupt
.
The service:
@Injectable()
export class SnippetService {
tile = new Subject<any>();
constructor() { }
getSnippets(): Observable<Snippet[]> {
return of (SNIPPETS);
}
addTile(data) {
this.tile.next(data);
}
}
Component A (available tiles/snippets):
@Component({
selector: 'app-available-snippets',
templateUrl: './available-snippets.component.html',
styleUrls: ['./available-snippets.component.css']
})
export class AvailableSnippetsComponent implements OnInit {
snippets: Snippet[];
constructor(private snippetService: SnippetService) { }
ngOnInit() {
this.getSnippets();
}
getSnippets(): void {
this.snippetService.getSnippets().subscribe(x => this.snippets = x);
}
onAddTile(data) {
this.snippetService.addTile(data);
}
}
Component B (The dashboard):
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit {
selectedSnippet: Snippet;
addedSnippets = [];
// Inject the SnippetService
constructor(private snippetService: SnippetService) { }
ngOnInit() {
this.snippetService.tile.subscribe(x => this.addToDashboard(x));
}
addToDashboard(s: Snippet) {
if (this.addedSnippets.indexOf(s) === -1) {
this.addedSnippets.push(s);
}
}
displayDetails(s: Snippet) {
this.snippetService.addTile(s);
}
}
Component C (snippet details)
@Component({
selector: 'app-snippet-detail',
templateUrl: './snippet-detail.component.html',
styleUrls: ['./snippet-detail.component.css']
})
export class SnippetDetailComponent implements OnInit {
snippet: Snippet;
constructor(private snippetService: SnippetService) { }
ngOnInit() {
this.snippetService.tile.subscribe(x => this.snippet = x);
}
}
Component C Template:
<div class="snippet-detail" *ngIf="snippet">
<hr>
<h2>{{ snippet.title }} </h2>
<div>{{snippet.description}}</div>
<code>{{snippet.code.example1}}</code>
<code>{{snippet.code.example2}}</code>
<code>{{snippet.code.example3}}</code>
</div>
So the the culprit is between the ngOnInit{}
in Component C and the *ngIf="snippet
" on C's view. I tried passing additional booleans from the service but the problem is that I need the state of those bools to be in a lifecycle loop.
So a RxJS'y way of doing this?
回答1:
The service:
@Injectable()
export class SnippetService {
tile = new Subject<any>();
details = new Subject<any>();
constructor() { }
getSnippets(): Observable<Snippet[]> {
return of (SNIPPETS);
}
addTile(data) {
this.tile.next(data);
}
showDetails(data) {
this.details.next(data);
}
}
Component B (Dashboard) now passes the snippet to the snippet.service showDetails()
method:
displayDetails(s: Snippet) {
this.snippetService.showDetails(s);
}
Component C (details) now subscribes to the details subject and assigns the result to C's snippet property:
ngOnInit() {
this.snippetService.details.subscribe(x => this.snippet = x);
}
来源:https://stackoverflow.com/questions/49889376/angular-5-sibling-component-communication-using-rxjs-subject