Wydarzenia na świecie w Angular
Czy nie ma odpowiednika $scope.emit()
LUB $scope.broadcast()
w Angular?
Znam funkcjonalność EventEmitter
, ale z tego, co wiem, będzie to po prostu emitować Zdarzenie do nadrzędnego elementu HTML.
10 answers
Nie ma odpowiednika $scope.emit()
lub $scope.broadcast()
z AngularJS.
EventEmitter wewnątrz komponentu zbliża się, ale jak już wspomnieliście, będzie emitować Zdarzenie tylko do najbliższego komponentu nadrzędnego.
W Angular, są inne alternatywy, które postaram się wyjaśnić poniżej.
@input() bindings umożliwia połączenie Modelu aplikacji w ukierunkowanym wykresie obiektu (root do leaves). Domyślnym zachowaniem strategii detektora zmian komponentu jest propagacja wszystkich zmian do model aplikacji dla wszystkich wiązań z dowolnego podłączonego komponentu.
Na bok: istnieją dwa rodzaje modeli: Modele widoku i modele aplikacji. Model aplikacji jest połączony za pomocą wiązań @Input (). Model widoku jest tylko właściwością komponentu (nie ozdobioną znakiem @Input ()), która jest związana w szablonie komponentu.
Aby odpowiedzieć na twoje pytania:
Co jeśli muszę komunikować się między komponentami rodzeństwa?
Wspólna Aplikacja Model : Rodzeństwo może komunikować się za pomocą współdzielonego modelu aplikacji (podobnie jak angular 1). Na przykład, gdy jedno rodzeństwo zmienia model, drugie rodzeństwo, które ma powiązania z tym samym modelem, jest automatycznie aktualizowane.
Zdarzenia komponentu: Komponenty potomne mogą emitować Zdarzenie do komponentu nadrzędnego za pomocą wiązań @ Output (). Komponent nadrzędny może obsługiwać zdarzenie i manipulować modelem aplikacji lub własnym modelem widoku. Zmiany w Modele aplikacji są automatycznie propagowane do wszystkich komponentów, które bezpośrednio lub pośrednio wiążą się z tym samym modelem.
Zdarzenia Usługi : komponenty mogą subskrybować zdarzenia usługi. Na przykład dwa komponenty siostrzane mogą subskrybować to samo zdarzenie usługi i reagować, modyfikując swoje modele. Więcej na ten temat poniżej.
Jak mogę komunikować się między komponentem głównym a komponentem zagnieżdżonym na kilku poziomach głęboko?
- Shared Application Model : model aplikacji może być przekazany z głównego komponentu w dół do głęboko zagnieżdżonych pod-komponentów poprzez powiązania @Input (). Zmiany w modelu z dowolnego komponentu będą automatycznie propagowane do wszystkich komponentów, które mają ten sam model.
-
zdarzenia Usługi : Można również przenieść EventEmitter do usługi współdzielonej, która umożliwia dowolnemu komponentowi wstrzyknięcie usługi i subskrypcję zdarzenia. W ten sposób korzeń komponent może wywołać metodę usługi (zazwyczaj mutującą model), która z kolei emituje Zdarzenie. Kilka warstw w dół, komponent grand-child, który również wstrzyknął usługę i subskrybował to samo zdarzenie, może ją obsłużyć. Każda obsługa zdarzeń, która zmienia model współdzielonej aplikacji, będzie automatycznie propagowana do wszystkich komponentów, które od niej zależą. Jest to prawdopodobnie najbliższy odpowiednik
$scope.broadcast()
z kąta 1. Następny rozdział opisuje ten pomysł w bardziej szczegóły.
Przykład Obserwowalnej usługi, która wykorzystuje zdarzenia usługi do propagowania zmian
Oto przykład obserwowalnej usługi, która używa zdarzeń usługi do propagowania zmian. Po dodaniu TodoItem usługa emituje Zdarzenie powiadamiające subskrybentów komponentu.
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);
}
}
Oto jak komponent root zapisałby się do zdarzenia:
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;
}
}
Komponent potomny zagnieżdżony na kilku głębokich poziomach subskrybowałby Zdarzenie w ten sam sposób:
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;
}
}
Oto komponent, który wywołuje usługę w celu wywołania zdarzenia (może znajdować się w dowolnym miejscu w drzewie komponentów):
@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));
}
}
Referencja: wykrywanie zmian kątowych
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-16 21:36:41
Poniższy kod jako przykład zamiennika dla $ scope.emit () lub $ scope.broadcast () w Angular 2 za pomocą shared service do obsługi zdarzeń.
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
});
}
}
Przykładowe użycie:
Emisja:
function handleHttpError(error) {
this.eventsService.broadcast('http-error', error);
return ( Rx.Observable.throw(error) );
}
Słuchacz:
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();
});
}
}
Może obsługiwać wiele argumentów:
this.eventsService.broadcast('something', "Am I a?", "Should be b", "C?");
this.eventsService.on('something', function (a, b, c) {
console.log(a, b, c);
});
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-29 00:06:22
Używam usługi wiadomości, która zawija rxjs Subject
(TypeScript)
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);
}
}
Komponenty mogą subskrybować i nadawać zdarzenia (nadawca):
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();
}
}
(odbiorca)
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();
}
}
Metoda subscribe
MessageService
zwraca obiekt rxjs Subscription
, z którego można zrezygnować w następujący sposób:
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();
});
}
}
Zobacz też tę odpowiedź: https://stackoverflow.com/a/36782616/1861779
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-09 08:32:51
Nie używaj EventEmitter do komunikacji z serwisem.
Powinieneś użyć jednego z obserwowalnych typów. Osobiście lubię BehaviorSubject.
Prosty przykład:
Możesz przekazać stan początkowy, tutaj przekazuję null
Let subject = new BehaviorSubject (null);
Kiedy chcesz zaktualizować temat
Temat.next (myObject)
Obserwować z dowolnego serwisu lub komponentu i działać, gdy dostaje nowe aktualizacje.
Temat.subscribe (this.YOURMETHOD);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-24 03:31:36
Możesz użyć EventEmitter lub observables, aby utworzyć usługę eventbus, którą zarejestrujesz w DI. Każdy komponent, który chce uczestniczyć, żąda usługi jako parametru konstruktora i emituje i / lub subskrybuje zdarzenia.
Zobacz też
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:32
Stworzyłem próbkę pub-sub tutaj:
Http://www.syntaxsuccess.com/viewarticle/pub-sub-in-angular-2.0
Ideą jest użycie obiektów RxJs do podłączenia obserwatora i Obserwabli jako ogólnego rozwiązania do emitowania i subskrybowania niestandardowych zdarzeń. W mojej próbce używam obiektu Klienta do celów demonstracyjnych
this.pubSubService.Stream.emit(customer);
this.pubSubService.Stream.subscribe(customer => this.processCustomer(customer));
Tutaj jest również demo na żywo: http://www.syntaxsuccess.com/angular-2-samples/#/demo/pub-sub
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-11 04:02:28
Moim ulubionym sposobem jest użycie emitera obiektu zachowania lub zdarzenia (prawie tego samego) w mojej usłudze, aby kontrolować cały mój subkomponent.
Używając angular cli, Uruchom ng G S, aby utworzyć nową usługę, a następnie użyj BehaviorSubject lub 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);
}
}
Kiedy to zrobisz, każdy komponent korzystający z Twojej usługi jako dostawcy będzie świadomy tej zmiany. Po prostu zapisz się do wyniku, tak jak to robisz z 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
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-19 14:46:40
Zaimplementowaliśmy obserwowalną dyrektywę ngModelChange, która wysyła wszystkie zmiany modelu za pośrednictwem emitera zdarzeń, który tworzysz we własnym komponencie. Po prostu musisz powiązać emiter zdarzeń z dyrektywą.
Zobacz: https://github.com/atomicbits/angular2-modelchangeobservable
W html, bind your event emitter (countryChanged w tym przykładzie):
<input [(ngModel)]="country.name"
[modelChangeObservable]="countryChanged"
placeholder="Country"
name="country" id="country"></input>
W komponencie typescript wykonaj kilka operacji asynchronicznych na Eventemitterze:
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)
})
})
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-28 11:42:45
To jest moja wersja:
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});
}
}
Użycie:
export class <YOURCOMPONENT> implements IEventListener{
constructor(private eventManager: EventManagerService) {
this.eventManager.registerEvent('EVENT_NAME',this,(args:any)=>{
....
})
}
ngOnDestroy(): void {
this.eventManager.unregisterEvent('closeModal',this)
}
}
Emitować:
this.eventManager.emit("EVENT_NAME");
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-26 10:55:53
Zdarzenia Usługi: komponenty mogą subskrybować zdarzenia usługi. Na przykład dwa komponenty siostrzane mogą subskrybować to samo zdarzenie usługi i reagować, modyfikując swoje modele. Więcej na ten temat poniżej.
Ale pamiętaj, aby wypisać się z tego na destroy komponentu nadrzędnego.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-28 20:11:36