2016-03-23 24 views
5

Sto nidificando elementi personalizzati. Mi piacerebbe che l'elemento personalizzato genitore utilizzi metodi e proprietà dal prototipo dell'elemento personalizzato figlio. Per esempio.Come ottenere una richiamata quando un elemento personalizzato * ed i suoi figli * sono stati inizializzati

<script>  
var ChildElement = Object.create(HTMLElement.prototype); 

ChildElement.getName = function() { 
    return "Bob"; 
} 

document.registerElement("child-element", { 
    prototype: ChildElement 
}); 

var ParentElement = Object.create(HTMLElement.prototype); 

ParentElement.createdCallback = function() { 
    var self = this; 
    setTimeout(function() { 
    // This logs 'Bob', correctly 
    console.log(self.childNodes[0].getName()); 
    }, 0); 

    // This explodes - getName is not defined. 
    console.log(self.childNodes[0].getName()); 
}; 

document.registerElement("parent-element", { 
    prototype: ParentElement 
}); 
</script> 

<parent-element><child-element></child-element></parent-element> 

Come indicato in linea, il genitore non può leggere nulla che sia definito sul prototipo dell'elemento del bambino. Può farlo se fa scattare un setTimeout immediato; ha solo bisogno di aspettare che i nodi figli di questo elemento siano stati impostati.

Sembra questo accade a causa dell'ordine di richiamata durante la creazione elemento, che a mio avviso è qualcosa di simile:

  • prototipo del padre è impostato (da HTMLElement a parentElement)
  • createdCallback del genitore è chiamato
  • attachedCallback del genitore è chiamato
  • prototipo del bambino è impostata (da HTMLElement a ChildElement)
  • createdCallback del bambino è cal portato
  • attachedCallback del bambino si chiama

che gli incendi createdCallback a questo punto ha un senso, ma per quanto ne so non c'è callback disponibili a tutto quel fuoco quando tutti i tuoi figli sono stati creati. Penso che ciò significhi che è impossibile fare qualsiasi cosa sulla creazione che utilizza il prototipo dei tuoi elementi figli, senza usare setTimeout per aspettare che l'intera pagina finisca il rendering.

Esistono richiami o eventi che è possibile ascoltare dal genitore, da attivare solo dopo aver impostato anche il prototipo di tutti i nodi figlio? C'è un approccio diverso che ti permetterebbe di usare strutture come questa? C'è qualcos'altro che puoi fare, oltre ad attivare un setTimeout?

Sono convinto che gli elementi personalizzati siano stati progettati per consentire la parametrizzazione con altri contenuti di elementi e che gli elementi personalizzati effettivamente non supportati in tale contenuto siano piuttosto sorprendenti.

Probabilmente questo potrebbe essere considerato un duplicato di Prototype not defined when accessing children on creation of custom-tag. Comunque questa domanda è mal formulata, con esempi rotti, e l'unica risposta sembra essere effettivamente un bug di implementazione, non una soluzione (o almeno, non è più il comportamento attuale del browser)

risposta

3

In realtà, ci sono molti modi diversi per ottenere ciò con elementi personalizzati nidificati.

Il modo più diretto è quello di aggiungere un callback personalizzata per l'elemento principale che sarà chiamata dall'elemento bambino da suo metodo attachedCallback:

ParentElement.childAttachedCallback = function() 
{ 
    console.log(this.childNodes[0].getName()) 
} 

ChildElement.attachedCallback = function() 
{ 
    this.parentElement.childAttachedCallback() 
} 

In uno scenario complesso si può usare invece:

  • un oggetto Promise impostata dal genitore e risolvere da uno o più bambino,
  • eventi personalizzati sparati da bambino e catturati dal genitore,
  • a MutationObserver oggetto impostato per osservare le modifiche nell'elenco figlio del genitore ...