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);
    }
  }
}