@@ -26,7 +26,7 @@ import {
2626import { ComponentFactoryResolver as AbstractComponentFactoryResolver } from '../linker/component_factory_resolver' ;
2727import { createElementRef , ElementRef } from '../linker/element_ref' ;
2828import { NgModuleRef } from '../linker/ng_module_factory' ;
29- import { Renderer2 , RendererFactory2 } from '../render/api' ;
29+ import { RendererFactory2 } from '../render/api' ;
3030import { Sanitizer } from '../sanitization/sanitizer' ;
3131import { assertDefined , assertGreaterThan , assertIndexInRange } from '../util/assert' ;
3232
@@ -56,13 +56,13 @@ import {ComponentDef, DirectiveDef, HostDirectiveDefs} from './interfaces/defini
5656import { InputFlags } from './interfaces/input_flags' ;
5757import {
5858 NodeInputBindings ,
59+ TAttributes ,
5960 TContainerNode ,
6061 TElementContainerNode ,
6162 TElementNode ,
6263 TNode ,
6364 TNodeType ,
6465} from './interfaces/node' ;
65- import { Renderer } from './interfaces/renderer' ;
6666import { RElement , RNode } from './interfaces/renderer_dom' ;
6767import {
6868 CONTEXT ,
@@ -75,14 +75,16 @@ import {
7575 TViewType ,
7676} from './interfaces/view' ;
7777import { MATH_ML_NAMESPACE , SVG_NAMESPACE } from './namespaces' ;
78- import { setupStaticAttributes , writeDirectClass } from './node_manipulation' ;
78+
79+ import { createElementNode } from './dom_node_manipulation' ;
80+ import { setupStaticAttributes } from './node_manipulation' ;
7981import {
8082 extractAttrsAndClassesFromSelector ,
8183 stringifyCSSSelectorList ,
8284} from './node_selector_matcher' ;
8385import { enterView , getCurrentTNode , getLView , leaveView } from './state' ;
8486import { computeStaticStyling } from './styling/static_styling' ;
85- import { mergeHostAttrs , setUpAttributes } from './util/attrs_utils' ;
87+ import { mergeHostAttrs } from './util/attrs_utils' ;
8688import { debugStringifyTypeForError , stringifyForError } from './util/stringify_utils' ;
8789import { getComponentLViewByIndex , getNativeByTNode , getTNode } from './util/view_utils' ;
8890import { ViewRef } from './view_ref' ;
@@ -91,7 +93,8 @@ import {unregisterLView} from './interfaces/lview_tracking';
9193import { profiler } from './profiler' ;
9294import { ProfilerEvent } from './profiler_types' ;
9395import { executeContentQueries } from './queries/query_execution' ;
94- import { createElementNode } from './dom_node_manipulation' ;
96+ import { AttributeMarker } from './interfaces/attribute_marker' ;
97+ import { CssSelector } from './interfaces/projection' ;
9598
9699export class ComponentFactoryResolver extends AbstractComponentFactoryResolver {
97100 /**
@@ -160,6 +163,18 @@ function getNamespace(elementName: string): string | null {
160163 return name === 'svg' ? SVG_NAMESPACE : name === 'math' ? MATH_ML_NAMESPACE : null ;
161164}
162165
166+ // TODO(pk): change the extractAttrsAndClassesFromSelector so it returns TAttributes already?
167+ function getRootTAttributesFromSelector ( selector : CssSelector ) {
168+ const { attrs, classes} = extractAttrsAndClassesFromSelector ( selector ) ;
169+
170+ const tAtts : TAttributes = attrs ;
171+ if ( classes . length ) {
172+ tAtts . push ( AttributeMarker . Classes , ...classes ) ;
173+ }
174+
175+ return tAtts ;
176+ }
177+
163178/**
164179 * ComponentFactory interface implementation.
165180 */
@@ -359,27 +374,39 @@ export class ComponentFactory<T> extends AbstractComponentFactory<T> {
359374 }
360375
361376 const hostTNode = createRootComponentTNode ( rootLView , hostRNode ) ;
377+ // If host dom element is created (instead of being provided as part of the dynamic component creation), also apply attributes and classes extracted from component selector.
378+ const tAttributes = rootSelectorOrNode
379+ ? [ 'ng-version' , '0.0.0-PLACEHOLDER' ]
380+ : // Extract attributes and classes from the first selector only to match VE behavior.
381+ getRootTAttributesFromSelector ( this . componentDef . selectors [ 0 ] ) ;
382+
383+ for ( const def of rootDirectives ) {
384+ hostTNode . mergedAttrs = mergeHostAttrs ( hostTNode . mergedAttrs , def . hostAttrs ) ;
385+ }
386+ hostTNode . mergedAttrs = mergeHostAttrs ( hostTNode . mergedAttrs , tAttributes ) ;
387+
388+ computeStaticStyling ( hostTNode , hostTNode . mergedAttrs , true ) ;
389+
390+ // TODO(crisbeto): in practice `hostRNode` should always be defined, but there are some
391+ // tests where the renderer is mocked out and `undefined` is returned. We should update the
392+ // tests so that this check can be removed.
393+ if ( hostRNode ) {
394+ setupStaticAttributes ( hostRenderer , hostRNode , hostTNode ) ;
395+ }
396+
362397 componentView = createRootComponentView (
363398 hostTNode ,
364399 hostRNode ,
365400 rootComponentDef ,
366401 rootDirectives ,
367402 rootLView ,
368403 environment ,
369- hostRenderer ,
370404 ) ;
371405
372406 tElementNode = getTNode ( rootTView , HEADER_OFFSET ) as TElementNode ;
373407
374- // TODO(crisbeto): in practice `hostRNode` should always be defined, but there are some
375- // tests where the renderer is mocked out and `undefined` is returned. We should update the
376- // tests so that this check can be removed.
377- if ( hostRNode ) {
378- setRootNodeAttributes ( hostRenderer , rootComponentDef , hostRNode , rootSelectorOrNode ) ;
379- }
380-
381408 if ( projectableNodes !== undefined ) {
382- projectNodes ( tElementNode , this . ngContentSelectors , projectableNodes ) ;
409+ projectNodes ( hostTNode , this . ngContentSelectors , projectableNodes ) ;
383410 }
384411
385412 // TODO: should LifecycleHooksFeature and other host features be generated by the compiler
@@ -528,10 +555,8 @@ function createRootComponentView(
528555 rootDirectives : DirectiveDef < any > [ ] ,
529556 rootView : LView ,
530557 environment : LViewEnvironment ,
531- hostRenderer : Renderer ,
532558) : LView {
533559 const tView = rootView [ TVIEW ] ;
534- applyRootComponentStyling ( rootDirectives , tNode , hostRNode , hostRenderer ) ;
535560
536561 // Hydration info is on the host element and needs to be retrieved
537562 // and passed to the component LView.
@@ -564,26 +589,6 @@ function createRootComponentView(
564589 return ( rootView [ tNode . index ] = componentView ) ;
565590}
566591
567- /** Sets up the styling information on a root component. */
568- function applyRootComponentStyling (
569- rootDirectives : DirectiveDef < any > [ ] ,
570- tNode : TElementNode ,
571- rNode : RElement | null ,
572- hostRenderer : Renderer ,
573- ) : void {
574- for ( const def of rootDirectives ) {
575- tNode . mergedAttrs = mergeHostAttrs ( tNode . mergedAttrs , def . hostAttrs ) ;
576- }
577-
578- if ( tNode . mergedAttrs !== null ) {
579- computeStaticStyling ( tNode , tNode . mergedAttrs , true ) ;
580-
581- if ( rNode !== null ) {
582- setupStaticAttributes ( hostRenderer , rNode , tNode ) ;
583- }
584- }
585- }
586-
587592/**
588593 * Creates a root component and sets it up with features and host bindings.Shared by
589594 * renderComponent() and ViewContainerRef.createComponent().
@@ -640,30 +645,6 @@ function createRootComponent<T>(
640645 return component ;
641646}
642647
643- /** Sets the static attributes on a root component. */
644- function setRootNodeAttributes (
645- hostRenderer : Renderer2 ,
646- componentDef : ComponentDef < unknown > ,
647- hostRNode : RElement ,
648- rootSelectorOrNode : any ,
649- ) {
650- if ( rootSelectorOrNode ) {
651- // The placeholder will be replaced with the actual version at build time.
652- setUpAttributes ( hostRenderer , hostRNode , [ 'ng-version' , '0.0.0-PLACEHOLDER' ] ) ;
653- } else {
654- // If host element is created as a part of this function call (i.e. `rootSelectorOrNode`
655- // is not defined), also apply attributes and classes extracted from component selector.
656- // Extract attributes and classes from the first selector only to match VE behavior.
657- const { attrs, classes} = extractAttrsAndClassesFromSelector ( componentDef . selectors [ 0 ] ) ;
658- if ( attrs ) {
659- setUpAttributes ( hostRenderer , hostRNode , attrs ) ;
660- }
661- if ( classes && classes . length > 0 ) {
662- writeDirectClass ( hostRenderer , hostRNode , classes . join ( ' ' ) ) ;
663- }
664- }
665- }
666-
667648/** Projects the `projectableNodes` that were specified when creating a root component. */
668649function projectNodes (
669650 tNode : TElementNode ,
0 commit comments