beforeChildren method
void
beforeChildren()
Implementation
void beforeChildren() {
if (hasViewContainer &&
!_providers.containsLocalProvider(Identifiers.viewContainerRefToken)) {
_providers.add(Identifiers.viewContainerRefToken, appViewContainer!);
}
// Access builtins with special visibility.
_providers.add(
Identifiers.changeDetectorRefToken,
componentView ?? o.thisExpr,
);
// ComponentLoader is currently just an alias for ViewContainerRef with
// a smaller API that is also usable outside of the context of a
// structural directive.
if (appViewContainer != null) {
_providers.add(Identifiers.componentLoaderToken, appViewContainer!);
}
_providers.addDirectiveProviders(_resolvedProvidersArray, _directives);
view!.registerDirectives(this, _directiveInstances);
directiveInstances = <ProviderSource?>[];
for (var directive in _directives) {
var directiveInstance = getDirectiveSource(directive);
directiveInstances.add(directiveInstance);
for (var queryMeta in directive.queries) {
_addQuery(queryMeta, directiveInstance);
}
}
var queriesWithReads = <_QueryWithRead>[];
for (var resolvedProvider in _resolvedProvidersArray) {
var queriesForProvider = _getQueriesFor(resolvedProvider.token);
queriesWithReads.addAll(
queriesForProvider.map(
(query) => _QueryWithRead(query, resolvedProvider.token),
),
);
}
// For each reference token create CompileTokenMetadata to read query.
if (referenceTokens.isNotEmpty) {
referenceTokens.forEach((String varName, token) {
var varValue = token != null
? _providers.get(token)!.build()
: renderNode.toReadExpr();
view!.nameResolver.addLocal(varName, varValue);
var varToken = CompileTokenMetadata(value: varName);
queriesWithReads.addAll(
_getQueriesFor(varToken)
.map((query) => _QueryWithRead(query, varToken)),
);
});
}
// For all @ViewChild(... read: Type) and references that map to locals,
// resolve value.
for (var queryWithRead in queriesWithReads) {
o.Expression? value;
o.Expression? changeDetectorRef;
if (queryWithRead.read.identifier != null) {
// Query for an identifier.
var providerSource = _providers.get(queryWithRead.read);
if (providerSource != null) {
value = providerSource.build();
changeDetectorRef = providerSource.buildChangeDetectorRef();
} else {
// Nothing publishes this token, so no query result can ever be
// assigned. Silently emitting no query leaves the annotated field
// permanently null, which only shows up as a null dereference at
// runtime, so fail the build instead.
//
// Thrown rather than reported via `CompileContext.reportAndRecover`:
// `throwRecoverableErrors` is only called from the template parser,
// so anything reported this late in view compilation is collected and
// never surfaced.
final read = queryWithRead.read.identifier!;
throw BuildError.withoutContext(
'No provider found for `read: ${read.name}` '
'(${read.moduleUrl}) on the query for '
'`${queryWithRead.query.metadata.propertyName}`.\n\n'
'The `read` token is matched by identity against what the element '
'publishes. A DOM element publishes `Element` and `HTMLElement` '
'from `package:web` -- note that the identically named `dart:html` '
'types are different tokens and will not match. Otherwise `read` '
'must name a directive on the element, `ElementRef`, '
'`TemplateRef`, or `ViewContainerRef`.',
);
}
} else {
// Query for a reference.
var token = referenceTokens.isNotEmpty
? referenceTokens[queryWithRead.read.value as String]
: null;
if (token != null) {
var providerSource = _providers.get(token);
if (providerSource != null) {
value = providerSource.build();
changeDetectorRef = providerSource.buildChangeDetectorRef();
}
} else {
// If we can't find a valid query type, then we fall back to
// ElementRef. HOWEVER, if specifically typed as Element or
// HtmlElement, use that.
value = queryWithRead.query.metadata.isElementType
? renderNode.toReadExpr()
: htmlElement;
}
}
if (value != null) {
queryWithRead.query.addQueryResult(view!, value, changeDetectorRef);
}
}
}