import { Directive , DoCheck , Inject , Injector , Input , KeyValueChanges , KeyValueDiffers , Optional , Renderer2 , Type , } from '@angular/core' ; import { DynamicComponentInjector , DynamicComponentInjectorToken , } from '../component-injector' ; export interface AttributesMap { [ key ] : string ; } interface AttributeActions { set : AttributesMap ; remove : string [ ] ; } @ Directive ( { selector : '[ndcDynamicAttributes],[ngComponentOutletNdcDynamicAttributes]' , exportAs : 'ndcDynamicAttributes' , } ) export class DynamicAttributesDirective implements DoCheck { @ Input ( ) ndcDynamicAttributes : AttributesMap ; @ Input ( ) ngComponentOutletNdcDynamicAttributes : AttributesMap ; private attrsDiffer = this . differs . find ( { } ) . create < string , string > ( ) ; private lastCompType : Type < any > ; private lastAttrActions : AttributeActions ; private get _attributes ( ) { return ( this . ndcDynamicAttributes || this . ngComponentOutletNdcDynamicAttributes ) ; } private get _nativeElement ( ) { return this . componentInjector . componentRef ?. location . nativeElement ; } private get _compType ( ) { return this . componentInjector . componentRef ?. componentType ; } private get _isCompChanged ( ) { if ( this . lastCompType !== this . _compType ) { this . lastCompType = this . _compType ; return true ; } return false ; } constructor ( private renderer , private differs , private injector , @ Inject ( DynamicComponentInjectorToken ) @ Optional ( ) private componentInjector ? ) { } ngDoCheck ( ) { const isCompChanged = this . _isCompChanged ; const changes = this . attrsDiffer . diff ( this . _attributes ) ; if ( changes ) { this . lastAttrActions = this . _changesToAttrActions ( changes ) ; } if ( changes || ( isCompChanged && this . lastAttrActions ) ) { this . _updateAttributes ( this . lastAttrActions ) ; } } setAttribute ( name , value , namespace ? ) { if ( this . _nativeElement ) { this . renderer . setAttribute ( this . _nativeElement , name , value , namespace ) ; } } removeAttribute ( name , namespace ? ) { if ( this . _nativeElement ) { this . renderer . removeAttribute ( this . _nativeElement , name , namespace ) ; } } private _updateAttributes ( actions ) { if ( ! this . _compType ) { return ; } Object . keys ( actions . set ) . forEach ( ( key ) => this . setAttribute ( key , actions . set [ key ] ) ) ; actions . remove . forEach ( ( key ) => this . removeAttribute ( key ) ) ; } private _changesToAttrActions ( changes ) { const attrActions = { set : { } , remove : [ ] , } ; changes . forEachAddedItem ( ( r ) => ( attrActions . set [ r . key ] = r . currentValue ) ) ; changes . forEachChangedItem ( ( r ) => ( attrActions . set [ r . key ] = r . currentValue ) ) ; changes . forEachRemovedItem ( ( r ) => attrActions . remove . push ( r . key ) ) ; return attrActions ; } }