거기에 상응하는 것이 없다.$scope.emit()
또는$scope.broadcast()
각도로?
나는 알고있다.EventEmitter
기능을 제공하지만, 이해하는 한 상위 HTML 요소에 이벤트를 내 보냅니다.
FX 사이에서 의사 소통이 필요한 경우 어떻게해야합니까? 형제 또는 DOM의 루트에있는 구성 요소와 여러 수준으로 중첩 된 요소 사이에 있습니까?
이에 상응하는 것은 없습니다.$scope.emit()
또는$scope.broadcast()
AngularJS에서.
구성 요소 내부의 EventEmitter는 가까이에 있지만 앞에서 언급했듯이 바로 위 부모 구성 요소에만 이벤트를 내 보냅니다.
Angular에는 아래에서 설명하려고하는 다른 대안이 있습니다.
@Input () 바인딩을 사용하면 응용 프로그램 모델을 직접 객체 그래프 (루트에서 리프)로 연결할 수 있습니다. 구성 요소의 변경 감지기 전략의 기본 동작은 연결된 구성 요소의 모든 바인딩에 대한 응용 프로그램 모델에 모든 변경 사항을 전파하는 것입니다.
옆으로 : 모델에는보기 모델과 응용 프로그램 모델이라는 두 가지 유형이 있습니다. 응용 프로그램 모델은 @Input () 바인딩을 통해 연결됩니다. 뷰 모델은 구성 요소의 템플릿에 바인딩 된 구성 요소 속성 (@Input ()으로 장식되지 않음)입니다.
귀하의 질문에 대답하십시오 :
형제 구성 요소 간 통신이 필요한 경우 어떻게해야합니까?
공유 응용 프로그램 모델: 형제는 공유 응용 프로그램 모델 (각도 1과 동일)을 통해 통신 할 수 있습니다. 예를 들어 한 형제가 모델을 변경하면 동일한 모델에 바인딩 된 다른 형제가 자동으로 업데이트됩니다.
구성 요소 이벤트: 자식 구성 요소는 @Output () 바인딩을 사용하여 부모 구성 요소로 이벤트를 내보낼 수 있습니다. 부모 구성 요소는 이벤트를 처리하고 응용 프로그램 모델 또는 자체 뷰 모델을 조작 할 수 있습니다. 응용 프로그램 모델의 변경 사항은 동일한 모델에 직접 또는 간접적으로 바인딩되는 모든 구성 요소에 자동으로 전파됩니다.
서비스 이벤트: 구성 요소는 서비스 이벤트를 구독 할 수 있습니다. 예를 들어, 두 형제 구성 요소는 동일한 서비스 이벤트에 가입하고 각각의 모델을 수정하여 응답 할 수 있습니다. 이에 대한 자세한 내용은 아래를 참조하십시오.
루트 구성 요소와 여러 수준의 중첩 된 구성 요소 사이에서 통신하려면 어떻게해야합니까?
$scope.broadcast()
다음 단원에서는이 아이디어에 대해 자세히 설명합니다.서비스 이벤트를 사용하여 변경 사항을 전파하는 관찰 가능한 서비스의 예
다음은 서비스 이벤트를 사용하여 변경 사항을 전파하는 관찰 가능한 서비스의 예입니다. TodoItem이 추가되면 서비스는 구성 요소 구독자에게 알리는 이벤트를 내 보냅니다.
export class TodoItem {
constructor(public name: string, public done: boolean) {
}
}
export class TodoService {
public itemAdded$: EventEmitter<TodoItem>;
private todoList: TodoItem[] = [];
constructor() {
this.itemAdded$ = new EventEmitter();
}
public list(): TodoItem[] {
return this.todoList;
}
public add(item: TodoItem): void {
this.todoList.push(item);
this.itemAdded$.emit(item);
}
}
다음은 루트 구성 요소가 이벤트에 가입하는 방법입니다.
export class RootComponent {
private addedItem: TodoItem;
constructor(todoService: TodoService) {
todoService.itemAdded$.subscribe(item => this.onItemAdded(item));
}
private onItemAdded(item: TodoItem): void {
// do something with added item
this.addedItem = item;
}
}
동일한 레벨로 이벤트에 등록 할 수있는 여러 수준의 중첩 된 하위 구성 요소 :
export class GrandChildComponent {
private addedItem: TodoItem;
constructor(todoService: TodoService) {
todoService.itemAdded$.subscribe(item => this.onItemAdded(item));
}
private onItemAdded(item: TodoItem): void {
// do something with added item
this.addedItem = item;
}
}
다음은 이벤트를 트리거하기 위해 서비스를 호출하는 구성 요소입니다 (구성 요소 트리의 아무 곳에 나 위치 할 수 있음).
@Component({
selector: 'todo-list',
template: `
<ul>
<li *ngFor="#item of model"> {{ item.name }}
</li>
</ul>
<br />
Add Item <input type="text" #txt /> <button (click)="add(txt.value); txt.value='';">Add</button>
`
})
export class TriggeringComponent{
private model: TodoItem[];
constructor(private todoService: TodoService) {
this.model = todoService.list();
}
add(value: string) {
this.todoService.add(new TodoItem(value, false));
}
}
참고:각도 변경 감지
itemAdded$
. RxJS 대회인가요? 이것은 어디서 오는 것입니까? - Mark Rajcokstreet
응용 프로그램 모델의 속성이지만 Angular 2에서는 ID / 참조에 의한 변경 감지를 구현하므로 변경 사항이 전파되지 않습니다 (onChanges
호출되지 않음), 앱 모델 참조가 변경되지 않았기 때문에 (계속 ...) - Mark Rajcok
대체 코드의 예는 다음과 같습니다.$ scope.emit ()또는$ scope.broadcast ()각도 2로공유 서비스이벤트를 처리합니다.
import {Injectable} from 'angular2/core';
import * as Rx from 'rxjs/Rx';
@Injectable()
export class EventsService {
constructor() {
this.listeners = {};
this.eventsSubject = new Rx.Subject();
this.events = Rx.Observable.from(this.eventsSubject);
this.events.subscribe(
({name, args}) => {
if (this.listeners[name]) {
for (let listener of this.listeners[name]) {
listener(...args);
}
}
});
}
on(name, listener) {
if (!this.listeners[name]) {
this.listeners[name] = [];
}
this.listeners[name].push(listener);
}
broadcast(name, ...args) {
this.eventsSubject.next({
name,
args
});
}
}
사용 예 :
방송:
function handleHttpError(error) {
this.eventsService.broadcast('http-error', error);
return ( Rx.Observable.throw(error) );
}
경청자:
import {Inject, Injectable} from "angular2/core";
import {EventsService} from './events.service';
@Injectable()
export class HttpErrorHandler {
constructor(eventsService) {
this.eventsService = eventsService;
}
static get parameters() {
return [new Inject(EventsService)];
}
init() {
this.eventsService.on('http-error', function(error) {
console.group("HttpErrorHandler");
console.log(error.status, "status code detected.");
console.dir(error);
console.groupEnd();
});
}
}
여러 인수를 지원할 수 있습니다.
this.eventsService.broadcast('something', "Am I a?", "Should be b", "C?");
this.eventsService.on('something', function (a, b, c) {
console.log(a, b, c);
});
off(name, listener) { this.listeners[name] = this.listeners[name].filter(x => x != listener); }
- LVDM
rxjs 래핑하는 메시지 서비스를 사용하고 있습니다.Subject
(유형 스크립트)
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { Subscription } from 'rxjs/Subscription';
import 'rxjs/add/operator/filter'
import 'rxjs/add/operator/map'
interface Message {
type: string;
payload: any;
}
type MessageCallback = (payload: any) => void;
@Injectable()
export class MessageService {
private handler = new Subject<Message>();
broadcast(type: string, payload: any) {
this.handler.next({ type, payload });
}
subscribe(type: string, callback: MessageCallback): Subscription {
return this.handler
.filter(message => message.type === type)
.map(message => message.payload)
.subscribe(callback);
}
}
구성 요소는 이벤트를 구독하고 브로드 캐스팅 할 수 있습니다 (보낸 사람).
import { Component, OnDestroy } from '@angular/core'
import { MessageService } from './message.service'
import { Subscription } from 'rxjs/Subscription'
@Component({
selector: 'sender',
template: ...
})
export class SenderComponent implements OnDestroy {
private subscription: Subscription;
private messages = [];
private messageNum = 0;
private name = 'sender'
constructor(private messageService: MessageService) {
this.subscription = messageService.subscribe(this.name, (payload) => {
this.messages.push(payload);
});
}
send() {
let payload = {
text: `Message ${++this.messageNum}`,
respondEvent: this.name
}
this.messageService.broadcast('receiver', payload);
}
clear() {
this.messages = [];
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
(리시버)
import { Component, OnDestroy } from '@angular/core'
import { MessageService } from './message.service'
import { Subscription } from 'rxjs/Subscription'
@Component({
selector: 'receiver',
template: ...
})
export class ReceiverComponent implements OnDestroy {
private subscription: Subscription;
private messages = [];
constructor(private messageService: MessageService) {
this.subscription = messageService.subscribe('receiver', (payload) => {
this.messages.push(payload);
});
}
send(message: {text: string, respondEvent: string}) {
this.messageService.broadcast(message.respondEvent, message.text);
}
clear() {
this.messages = [];
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
그만큼subscribe
의 방법MessageService
rxjs를 반환합니다.Subscription
개체, 그렇게에서 구독 취소 할 수 있습니다 :
import { Subscription } from 'rxjs/Subscription';
...
export class SomeListener {
subscription: Subscription;
constructor(private messageService: MessageService) {
this.subscription = messageService.subscribe('someMessage', (payload) => {
console.log(payload);
this.subscription.unsubscribe();
});
}
}
또한이 답변을 참조하십시오 :https://stackoverflow.com/a/36782616/1861779
사용하지 마세요귀하의 서비스 통신을위한 EventEmitter.
Observable 유형 중 하나를 사용해야합니다. 저는 개인적으로 BehaviorSubject를 좋아합니다.
간단한 예 :
당신은 초기 상태를 전달할 수 있습니다, 여기는 null을 전달합니다.
피사체 = 새로운 BehaviorSubject (null);
제목을 업데이트하려고 할 때
subject.next (myObject)
모든 서비스 또는 구성 요소를 관찰하고 새 업데이트가있을 때 작동합니다.
subject.subscribe (this.YOURMETHOD);
당신이 사용할 수있는EventEmitter 또는observables를 사용하여 DI에 등록하는 eventbus 서비스를 생성하십시오. 참여하려는 모든 구성 요소는 서비스를 생성자 매개 변수로 요청하고 이벤트를 내보내거나 구독합니다.
또한보십시오
여기에 펍 서브 샘플을 만들었습니다.
http://www.syntaxsuccess.com/viewarticle/pub-sub-in-angular-2.0
RxJs Subject를 사용하여 Observer 및 Observables를 커스텀 이벤트를 생성 및 수신하기위한 일반적인 솔루션으로 연결하는 것이 아이디어입니다. 내 샘플에서는 데모 목적으로 고객 객체를 사용합니다.
this.pubSubService.Stream.emit(customer);
this.pubSubService.Stream.subscribe(customer => this.processCustomer(customer));
여기에 라이브 데모도 있습니다 :http://www.syntaxsuccess.com/angular-2-samples/#/demo/pub-sub
제가 가장 좋아하는 방법은 내 하위 구성 요소 모두를 제어하기 위해 내 서비스에서 동작 제목 또는 이벤트 이미 터 (거의 동일한)를 사용하는 것입니다.
각 클립을 사용하여 새 서비스를 만든 다음 BehaviorSubject 또는 EventEmitter를 사용하십시오.
export Class myService {
#all the stuff that must exist
myString: string[] = [];
contactChange : BehaviorSubject<string[]> = new BehaviorSubject(this.myString);
getContacts(newContacts) {
// get your data from a webservices & when you done simply next the value
this.contactChange.next(newContacts);
}
}
그렇게하면 서비스를 공급자로 사용하는 모든 구성 요소가 변경 사항을 인식하게됩니다. eventEmitter와 마찬가지로 결과에 간단히 가입하십시오.)
export Class myComp {
#all the stuff that exists like @Component + constructor using (private myService: myService)
this.myService.contactChange.subscribe((contacts) => {
this.contactList += contacts; //run everytime next is called
}
}
우리는 자신의 구성 요소에서 인스턴스화하는 이벤트 이미 터를 통해 모든 모델 변경 사항을 보내는 ngModelChange observable 지시문을 구현했습니다. 이벤트 이미 터를 지정.에 Y 인드하면됩니다.
만나다:https://github.com/atomicbits/angular2-modelchangeobservable
html에서 이벤트 이미 터 (이 예제에서는 countryChanged)를 바인딩하십시오.
<input [(ngModel)]="country.name"
[modelChangeObservable]="countryChanged"
placeholder="Country"
name="country" id="country"></input>
타이피 스크립트 구성 요소에서 EventEmitter에 대한 비동기 작업을 수행하십시오.
import ...
import {ModelChangeObservable} from './model-change-observable.directive'
@Component({
selector: 'my-component',
directives: [ModelChangeObservable],
providers: [],
templateUrl: 'my-component.html'
})
export class MyComponent {
@Input()
country: Country
selectedCountries:Country[]
countries:Country[] = <Country[]>[]
countryChanged:EventEmitter<string> = new EventEmitter<string>()
constructor() {
this.countryChanged
.filter((text:string) => text.length > 2)
.debounceTime(300)
.subscribe((countryName:string) => {
let query = new RegExp(countryName, 'ig')
this.selectedCountries = this.countries.filter((country:Country) => {
return query.test(country.name)
})
})
}
}
이것은 내 버전입니다.
export interface IEventListenr extends OnDestroy{
ngOnDestroy(): void
}
@Injectable()
export class EventManagerService {
private listeners = {};
private subject = new EventEmitter();
private eventObserver = this.subject.asObservable();
constructor() {
this.eventObserver.subscribe(({name,args})=>{
if(this.listeners[name])
{
for(let listener of this.listeners[name])
{
listener.callback(args);
}
}
})
}
public registerEvent(eventName:string,eventListener:IEventListenr,callback:any)
{
if(!this.listeners[eventName])
this.listeners[eventName] = [];
let eventExist = false;
for(let listener of this.listeners[eventName])
{
if(listener.eventListener.constructor.name==eventListener.constructor.name)
{
eventExist = true;
break;
}
}
if(!eventExist)
{
this.listeners[eventName].push({eventListener,callback});
}
}
public unregisterEvent(eventName:string,eventListener:IEventListenr)
{
if(this.listeners[eventName])
{
for(let i = 0; i<this.listeners[eventName].length;i++)
{
if(this.listeners[eventName][i].eventListener.constructor.name==eventListener.constructor.name)
{
this.listeners[eventName].splice(i, 1);
break;
}
}
}
}
emit(name:string,...args:any[])
{
this.subject.next({name,args});
}
}
용도:
export class <YOURCOMPONENT> implements IEventListener{
constructor(private eventManager: EventManagerService) {
this.eventManager.registerEvent('EVENT_NAME',this,(args:any)=>{
....
})
}
ngOnDestroy(): void {
this.eventManager.unregisterEvent('closeModal',this)
}
}
방출 :
this.eventManager.emit("EVENT_NAME");
서비스 이벤트 : 구성 요소는 서비스 이벤트에 가입 할 수 있습니다. 예를 들어, 두 형제 구성 요소는 동일한 서비스 이벤트에 가입하고 각각의 모델을 수정하여 응답 할 수 있습니다. 이에 대한 자세한 내용은 아래를 참조하십시오.
하지만 부모 구성 요소가 파손되었을 때이를 구독 취소해야합니다.