I'm having trouble understanding when access to the shadowRoot of a component is available. Here is an image of a set of nested components:
So there are a handful of components:
- MortgageDetails: Component binding together a group of 3 other components
- MoneyInput - Input component with Amount label
- NumWithUnitsInput - Input component with Term label
- RateInput - Input component with Rate label
- PaymentSchedule: Component with corresponding label
- DateInput: Component with Start Date label
I've instrumented the created and attached methods with log message printing the shadowRoot ( sr => ...) and I get the following:
mortgageDetails [FINE]: MortgageDetails created sr => null (:1)
moneyInput [FINE]: MoneyInput created sr => null (:1)
numWithUnitsInput [FINE]: NumWithUnitsInput created sr => null (:1)
rateInput [FINE]: RateInput created sr => null (:1)
paymentSchedule [FINE]: PaymentSchedule created sr => null (:1)
dateInput [FINE]: DateInput created sr => null (:1)
mortgageDetails [FINE]: MortgageDetails attached with sr => Instance of 'ShadowRoot' (:1)
The logging makes sense. Components are created in a reasonable order and then the attaching starts. The problem is though, the mortgage details is attached before its contained moneyInput is attached. If I add one more log statement in the MortgageDetails.attached I can see that its contained MoneyInput object has a shadowRoot:
mortgageDetails [FINE]: Composed moneyInput sr => Instance of 'ShadowRoot' (:1)
This is a problem for the way I'm doing things. I need some initialization event in the MoneyInput component to reach into the shadowRoot and attach some handlers. I can't use created because shadowRoot is not even set yet. I'm trying to use attached. I have code like this currently in the attach of MoneyInput:
_amountElement = shadowRoot.querySelector('#money-amount')
..onBlur.listen((evt) => reformatAmount())
..onFocus.listen((evt) => reformatAmount())
..onKeyUp.listen((evt) { if(evt.which == 13) reformatAmount(); });
Since MortgageDetails is being attached and MoneyInput has not yet been attached, an instance of MortgageDetails can not use the contained MoneyInput as it would like as it is not fully initialized. For example, in MortgageDetails activate I have:
(mortgageAmountInput = $["mortgage-amount"] as MoneyInput)
..label = r" $ Amount of Loan"
..onBlur.listen((_) => recalc())
..onFocus.listen((_) => recalc());
This fails because MoneyInput's activate has not been called. I think what I really need is an event that says the shadowRoot has been set, then on that event I could do my initialization.
What am I missing on the lifecycle of polymer elements?