Angular 2 형제 구성 요소 통신
List Component가 있습니다.List Component에서 항목을 클릭하면 해당 항목의 세부 정보가 Detail Component에 표시됩니다.둘 다 동시에 화면에 표시되므로 라우팅은 필요하지 않습니다.
List Component에서 어떤 항목을 클릭했는지 Detail Component에 어떻게 알 수 있습니까?
부모(App Component)까지 이벤트를 송신하는 것을 검토하고 부모에게 @Input을 사용하여 Detail Component의 selectedItem.id을 설정하도록 했습니다.또는 관찰 가능한 구독을 가진 공유 서비스를 사용할 수도 있습니다.
편집: 이벤트 + @Input을 통해 선택한 항목을 설정해도 추가 코드를 실행해야 할 경우 Detail Component가 트리거되지 않습니다.그래서 나는 이것이 받아들일 수 있는 해결책인지 잘 모르겠다.
그러나 이 두 가지 방법 모두 $rootScope를 통한 Angular 1의 작업 방식보다 훨씬 복잡해 보입니다.$190 또는 $190.$parent.$140입니다.
Angular 2의 모든 것이 컴포넌트이기 때문에 컴포넌트 통신에 관한 정보가 부족하다는 것이 놀랍습니다.
이를 실현하는 다른/좀 더 간단한 방법이 있습니까?
rc.4로 업데이트: angular 2의 형제 컴포넌트 간에 데이터를 전달하려고 할 때 가장 간단한 방법(angular.rc.4)은 angular 2의 계층적 종속성 주입을 이용하여 공유 서비스를 만드는 것입니다.
서비스는 다음과 같습니다.
import {Injectable} from '@angular/core';
@Injectable()
export class SharedService {
dataArray: string[] = [];
insertData(data: string){
this.dataArray.unshift(data);
}
}
여기 PARENT 컴포넌트가 있습니다.
import {Component} from '@angular/core';
import {SharedService} from './shared.service';
import {ChildComponent} from './child.component';
import {ChildSiblingComponent} from './child-sibling.component';
@Component({
selector: 'parent-component',
template: `
<h1>Parent</h1>
<div>
<child-component></child-component>
<child-sibling-component></child-sibling-component>
</div>
`,
providers: [SharedService],
directives: [ChildComponent, ChildSiblingComponent]
})
export class parentComponent{
}
그리고 그 두 아이는
아이 1
import {Component, OnInit} from '@angular/core';
import {SharedService} from './shared.service'
@Component({
selector: 'child-component',
template: `
<h1>I am a child</h1>
<div>
<ul *ngFor="#data in data">
<li>{{data}}</li>
</ul>
</div>
`
})
export class ChildComponent implements OnInit{
data: string[] = [];
constructor(
private _sharedService: SharedService) { }
ngOnInit():any {
this.data = this._sharedService.dataArray;
}
}
child 2(형제)
import {Component} from 'angular2/core';
import {SharedService} from './shared.service'
@Component({
selector: 'child-sibling-component',
template: `
<h1>I am a child</h1>
<input type="text" [(ngModel)]="data"/>
<button (click)="addData()"></button>
`
})
export class ChildSiblingComponent{
data: string = 'Testing data';
constructor(
private _sharedService: SharedService){}
addData(){
this._sharedService.insertData(this.data);
this.data = '';
}
}
NOW: 이 방법을 사용할 때 주의해야 할 사항.
- 공유 서비스에 대한 서비스 제공자만 상위 구성 요소에 포함시키고 하위 구성 요소는 포함하지 마십시오.
- 그래도 생성자를 포함하고 하위 항목에 서비스를 가져와야 합니다.
- 이 답변은 원래 초기 Angle 2 베타 버전에 대한 답변이었습니다.변경된 것은 Import 스테이트먼트뿐이므로 원래 버전을 사용한 경우 업데이트만 하면 됩니다.
2개의 다른 컴포넌트(네스트된 컴포넌트가 아닌 parent\child\handchild)의 경우 다음을 권장합니다.
미션 서비스:
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class MissionService {
// Observable string sources
private missionAnnouncedSource = new Subject<string>();
private missionConfirmedSource = new Subject<string>();
// Observable string streams
missionAnnounced$ = this.missionAnnouncedSource.asObservable();
missionConfirmed$ = this.missionConfirmedSource.asObservable();
// Service message commands
announceMission(mission: string) {
this.missionAnnouncedSource.next(mission);
}
confirmMission(astronaut: string) {
this.missionConfirmedSource.next(astronaut);
}
}
우주 비행사 컴포넌트:
import { Component, Input, OnDestroy } from '@angular/core';
import { MissionService } from './mission.service';
import { Subscription } from 'rxjs/Subscription';
@Component({
selector: 'my-astronaut',
template: `
<p>
{{astronaut}}: <strong>{{mission}}</strong>
<button
(click)="confirm()"
[disabled]="!announced || confirmed">
Confirm
</button>
</p>
`
})
export class AstronautComponent implements OnDestroy {
@Input() astronaut: string;
mission = '<no mission announced>';
confirmed = false;
announced = false;
subscription: Subscription;
constructor(private missionService: MissionService) {
this.subscription = missionService.missionAnnounced$.subscribe(
mission => {
this.mission = mission;
this.announced = true;
this.confirmed = false;
});
}
confirm() {
this.confirmed = true;
this.missionService.confirmMission(this.astronaut);
}
ngOnDestroy() {
// prevent memory leak when component destroyed
this.subscription.unsubscribe();
}
}
출처: 부모와 자녀는 서비스를 통해 통신합니다.
이를 위한 한 가지 방법은 공유 서비스를 사용하는 것입니다.
다만, 이하의 솔루션은, 2명의 형제자매간에 데이터를 공유할 수 있는 것이 보다 간단하다고 생각합니다.(이 테스트는 Angular 5에서만 실시)
부모 컴포넌트 템플릿:
<!-- Assigns "AppSibling1Component" instance to variable "data" -->
<app-sibling1 #data></app-sibling1>
<!-- Passes the variable "data" to AppSibling2Component instance -->
<app-sibling2 [data]="data"></app-sibling2>
app-syslog2.component.ts
import { AppSibling1Component } from '../app-sibling1/app-sibling1.component';
...
export class AppSibling2Component {
...
@Input() data: AppSibling1Component;
...
}
여기에 그것에 대한 논의가 있다.
https://github.com/angular/angular.io/issues/2663
Alex J의 답변은 좋지만 2017년 7월 현재 Angular 4에서는 더 이상 작동하지 않습니다.
그리고 이 plunker 링크는 공유 서비스와 관찰 가능한 서비스를 사용하여 형제자매 간에 통신하는 방법을 보여줍니다.
https://embed.plnkr.co/P8xCEwSKgcOg07pwDrlO/
특정 상황에서는 컴포넌트를 '연결'하도록 지시하는 것이 타당할 수 있습니다.실제로 접속되어 있는 것이 완전한 컴포넌트일 필요는 없습니다.또, 접속되어 있지 않으면, 보다 가볍고 심플한 경우도 있습니다.
를 들어, 나는 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★.Youtube Player
Youtube API 와와와와와와와와 apiy 。버튼이 주요 컴포넌트의 일부가 아닌 유일한 이유는 버튼이 DOM의 다른 곳에 있기 때문입니다.
이 경우 실제로는 '확장' 컴포넌트일 뿐이며 '상위' 컴포넌트에서만 사용할 수 있습니다.저는 '부모'라고 말하는데, DOM에서는 형제자매입니다.그러니까 뭐라고 부르면 될까요?
가 말한 처럼 그것은 컴포넌트일 도 없다 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」<button>
(서양속담, 서양속담)
@Directive({
selector: '[ytPlayerPlayButton]'
})
export class YoutubePlayerPlayButtonDirective {
_player: YoutubePlayerComponent;
@Input('ytPlayerVideo')
private set player(value: YoutubePlayerComponent) {
this._player = value;
}
@HostListener('click') click() {
this._player.play();
}
constructor(private elementRef: ElementRef) {
// the button itself
}
}
for 'HTML'에서ProductPage.component
서, snowledge.youtube-player
Youtube API입니다.
<youtube-player #technologyVideo videoId='NuU74nesR5A'></youtube-player>
... lots more DOM ...
<button class="play-button"
ytPlayerPlayButton
[ytPlayerVideo]="technologyVideo">Play</button>
디렉티브에 의해 모든 것이 연결되므로 HTML에서 (클릭) 이벤트를 선언할 필요가 없습니다.
는 비디오 할 수 .ProductPage
중재자로서
이것은 실제로 처음 하는 일이기 때문에, 훨씬 더 복잡한 상황에서 얼마나 확장할 수 있을지는 아직 확실하지 않습니다.이 때문에 저는 기쁘고 HTML의 심플함과 모든 것에 대한 책임이 남습니다.
공유 서비스는 이 문제에 대한 좋은 해결책입니다.액티비티 정보도 저장할 경우 메인 모듈(app.module) 공급자목록에 Shared Service를 추가할 수 있습니다.
@NgModule({
imports: [
...
],
bootstrap: [
AppComponent
],
declarations: [
AppComponent,
],
providers: [
SharedService,
...
]
});
그런 다음 컴포넌트에 직접 제공할 수 있습니다.
constructor(private sharedService: SharedService)
공유 서비스를 사용하면 기능을 사용하거나 제목을 만들어 여러 위치를 한 번에 업데이트할 수 있습니다.
@Injectable()
export class SharedService {
public clickedItemInformation: Subject<string> = new Subject();
}
목록 구성 요소에서 클릭된 항목 정보를 게시할 수 있습니다.
this.sharedService.clikedItemInformation.next("something");
그런 다음 세부 구성 요소에서 다음 정보를 가져올 수 있습니다.
this.sharedService.clikedItemInformation.subscribe((information) => {
// do something
});
컴포넌트 공유를 나열하는 데이터는 당연히 모든 것이 될 수 있습니다.이게 도움이 됐으면 좋겠다.
구성 요소 간에 부모-자녀 관계를 설정해야 합니다.문제는 상위 구성 요소의 생성자에 하위 구성 요소를 주입하고 로컬 변수에 저장할 수 있다는 것입니다.부모 는 부모 컴포넌트를 사용하여 선언해야 합니다.@ViewChild
.부모 컴포넌트는 다음과 같습니다.
import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ListComponent } from './list.component';
import { DetailComponent } from './detail.component';
@Component({
selector: 'app-component',
template: '<list-component></list-component><detail-component></detail-component>',
directives: [ListComponent, DetailComponent]
})
class AppComponent implements AfterViewInit {
@ViewChild(ListComponent) listComponent:ListComponent;
@ViewChild(DetailComponent) detailComponent: DetailComponent;
ngAfterViewInit() {
// afther this point the children are set, so you can use them
this.detailComponent.doSomething();
}
}
https://angular.io/docs/ts/latest/api/core/index/ViewChild-var.html
https://angular.io/docs/ts/latest/cookbook/component-communication.html#parent-to-view-child
컴포넌트의 할 수 컴포넌트 뒤에 .ngAfterViewInit
라이프 사이클 훅이 호출됩니다.하세요.AfterViewInit
는, 「」와 됩니다.OnInit
.
단, 다음 블로그 노트에서 설명한 바와 같이 다른 자산 신고자가 있습니다.http://blog.mgechev.com/2016/01/23/angular2-viewchildren-contentchildren-difference-viewproviders/
다음은 간단한 실용적인 설명입니다.여기에 간단히 설명하겠습니다.
in call.service.ts
import { Observable } from 'rxjs';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class CallService {
private subject = new Subject<any>();
sendClickCall(message: string) {
this.subject.next({ text: message });
}
getClickCall(): Observable<any> {
return this.subject.asObservable();
}
}
버튼이 클릭되었음을 다른 컴포넌트에 알리기 위해 관찰 가능한 컴포넌트를 호출하는 컴포넌트
import { CallService } from "../../../services/call.service";
export class MarketplaceComponent implements OnInit, OnDestroy {
constructor(public Util: CallService) {
}
buttonClickedToCallObservable() {
this.Util.sendClickCall('Sending message to another comp that button is clicked');
}
}
다른 컴포넌트를 누른 버튼에 대해 작업을 수행할 컴포넌트
import { Subscription } from 'rxjs/Subscription';
import { CallService } from "../../../services/call.service";
ngOnInit() {
this.subscription = this.Util.getClickCall().subscribe(message => {
this.message = message;
console.log('---button clicked at another component---');
//call you action which need to execute in this component on button clicked
});
}
import { Subscription } from 'rxjs/Subscription';
import { CallService } from "../../../services/call.service";
ngOnInit() {
this.subscription = this.Util.getClickCall().subscribe(message => {
this.message = message;
console.log('---button clicked at another component---');
//call you action which need to execute in this component on button clicked
});
}
컴포넌트 통신에 대해서는, http://musttoknow.com/angular-4-angular-5-communicate-two-components-using-observable-subject/ 를 참조해 주세요.
이것은 당신이 원하는 것은 아니지만 확실히 당신을 도울 것이다.
컴포넌트 통신에 관한 정보가 아직 없는 것이 놀랍습니다.<=> angualr2의 튜토리얼을 참조해 주십시오.
형제 컴포넌트 통신에 대해서는 다음과 같이 하는 것이 좋습니다.sharedService
다른 옵션도 있습니다.
import {Component,bind} from 'angular2/core';
import {bootstrap} from 'angular2/platform/browser';
import {HTTP_PROVIDERS} from 'angular2/http';
import {NameService} from 'src/nameService';
import {TheContent} from 'src/content';
import {Navbar} from 'src/nav';
@Component({
selector: 'app',
directives: [TheContent,Navbar],
providers: [NameService],
template: '<navbar></navbar><thecontent></thecontent>'
})
export class App {
constructor() {
console.log('App started');
}
}
bootstrap(App,[]);
자세한 코드는 상단에 있는 링크를 참조하십시오.
편집: 이것은 매우 작은 데모입니다.당신은 이미 당신이 이미 시도했다고 언급했습니다.sharedService
자세한 내용은 angualr2의 튜토리얼을 참조해 주십시오.
행동 대상.나는 그것에 대해 블로그를 썼다.
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
private noId = new BehaviorSubject<number>(0);
defaultId = this.noId.asObservable();
newId(urlId) {
this.noId.next(urlId);
}
이 예에서는 타입 번호의 noid 동작 서브젝트를 선언하고 있습니다.또한 그것은 관찰할 수 있다.또한 "something"이 발생하면 new(){} 함수로 변경됩니다.
따라서 형제자매의 컴포넌트에서 한 명은 함수를 호출하여 변경을 가하고 다른 한 명은 해당 변경의 영향을 받습니다.또는 그 반대의 경우도 마찬가지입니다.
예를 들어 URL에서 ID를 가져와 동작 주체에서 noid를 업데이트합니다.
public getId () {
const id = +this.route.snapshot.paramMap.get('id');
return id;
}
ngOnInit(): void {
const id = +this.getId ();
this.taskService.newId(id)
}
그리고 반대편에서 그 ID가 "what anyver"인지 물어보고 그 후에 선택할 수 있습니다. 내 경우 작업을 자세히 설명하려면 해당 작업이 현재 URL이면 홈으로 리디렉션해야 합니다.
delete(task: Task): void {
//we save the id , cuz after the delete function, we gonna lose it
const oldId = task.id;
this.taskService.deleteTask(task)
.subscribe(task => { //we call the defaultId function from task.service.
this.taskService.defaultId //here we are subscribed to the urlId, which give us the id from the view task
.subscribe(urlId => {
this.urlId = urlId ;
if (oldId == urlId ) {
// Location.call('/home');
this.router.navigate(['/home']);
}
})
})
}
형제간 통신을 하는 깔끔한 방법 중 하나는 한 아이에게는 @Output 데코레이터를 사용하고 다른 아이에게는 템플릿 참조 변수를 사용하여 부모가 이 아이의 메서드를 호출하도록 하는 것입니다.이것은 자녀와 부모의 커뮤니케이션에 @Ouput을 사용하는 것과 매우 유사합니다.
하고있다this.emitSomething.emit(something);
child-2가 트리거합니다.onEmitSomething()
1세 때.
child-1.component.ts
onEmitSomething(event: any): void {
// do something
}
아이-2.component.ts
@Output() emitSomething: EventEmitter<any> = new EventEmitter<any>();
parent.component.displaces
<child-1 #child1></child-1>
<child-2 (emitSomething)="child1.onEmitSomething($event)"></child-2>
두 가지 다른 성분 상호 작용 방법은 각도 - 성분 상호 작용에서 찾을 수 있습니다.
바인딩을 통해 세터 메서드를 부모 컴포넌트에서 자식 컴포넌트 중 하나로 전달하고 있습니다.즉, 부모 컴포넌트가 갱신되어 두 번째 자녀 컴포넌트를 새로운 데이터로 갱신할 수 있습니다.단, 'this'를 바인딩하거나 화살표 기능을 사용해야 합니다.
이것은 아이들이 특별한 공유 서비스를 필요로 하지 않기 때문에 서로 결합하지 않는다는 장점이 있다.
이것이 베스트 프랙티스인지 아닌지는 잘 모르겠습니다만, 이것에 관한 다른 견해를 듣는 것은 흥미로울 것입니다.
또한 입력과 출력을 통한 부모 컴포넌트를 통한 2남매 간의 커뮤니케이션도 좋아합니다.OnPush 변경 통지는 일반 서비스를 사용하는 것보다 더 잘 처리됩니다.아니면 NgRx 스토어를 이용하세요.
예.
@Component({
selector: 'parent',
template: `<div><notes-grid
[Notes]="(NotesList$ | async)"
(selectedNote)="ReceiveSelectedNote($event)"
</notes-grid>
<note-edit
[gridSelectedNote]="(SelectedNote$ | async)"
</note-edit></div>`,
styleUrls: ['./parent.component.scss']
})
export class ParentComponent {
// create empty observable
NotesList$: Observable<Note[]> = of<Note[]>([]);
SelectedNote$: Observable<Note> = of<Note>();
//passed from note-grid for selected note to edit.
ReceiveSelectedNote(selectedNote: Note) {
if (selectedNote !== null) {
// change value direct subscribers or async pipe subscribers will get new value.
this.SelectedNote$ = of<Note>(selectedNote);
}
}
//used in subscribe next() to http call response. Left out all that code for brevity. This just shows how observable is populated.
onNextData(n: Note[]): void {
// Assign to Obeservable direct subscribers or async pipe subscribers will get new value.
this.NotesList$ = of<Note[]>(n.NoteList); //json from server
}
}
//child 1 sibling
@Component({
selector: 'note-edit',
templateUrl: './note-edit.component.html', // just a textarea for noteText and submit and cancel buttons.
styleUrls: ['./note-edit.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class NoteEditComponent implements OnChanges {
@Input() gridSelectedNote: Note;
constructor() {
}
// used to capture @Input changes for new gridSelectedNote input
ngOnChanges(changes: SimpleChanges) {
if (changes.gridSelectedNote && changes.gridSelectedNote.currentValue !== null) {
this.noteText = changes.gridSelectedNote.currentValue.noteText;
this.noteCreateDtm = changes.gridSelectedNote.currentValue.noteCreateDtm;
this.noteAuthorName = changes.gridSelectedNote.currentValue.noteAuthorName;
}
}
}
//child 2 sibling
@Component({
selector: 'notes-grid',
templateUrl: './notes-grid.component.html', //just an html table with notetext, author, date
styleUrls: ['./notes-grid.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class NotesGridComponent {
// the not currently selected fromt eh grid.
CurrentSelectedNoteData: Note;
// list for grid
@Input() Notes: Note[];
// selected note of grid sent out to the parent to send to sibling.
@Output() readonly selectedNote: EventEmitter<Note> = new EventEmitter<Note>();
constructor() {
}
// use when you need to send out the selected note to note-edit via parent using output-> input .
EmitSelectedNote(){
this.selectedNote.emit(this.CurrentSelectedNoteData);
}
}
// here just so you can see what it looks like.
export interface Note {
noteText: string;
noteCreateDtm: string;
noteAuthorName: string;
}
언급URL : https://stackoverflow.com/questions/35884451/angular-2-sibling-component-communication
'programing' 카테고리의 다른 글
기본적으로는 Spring Boot에서는 뷰가 저장되는 장소는 어디입니까? (0) | 2023.03.31 |
---|---|
Wordpress 사용자 지정 게시 유형 레이블 이름 가져오기 (0) | 2023.03.31 |
Angularjs: ng-model 업데이트 시 업데이트 안 함을 선택합니다. (0) | 2023.03.26 |
리액트 훅으로 빨리 돌아올 수 있나요? (0) | 2023.03.26 |
ngInject는 다음 코드에서 무엇을 합니까? (0) | 2023.03.26 |