Angular2에서 다른 구성 요소 함수를 호출하는 방법


154

다음과 같은 두 가지 구성 요소가 있으며 다른 구성 요소에서 함수를 호출하려고합니다. 두 구성 요소는 지시문을 사용하여 세 번째 상위 구성 요소에 포함됩니다.

성분 1 :

@component(
    selector:'com1'
)
export class com1{
    function1(){...}
}

성분 2 :

@component(
    selector:'com2'
)
export class com2{
    function2(){...
        // i want to call function 1 from com1 here
    }
}

내가 사용 해봤 @input하고 @output있지만 정확히 어떻게 그것을 사용하는 이해하지 않고 어떻게 기능, 캔 누군가의 도움을 전화를?


답변:


130

com1과 com2가 형제이면 사용할 수 있습니다

@component({
  selector:'com1',
})
export class com1{
  function1(){...}
}

com2는 EventEmitter

@component({
  selector:'com2',
  template: `<button (click)="function2()">click</button>`
)
export class com2{
  @Output() myEvent = new EventEmitter();
  function2(){...
    this.myEvent.emit(null)
  }
}

여기서 상위 컴포넌트는 이벤트 바인딩을 추가하여 이벤트를 청취 myEvent한 다음 com1.function1()해당 이벤트가 발생할 때 호출 합니다. #com1템플릿의 다른 곳에서이 요소를 참조 할 수있는 템플릿 변수입니다. 우리는 만들기 위해 이것을 사용 function1()하기위한 이벤트 핸들러 myEventcom2:

@component({
  selector:'parent',
  template: `<com1 #com1></com1><com2 (myEvent)="com1.function1()"></com2>`
)
export class com2{
}

구성 요소 간 통신을위한 다른 옵션은 구성 요소 상호 작용 도 참조하십시오.


귀하의 질문에는 부모-자식에 관한 내용이 없습니다. 당신은 무엇을 성취하려고합니까?
Günter Zöchbauer 2016 년

"여기서 부모 구성 요소가 myEvent를 수신하기 위해 이벤트 바인딩을 추가합니다"라고 말하기 시작했을 때 나는 매우 혼란스러워합니다. 우리는 형제 구성 요소 상황을 해결하려고한다고 생각했습니다. 각도 링크는 모두 부모 자식이므로 사용할 수 없습니다.
Angela P

rhe 형제의 부모입니다 (당신은 또한 호스트라고 말할 수 있습니다). <sibling1 (myEvent)="...">Angular가 제공하는 유일한 방법이기 때문에 부모 / 호스트에 대한 이벤트 바인딩입니다. 그러나 이벤트 핸들러는 다른 형제 ( com1) 에서 메소드를 호출합니다 . 부모는 중재자로 사용됩니다.
Günter Zöchbauer 2018 년

보기에서 그것을 부르는 방법?! 그냥 안에 somecomponent.ts?
모하마드 Kermani

그러나 목록의 일부 사용자에 대한 두 개의 다른 구성 요소 (On Click 이벤트 ((하나의 구성 요소))가 세부 정보 페이지 (다른 구성 요소)에 해당 클릭 이벤트를 복사하는 경우)-한 구성 요소 방법에서 다른 구성 요소에서 사용하고 싶습니다. 말해줘 ?? @ GünterZöchbauer
Jignesh Vagh

164

먼저 구성 요소 간의 관계를 이해해야합니다. 그런 다음 올바른 의사 소통 방법을 선택할 수 있습니다. 구성 요소 간 통신을 위해 실습에서 알고 사용하는 모든 방법을 설명하려고합니다.

구성 요소간에 어떤 종류의 관계가있을 수 있습니까?

1. 부모> 자녀

여기에 이미지 설명을 입력하십시오

입력을 통한 데이터 공유

아마도 가장 일반적인 데이터 공유 방법 일 것입니다. @Input()데코레이터를 사용하여 데이터를 템플릿을 통해 전달할 수 있습니다.

parent.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'parent-component',
  template: `
    <child-component [childProperty]="parentProperty"></child-component>
  `,
  styleUrls: ['./parent.component.css']
})
export class ParentComponent{
  parentProperty = "I come from parent"
  constructor() { }
}

child.component.ts

import { Component, Input } from '@angular/core';

@Component({
  selector: 'child-component',
  template: `
      Hi {{ childProperty }}
  `,
  styleUrls: ['./child.component.css']
})
export class ChildComponent {

  @Input() childProperty: string;

  constructor() { }

}

이것은 매우 간단한 방법입니다. 사용하기 쉽습니다. ngOnChanges를 사용하여 자식 구성 요소의 데이터 변경 사항을 잡을 수도 있습니다 .

그러나 객체를 데이터로 사용하고이 객체의 매개 변수를 변경해도 참조는 변경되지 않습니다. 따라서 자식 구성 요소에서 수정 된 개체를 받으려면 변경할 수 없어야합니다.

2. 자녀> 부모

여기에 이미지 설명을 입력하십시오

ViewChild를 통한 데이터 공유

ViewChild를 사용하면 한 구성 요소를 다른 구성 요소에 주입하여 부모에게 해당 속성 및 기능에 액세스 할 수 있습니다. 그러나 한 가지주의 child할 점 은 뷰가 초기화 될 때까지 사용할 수 없다는 것입니다. 즉, 자식에서 데이터를 수신하려면 AfterViewInit 수명주기 후크를 구현해야합니다.

parent.component.ts

import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ChildComponent } from "../child/child.component";

@Component({
  selector: 'parent-component',
  template: `
    Message: {{ message }}
    <child-compnent></child-compnent>
  `,
  styleUrls: ['./parent.component.css']
})
export class ParentComponent implements AfterViewInit {

  @ViewChild(ChildComponent) child;

  constructor() { }

  message:string;

  ngAfterViewInit() {
    this.message = this.child.message
  }
}

child.component.ts

import { Component} from '@angular/core';

@Component({
  selector: 'child-component',
  template: `
  `,
  styleUrls: ['./child.component.css']
})
export class ChildComponent {

  message = 'Hello!';

  constructor() { }

}

Output () 및 EventEmitter를 통한 데이터 공유

데이터를 공유하는 또 다른 방법은 부모가 나열 할 수있는 자식에서 데이터를 내보내는 것입니다. 이 방법은 버튼 클릭, 양식 항목 및 기타 사용자 이벤트와 같은 데이터 변경 사항을 공유하려는 경우에 이상적입니다.

parent.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'parent-component',
  template: `
    Message: {{message}}
    <child-component (messageEvent)="receiveMessage($event)"></child-component>
  `,
  styleUrls: ['./parent.component.css']
})
export class ParentComponent {

  constructor() { }

  message:string;

  receiveMessage($event) {
    this.message = $event
  }
}

child.component.ts

import { Component, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'child-component',
  template: `
      <button (click)="sendMessage()">Send Message</button>
  `,
  styleUrls: ['./child.component.css']
})
export class ChildComponent {

  message: string = "Hello!"

  @Output() messageEvent = new EventEmitter<string>();

  constructor() { }

  sendMessage() {
    this.messageEvent.emit(this.message)
  }
}

3. 형제 자매

여기에 이미지 설명을 입력하십시오

어린이> 부모> 어린이

아래 형제들과 의사 소통하는 다른 방법을 설명하려고합니다. 그러나 위의 방법을 이해하는 방법 중 하나를 이미 이해할 수 있습니다.

parent.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'parent-component',
  template: `
    Message: {{message}}
    <child-one-component (messageEvent)="receiveMessage($event)"></child1-component>
    <child-two-component [childMessage]="message"></child2-component>
  `,
  styleUrls: ['./parent.component.css']
})
export class ParentComponent {

  constructor() { }

  message: string;

  receiveMessage($event) {
    this.message = $event
  }
}

child-one.component.ts

import { Component, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'child-one-component',
  template: `
      <button (click)="sendMessage()">Send Message</button>
  `,
  styleUrls: ['./child-one.component.css']
})
export class ChildOneComponent {

  message: string = "Hello!"

  @Output() messageEvent = new EventEmitter<string>();

  constructor() { }

  sendMessage() {
    this.messageEvent.emit(this.message)
  }
}

child-two.component.ts

import { Component, Input } from '@angular/core';

@Component({
  selector: 'child-two-component',
  template: `
       {{ message }}
  `,
  styleUrls: ['./child-two.component.css']
})
export class ChildTwoComponent {

  @Input() childMessage: string;

  constructor() { }

}

4. 관련없는 구성 요소

여기에 이미지 설명을 입력하십시오

아래 설명 된 모든 방법은 구성 요소 간의 관계에 대한 위의 모든 옵션에 사용할 수 있습니다. 그러나 각각의 장점과 단점이 있습니다.

서비스와 데이터 공유

형제, 손자 등 직접 연결이없는 구성 요소간에 데이터를 전달할 때는 공유 서비스를 사용해야합니다. 항상 동기화해야하는 데이터가 있으면이 상황에서 RxJS BehaviorSubject가 매우 유용합니다.

data.service.ts

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable()
export class DataService {

  private messageSource = new BehaviorSubject('default message');
  currentMessage = this.messageSource.asObservable();

  constructor() { }

  changeMessage(message: string) {
    this.messageSource.next(message)
  }

}

first.component.ts

import { Component, OnInit } from '@angular/core';
import { DataService } from "../data.service";

@Component({
  selector: 'first-componennt',
  template: `
    {{message}}
  `,
  styleUrls: ['./first.component.css']
})
export class FirstComponent implements OnInit {

  message:string;

  constructor(private data: DataService) {
      // The approach in Angular 6 is to declare in constructor
      this.data.currentMessage.subscribe(message => this.message = message);
  }

  ngOnInit() {
    this.data.currentMessage.subscribe(message => this.message = message)
  }

}

second.component.ts

import { Component, OnInit } from '@angular/core';
import { DataService } from "../data.service";

@Component({
  selector: 'second-component',
  template: `
    {{message}}
    <button (click)="newMessage()">New Message</button>
  `,
  styleUrls: ['./second.component.css']
})
export class SecondComponent implements OnInit {

  message:string;

  constructor(private data: DataService) { }

  ngOnInit() {
    this.data.currentMessage.subscribe(message => this.message = message)
  }

  newMessage() {
    this.data.changeMessage("Hello from Second Component")
  }

}

경로와 데이터 공유

때로는 구성 요소간에 간단한 데이터를 전달해야 할뿐만 아니라 페이지의 일부 상태를 저장해야합니다. 예를 들어, 온라인 시장에서 일부 필터를 저장 한 다음이 링크를 복사하여 친구에게 보내려고합니다. 그리고 우리와 같은 상태로 페이지를 열 것으로 기대합니다. 가장 빠른 방법은 query parameters 를 사용하는 것 입니다.

쿼리 매개 변수는 더의 라인을 따라 보이는 /people?id=id아무 것도 동일 할 수 있고 당신이 원하는대로 당신은 많은 매개 변수로 할 수 있습니다. 쿼리 매개 변수는 앰퍼샌드 문자로 구분됩니다.

쿼리 매개 변수로 작업 할 때 경로 파일에서 매개 변수를 정의 할 필요가 없으며 매개 변수의 이름을 지정할 수 있습니다. 예를 들어 다음 코드를 사용하십시오.

page1.component.ts

import {Component} from "@angular/core";
import {Router, NavigationExtras} from "@angular/router";

@Component({
    selector: "page1",
  template: `
    <button (click)="onTap()">Navigate to page2</button>
  `,
})
export class Page1Component {

    public constructor(private router: Router) { }

    public onTap() {
        let navigationExtras: NavigationExtras = {
            queryParams: {
                "firstname": "Nic",
                "lastname": "Raboy"
            }
        };
        this.router.navigate(["page2"], navigationExtras);
    }

}

수신 페이지에서 다음과 같은 쿼리 매개 변수가 수신됩니다.

page2.component.ts

import {Component} from "@angular/core";
import {ActivatedRoute} from "@angular/router";

@Component({
    selector: "page2",
    template: `
         <span>{{firstname}}</span>
         <span>{{lastname}}</span>
      `,
})
export class Page2Component {

    firstname: string;
    lastname: string;

    public constructor(private route: ActivatedRoute) {
        this.route.queryParams.subscribe(params => {
            this.firstname = params["firstname"];
            this.lastname = params["lastname"];
        });
    }

}

NgRx

더 복잡하지만 더 강력한 마지막 방법은 NgRx 를 사용하는 입니다. 이 라이브러리는 데이터 공유를위한 것이 아닙니다. 강력한 상태 관리 라이브러리입니다. 나는 짧은 예제에서 그것을 사용하는 방법을 설명 할 수는 없지만 공식 사이트로 이동하여 관련 문서를 읽을 수 있습니다.

NgRx Store는 여러 가지 문제를 해결합니다. 예를 들어, 관찰 가능 데이터를 처리해야하고 일부 관찰 가능 데이터에 대한 책임이 다른 구성 요소간에 공유되는 경우, 상점 조치 및 감속기는 데이터 수정이 항상 "올바른 방법"으로 수행되도록합니다.

또한 HTTP 요청 캐싱을위한 안정적인 솔루션을 제공합니다. 요청한 요청에 아직 저장된 응답이 없는지 확인할 수 있도록 요청 및 응답을 저장할 수 있습니다.

NgRx에 대해 읽고 앱에 필요한지 여부를 이해할 수 있습니다.

마지막으로, 데이터 공유 방법 중 일부를 선택하기 전에이 데이터가 향후 어떻게 사용되는지 이해해야한다고 말하고 싶습니다. 어쩌면 지금 @Input은 사용자 이름과 성을 공유하기 위해 데코레이터 만 사용할 수 있습니다 . 그런 다음 사용자에 대한 자세한 정보가 필요한 새 구성 요소 또는 새 모듈 (예 : 관리자 패널)을 추가합니다. 이는 사용자 데이터를위한 서비스를 사용하거나 다른 방법으로 데이터를 공유하는 더 좋은 방법 일 수 있음을 의미합니다. 데이터 공유 구현을 시작하기 전에 더 자세히 고려해야합니다.


3
예제를 통한 최상의 설명
afeef

1
내가 본,이 주제에 대한 최고의 답변, 축하합니다 ..
외로운

탁월한 설명
Moisés Aguilar

HTML에서 ts child-two.component.ts 표시 이름의 형제 자매는 childMessage 여야합니다 (이 경우 html 파일 사용)
Nguyễn

84

컴포넌트 2에서 컴포넌트 1의 메소드에 액세스 할 수 있습니다.

componentOne

  ngOnInit() {}

  public testCall(){
    alert("I am here..");    
  }

componentTwo

import { oneComponent } from '../one.component';


@Component({
  providers:[oneComponent ],
  selector: 'app-two',
  templateUrl: ...
}


constructor(private comp: oneComponent ) { }

public callMe(): void {
    this.comp.testCall();
  }

componentTwo HTML 파일

<button (click)="callMe()">click</button>

2
예를 들어 testCall ...을 호출하여 componentTwo에서 componentOne의 변수에 액세스해야 할 때까지는 변수 값이 componentOne에 의해 설정되었지만 componentTwo는 현재가 아닌 기본값을 가져옵니다.
rey_coder

2
componentTwo에서 testCall을 호출하면 testCall 메소드 내부에 componentOne 변수 값이 표시되지 않습니다. 어떤 생각?
Raja

각도 7 이오니아 4이 방법을 설명해주십시오
모하마드 아 유브 칸

이 방법으로는 triger @Raja 같은 문제가되지 않습니다
케빈 디아스

1
THQQQQQQQQQQQQ SO MUCH MAN
Ashu

33

구성 요소 1 (자식) :

@Component(
  selector:'com1'
)
export class Component1{
  function1(){...}
}

성분 2 (부모) :

@Component(
  selector:'com2',
  template: `<com1 #component1></com1>`
)
export class Component2{
  @ViewChild("component1") component1: Component1;

  function2(){
    this.component1.function1();
  }
}

좋은 답변은 여기를 참조 하십시오 .
Cipher

HTML에서 function2를 어떻게 호출합니까? 나는 항상 이것을 얻었다 .component1은 정의되지
않았다

<com1 # component1 (click) = "function2 ()"> </ com1>
Ihor Khomiak

1
이것은 @ angular / core에서 ViewChild를 가져와야하고 어디에서나 Component1을 가져와야한다는 것을 깨달았을 때 저에게 효과적이었습니다.
Dallas Caley

1
구성 요소 클래스를 확장하는 대신 @ViewChild나에게 도움이되었습니다. 이 예제에 감사드립니다.
Yash

27

구성 요소 (부모 / 자식) 간의 관계에 따라 다르지만 구성 요소를 전달하는 가장 좋은 방법은 공유 서비스를 사용하는 것입니다.

자세한 내용은이 문서를 참조하십시오.

즉, 다음을 사용하여 com1의 인스턴스를 com2에 제공 할 수 있습니다.

<div>
  <com1 #com1>...</com1>
  <com2 [com1ref]="com1">...</com2>
</div>

com2에서는 다음을 사용할 수 있습니다.

@Component({
  selector:'com2'
})
export class com2{
  @Input()
  com1ref:com1;

  function2(){
    // i want to call function 1 from com1 here
    this.com1ref.function1();
  }
}

내가 그것을 알고있는 기본 재산이 아니므로 오류가 'com1Ref'에 결합 할 수 없습니다 무엇입니까
noobProgrammer

그리고 this.com1.function1 (); 대신 this.com1ref.function1 ();
noobProgrammer

오타를 지적 해 주셔서 감사합니다! 당신은 가지고 있습니까 @Input필드에서를?
Thierry Templier

좋아, 그것의 작동, 부모-자식 관계를 위해 동일한 달성 방법을 말해 줄 수 있습니까 ??
noobProgrammer

1
부모 자식도 똑같이 시도했지만 undegined의 function1 ()이라고합니다.
noobProgrammer

1
  • 첫 번째 구성 요소가 DbstatsMainComponent라고 가정 해 봅시다.
  • 두 번째 구성 요소 DbstatsGraphComponent.
  • 두 번째 방법을 호출하는 첫 번째 구성 요소

<button (click)="dbgraph.displayTableGraph()">Graph</button> <dbstats-graph #dbgraph></dbstats-graph>

#dbgraph부모가 자식 메서드에 액세스하는 데 사용할 수있는 자식 구성 요소 의 로컬 변수 에 유의하십시오 ( dbgraph.displayTableGraph()).


0

Dataservice를 사용하여 다른 컴포넌트에서 함수를 호출 할 수 있습니다.

Component1 : 함수를 호출하는 컴포넌트

constructor( public bookmarkRoot: dataService ) { } 

onClick(){
     this.bookmarkRoot.callToggle.next( true );
}

dataservice.ts

import { Injectable } from '@angular/core';
@Injectable()
export class dataService {
     callToggle = new Subject();
}

Component2 : 기능을 포함하는 구성 요소

constructor( public bookmarkRoot: dataService ) { 
  this.bookmarkRoot.callToggle.subscribe(( data ) => {
            this.closeDrawer();
        } )
} 

 closeDrawer() {
        console.log("this is called")
    }

생성자 내부에서이 코드를 사용하지 않도록 여러 번 호출 할 수 있습니다.if ( this.bookmarkRoot.callToggle.observers.length === 0 ) { this.bookmarkRoot.callToggle.subscribe(( data ) => { this.closeDrawer(); } ) }
Shafeeq Mohammed
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.