@@ -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,21 +75,24 @@ 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' ;
8991import { ChainedInjector } from './chained_injector' ;
9092import { unregisterLView } from './interfaces/lview_tracking' ;
9193import { executeContentQueries } from './queries/query_execution' ;
92- import { createElementNode } from './dom_node_manipulation' ;
94+ import { AttributeMarker } from './interfaces/attribute_marker' ;
95+ import { CssSelector } from './interfaces/projection' ;
9396
9497export class ComponentFactoryResolver extends AbstractComponentFactoryResolver {
9598 /**
@@ -158,6 +161,18 @@ function getNamespace(elementName: string): string | null {
158161 return name === 'svg' ? SVG_NAMESPACE : name === 'math' ? MATH_ML_NAMESPACE : null ;
159162}
160163
164+ // TODO(pk): change the extractAttrsAndClassesFromSelector so it returns TAttributes already?
165+ function getRootTAttributesFromSelector ( selector : CssSelector ) {
166+ const { attrs, classes} = extractAttrsAndClassesFromSelector ( selector ) ;
167+
168+ const tAtts : TAttributes = attrs ;
169+ if ( classes . length ) {
170+ tAtts . push ( AttributeMarker . Classes , ...classes ) ;
171+ }
172+
173+ return tAtts ;
174+ }
175+
161176/**
162177 * ComponentFactory interface implementation.
163178 */
@@ -355,27 +370,39 @@ export class ComponentFactory<T> extends AbstractComponentFactory<T> {
355370 }
356371
357372 const hostTNode = createRootComponentTNode ( rootLView , hostRNode ) ;
373+ // 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.
374+ const tAttributes = rootSelectorOrNode
375+ ? [ 'ng-version' , '0.0.0-PLACEHOLDER' ]
376+ : // Extract attributes and classes from the first selector only to match VE behavior.
377+ getRootTAttributesFromSelector ( this . componentDef . selectors [ 0 ] ) ;
378+
379+ for ( const def of rootDirectives ) {
380+ hostTNode . mergedAttrs = mergeHostAttrs ( hostTNode . mergedAttrs , def . hostAttrs ) ;
381+ }
382+ hostTNode . mergedAttrs = mergeHostAttrs ( hostTNode . mergedAttrs , tAttributes ) ;
383+
384+ computeStaticStyling ( hostTNode , hostTNode . mergedAttrs , true ) ;
385+
386+ // TODO(crisbeto): in practice `hostRNode` should always be defined, but there are some
387+ // tests where the renderer is mocked out and `undefined` is returned. We should update the
388+ // tests so that this check can be removed.
389+ if ( hostRNode ) {
390+ setupStaticAttributes ( hostRenderer , hostRNode , hostTNode ) ;
391+ }
392+
358393 componentView = createRootComponentView (
359394 hostTNode ,
360395 hostRNode ,
361396 rootComponentDef ,
362397 rootDirectives ,
363398 rootLView ,
364399 environment ,
365- hostRenderer ,
366400 ) ;
367401
368402 tElementNode = getTNode ( rootTView , HEADER_OFFSET ) as TElementNode ;
369403
370- // TODO(crisbeto): in practice `hostRNode` should always be defined, but there are some
371- // tests where the renderer is mocked out and `undefined` is returned. We should update the
372- // tests so that this check can be removed.
373- if ( hostRNode ) {
374- setRootNodeAttributes ( hostRenderer , rootComponentDef , hostRNode , rootSelectorOrNode ) ;
375- }
376-
377404 if ( projectableNodes !== undefined ) {
378- projectNodes ( tElementNode , this . ngContentSelectors , projectableNodes ) ;
405+ projectNodes ( hostTNode , this . ngContentSelectors , projectableNodes ) ;
379406 }
380407
381408 // TODO: should LifecycleHooksFeature and other host features be generated by the compiler
@@ -523,10 +550,8 @@ function createRootComponentView(
523550 rootDirectives : DirectiveDef < any > [ ] ,
524551 rootView : LView ,
525552 environment : LViewEnvironment ,
526- hostRenderer : Renderer ,
527553) : LView {
528554 const tView = rootView [ TVIEW ] ;
529- applyRootComponentStyling ( rootDirectives , tNode , hostRNode , hostRenderer ) ;
530555
531556 // Hydration info is on the host element and needs to be retrieved
532557 // and passed to the component LView.
@@ -559,26 +584,6 @@ function createRootComponentView(
559584 return ( rootView [ tNode . index ] = componentView ) ;
560585}
561586
562- /** Sets up the styling information on a root component. */
563- function applyRootComponentStyling (
564- rootDirectives : DirectiveDef < any > [ ] ,
565- tNode : TElementNode ,
566- rNode : RElement | null ,
567- hostRenderer : Renderer ,
568- ) : void {
569- for ( const def of rootDirectives ) {
570- tNode . mergedAttrs = mergeHostAttrs ( tNode . mergedAttrs , def . hostAttrs ) ;
571- }
572-
573- if ( tNode . mergedAttrs !== null ) {
574- computeStaticStyling ( tNode , tNode . mergedAttrs , true ) ;
575-
576- if ( rNode !== null ) {
577- setupStaticAttributes ( hostRenderer , rNode , tNode ) ;
578- }
579- }
580- }
581-
582587/**
583588 * Creates a root component and sets it up with features and host bindings.Shared by
584589 * renderComponent() and ViewContainerRef.createComponent().
@@ -635,30 +640,6 @@ function createRootComponent<T>(
635640 return component ;
636641}
637642
638- /** Sets the static attributes on a root component. */
639- function setRootNodeAttributes (
640- hostRenderer : Renderer2 ,
641- componentDef : ComponentDef < unknown > ,
642- hostRNode : RElement ,
643- rootSelectorOrNode : any ,
644- ) {
645- if ( rootSelectorOrNode ) {
646- // The placeholder will be replaced with the actual version at build time.
647- setUpAttributes ( hostRenderer , hostRNode , [ 'ng-version' , '0.0.0-PLACEHOLDER' ] ) ;
648- } else {
649- // If host element is created as a part of this function call (i.e. `rootSelectorOrNode`
650- // is not defined), also apply attributes and classes extracted from component selector.
651- // Extract attributes and classes from the first selector only to match VE behavior.
652- const { attrs, classes} = extractAttrsAndClassesFromSelector ( componentDef . selectors [ 0 ] ) ;
653- if ( attrs ) {
654- setUpAttributes ( hostRenderer , hostRNode , attrs ) ;
655- }
656- if ( classes && classes . length > 0 ) {
657- writeDirectClass ( hostRenderer , hostRNode , classes . join ( ' ' ) ) ;
658- }
659- }
660- }
661-
662643/** Projects the `projectableNodes` that were specified when creating a root component. */
663644function projectNodes (
664645 tNode : TElementNode ,
0 commit comments