( component: Type<any>, config: NgElementConfig, )
| 130 | * @publicApi |
| 131 | */ |
| 132 | export function createCustomElement<P>( |
| 133 | component: Type<any>, |
| 134 | config: NgElementConfig, |
| 135 | ): NgElementConstructor<P> { |
| 136 | const inputs = getComponentInputs(component, config.injector); |
| 137 | |
| 138 | const strategyFactory = |
| 139 | config.strategyFactory || new ComponentNgElementStrategyFactory(component); |
| 140 | |
| 141 | const attributeToPropertyInputs = getDefaultAttributeToPropertyInputs(inputs); |
| 142 | |
| 143 | class NgElementImpl extends NgElement { |
| 144 | // Work around a bug in closure typed optimizations(b/79557487) where it is not honoring static |
| 145 | // field externs. So using quoted access to explicitly prevent renaming. |
| 146 | static readonly ['observedAttributes'] = Object.keys(attributeToPropertyInputs); |
| 147 | |
| 148 | protected override get ngElementStrategy(): NgElementStrategy { |
| 149 | // TODO(andrewseguin): Add e2e tests that cover cases where the constructor isn't called. For |
| 150 | // now this is tested using a Google internal test suite. |
| 151 | if (!this._ngElementStrategy) { |
| 152 | const strategy = (this._ngElementStrategy = strategyFactory.create( |
| 153 | this.injector || config.injector, |
| 154 | )); |
| 155 | |
| 156 | // Re-apply pre-existing input values (set as properties on the element) through the |
| 157 | // strategy. |
| 158 | // TODO(alxhub): why are we doing this? this makes no sense. |
| 159 | inputs.forEach(({propName, transform}) => { |
| 160 | if (!this.hasOwnProperty(propName)) { |
| 161 | // No pre-existing value for `propName`. |
| 162 | return; |
| 163 | } |
| 164 | |
| 165 | // Delete the property from the DOM node and re-apply it through the strategy. |
| 166 | const value = (this as any)[propName]; |
| 167 | delete (this as any)[propName]; |
| 168 | strategy.setInputValue(propName, value, transform); |
| 169 | }); |
| 170 | } |
| 171 | |
| 172 | return this._ngElementStrategy!; |
| 173 | } |
| 174 | |
| 175 | private _ngElementStrategy?: NgElementStrategy; |
| 176 | |
| 177 | constructor(private readonly injector?: Injector) { |
| 178 | super(); |
| 179 | } |
| 180 | |
| 181 | override attributeChangedCallback( |
| 182 | attrName: string, |
| 183 | oldValue: string | null, |
| 184 | newValue: string, |
| 185 | namespace?: string, |
| 186 | ): void { |
| 187 | const [propName, transform] = attributeToPropertyInputs[attrName]!; |
| 188 | this.ngElementStrategy.setInputValue(propName, newValue, transform); |
| 189 | } |
no test coverage detected
searching dependent graphs…