Intro
ci siamo imbattuti in questo oggi, e posso veramente vedere la necessità di questa implementazione in un sacco di applicazioni. Ora non posso garantire che questa sia la migliore tecnica al 100%, tuttavia mi sono impegnato a rendere questo approccio il più angoloso possibile.
L'approccio che ho trovato ha 2 fasi. Sia la fase 1 che la fase 2 aggiungeranno un totale di years * months + years * months * days
, quindi per 1 anno si avranno gli eventi 12 + 365
.
fase Ambito
Fase 1: eventi delegato quando un mese fa clic giù nel giorno stesso che è stato cliccato senza richiedere un evento il giorno.
Fase 2: Propagare il giorno scelto di nuovo al mese.
Poco prima scavare in, l'applicazione è costituito da 3 componenti che sono annidati nel seguente ordine: app => month => day
Ciò è tanto html che è richiesto. app.il componente ospita un numero di mesi, month.component ospita un numero di giorni e day.component non fa altro che visualizzarlo come testo.
app.component.html
<app-month *ngFor="let month of months" [data-month]="month"></app-month>
month.component.html
<app-day *ngFor="let day of days" [data-day]="day">{{day}}</app-day>
day.component.html
<ng-content></ng-content>
Questo è piuttosto roba standard di serie.
Fase 1
Diamo uno sguardo al month.component.ts
dove vogliamo delegare il nostro evento da.
// obtain a reference to the month(this) element
constructor(private element: ElementRef) { }
// when this component is clicked...
@HostListener('click', ['$event'])
public onMonthClick(event) {
// check to see whether the target element was a child or if it was in-fact this element
if (event.target != this.element.nativeElement) {
// if it was a child, then delegate our event to it.
// this is a little bit of javascript trickery where we are going to dispatch a custom event named 'delegateclick' on the target.
event.target.dispatchEvent(new CustomEvent('delegateEvent'));
}
}
Sia fase 1 e 2, v'è solo 1 avvertimento e che è; se si hanno nidificato elementi figlio all'interno della vostra day.component.html
, sarà necessario implementare uno spumeggiante per questo, una migliore logica nel senso che se dichiarazione, o un trucco veloce sarebbe .. in day.component.css
:host *{pointer-events: none;}
Ora abbiamo bisogno di raccontare la nostra day.component aspettarsi il nostro evento
delegateEvent
. Quindi, in
day.component.ts
tutto quello che dovete fare (nel modo più angolare possibile) è ...
@HostListener('delegateEvent', ['$event'])
public onEvent() {
console.log("i've been clicked via a delegate!");
}
Questo funziona perché dattiloscritto non si preoccupa se l'evento è nativo o no, sarà solo associare un nuovo evento javascript per l'elemento e quindi ci consente di chiamarlo "nativamente" tramite event.target.dispatchEvent
come facciamo in precedenza in month.component.ts
.
Concludendo la Fase 1, ora stiamo delegando con successo gli eventi dal nostro mese ai nostri giorni.
Fase 2
Che cosa succede se diciamo vuole correre un po 'di logica nel nostro evento delegato entro day.component
e poi tornare a month.component
- in modo che possa poi proseguire con la sua possedere la funzionalità in un metodo molto orientato agli oggetti? Bene per fortuna, possiamo facilmente implementarlo!
Nell'aggiornamento month.component.ts
di seguito. Tutto ciò che è cambiato è che ora stiamo per passare una funzione con la nostra invocazione all'evento e abbiamo definito la nostra funzione di callback.
@HostListener('click', ['$event'])
public onMonthClick(event) {
if (event.target != this.element.nativeElement) {
event.target.dispatchEvent(new CustomEvent('delegateEvent', { detail: this.eventDelegateCallback}));
}
}
public eventDelegateCallback(data) {
console.log(data);
}
Tutto ciò che rimane è quello di richiamare questa funzione all'interno day.component.ts
...
public onEvent(event) {
// run whatever logic you like,
//return whatever data you like to month.component
event.detail(this.day);
}
Purtroppo la nostra funzione di callback è un po 'ambiguo di nome qui, tuttavia dattiloscritto si lamenterà la proprietà non essendo un oggetto definito letterale CustomEventInit
se chiamato in altro modo.
Imbuto eventi Diverse
L'altra cosa interessante di questo approccio è che non si dovrebbe mai essere necessario definire più di questo numero di eventi, perché si può solo incanalare tutti gli eventi attraverso questa delega e quindi eseguire la logica entro day.component.ts
per filtrare per event.type
...
month.component.ts
@HostListener('click', ['$event'])
@HostListener('mouseover', ['$event'])
@HostListener('mouseout', ['$event'])
public onMonthEvent(event) {
if (event.target != this.element.nativeElement) {
event.target.dispatchEvent(new CustomEvent('delegateEvent', { detail: this.eventDelegateCallback }));
}
}
day.component.ts
private eventDelegateCallback: any;
@HostListener('delegateEvent', ['$event'])
public onEvent(event) {
this.eventDelegateCallback = event.detail;
if(event.type == "click"){
// run click stuff
this.eventDelegateCallback(this.day)
}
}
Ci sono moduli autonomi che gestisce questo. Trovo che "dom-delegate" funzioni molto bene. Non c'è niente di built-in in ng2 per quanto ne so. – Chrillewoodz
Se questo è un problema ... sarebbe un problema di ottimizzazione in angolare. Non dovresti preoccuparti di aggregare eventi per ottimizzare. –
Ho avuto un problema simile alcuni mesi fa, da quello che so, il metodo che hai descritto è il modo migliore per farlo con il raw angolare. controllando i target di clic con meno ascoltatori di eventi. l'unica cosa che suggerirei è mettere la logica in un servizio o in una direttiva (la direttiva potrebbe funzionare meglio dal momento che lo si desidera ogni div ogni mese) in questo modo il codice è pulito e separato dal componente. Dopo tutto, è la logica html, non la logica dei componenti – FussinHussin