| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							| 
									
										
										
										
											2020-05-19 12:08:49 -07:00
										 |  |  |  * Copyright Google LLC All Rights Reserved. | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Use of this source code is governed by an MIT-style license that can be | 
					
						
							|  |  |  |  * found in the LICENSE file at https://angular.io/license
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-13 16:40:21 -07:00
										 |  |  | import {Component, destroyPlatform, DoBootstrap, EventEmitter, Injector, Input, NgModule, Output} from '@angular/core'; | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  | import {BrowserModule} from '@angular/platform-browser'; | 
					
						
							|  |  |  | import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; | 
					
						
							| 
									
										
										
										
											2018-07-12 15:58:13 -07:00
										 |  |  | import {browserDetection} from '@angular/platform-browser/testing/src/browser_util'; | 
					
						
							| 
									
										
										
										
											2018-02-27 17:06:06 -05:00
										 |  |  | import {Subject} from 'rxjs'; | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-13 16:40:21 -07:00
										 |  |  | import {createCustomElement, NgElementConstructor} from '../src/create-custom-element'; | 
					
						
							| 
									
										
										
										
											2018-03-14 15:58:12 -07:00
										 |  |  | import {NgElementStrategy, NgElementStrategyEvent, NgElementStrategyFactory} from '../src/element-strategy'; | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | type WithFooBar = { | 
					
						
							|  |  |  |   fooFoo: string, | 
					
						
							|  |  |  |   barBar: string | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-12 15:58:13 -07:00
										 |  |  | if (browserDetection.supportsCustomElements) { | 
					
						
							| 
									
										
										
										
											2018-03-14 13:24:27 -07:00
										 |  |  |   describe('createCustomElement', () => { | 
					
						
							| 
									
										
										
										
											2020-05-20 11:10:26 +03:00
										 |  |  |     let selectorUid = 0; | 
					
						
							|  |  |  |     let testContainer: HTMLDivElement; | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  |     let NgElementCtor: NgElementConstructor<WithFooBar>; | 
					
						
							|  |  |  |     let strategy: TestStrategy; | 
					
						
							|  |  |  |     let strategyFactory: TestStrategyFactory; | 
					
						
							| 
									
										
										
										
											2018-03-01 22:34:21 -08:00
										 |  |  |     let injector: Injector; | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     beforeAll(done => { | 
					
						
							| 
									
										
										
										
											2020-05-20 11:10:26 +03:00
										 |  |  |       testContainer = document.createElement('div'); | 
					
						
							|  |  |  |       document.body.appendChild(testContainer); | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  |       destroyPlatform(); | 
					
						
							|  |  |  |       platformBrowserDynamic() | 
					
						
							|  |  |  |           .bootstrapModule(TestModule) | 
					
						
							|  |  |  |           .then(ref => { | 
					
						
							| 
									
										
										
										
											2018-03-01 22:34:21 -08:00
										 |  |  |             injector = ref.injector; | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  |             strategyFactory = new TestStrategyFactory(); | 
					
						
							|  |  |  |             strategy = strategyFactory.testStrategy; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:06:35 +03:00
										 |  |  |             NgElementCtor = createAndRegisterTestCustomElement(strategyFactory); | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  |           }) | 
					
						
							|  |  |  |           .then(done, done.fail); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-20 11:10:25 +03:00
										 |  |  |     afterEach(() => strategy.reset()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-20 11:10:26 +03:00
										 |  |  |     afterAll(() => { | 
					
						
							|  |  |  |       destroyPlatform(); | 
					
						
							|  |  |  |       document.body.removeChild(testContainer); | 
					
						
							|  |  |  |       (testContainer as any) = null; | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     it('should use a default strategy for converting component inputs', () => { | 
					
						
							|  |  |  |       expect(NgElementCtor.observedAttributes).toEqual(['foo-foo', 'barbar']); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should send input values from attributes when connected', () => { | 
					
						
							| 
									
										
										
										
											2018-03-06 14:02:25 -08:00
										 |  |  |       const element = new NgElementCtor(injector); | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  |       element.setAttribute('foo-foo', 'value-foo-foo'); | 
					
						
							|  |  |  |       element.setAttribute('barbar', 'value-barbar'); | 
					
						
							|  |  |  |       element.connectedCallback(); | 
					
						
							|  |  |  |       expect(strategy.connectedElement).toBe(element); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-02 10:08:16 -08:00
										 |  |  |       expect(strategy.getInputValue('fooFoo')).toBe('value-foo-foo'); | 
					
						
							|  |  |  |       expect(strategy.getInputValue('barBar')).toBe('value-barbar'); | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-04 20:45:31 +02:00
										 |  |  |     it('should work even if the constructor is not called (due to polyfill)', () => { | 
					
						
							| 
									
										
										
										
											2020-05-20 11:10:27 +03:00
										 |  |  |       // Some polyfills (e.g. `document-register-element`) do not call the constructor of custom
 | 
					
						
							|  |  |  |       // elements. Currently, all the constructor does is initialize the `injector` property. This
 | 
					
						
							|  |  |  |       // test simulates not having called the constructor by "unsetting" the property.
 | 
					
						
							|  |  |  |       //
 | 
					
						
							|  |  |  |       // NOTE:
 | 
					
						
							|  |  |  |       // If the constructor implementation changes in the future, this test needs to be adjusted
 | 
					
						
							|  |  |  |       // accordingly.
 | 
					
						
							|  |  |  |       const element = new NgElementCtor(injector); | 
					
						
							|  |  |  |       delete (element as any).injector; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       element.setAttribute('foo-foo', 'value-foo-foo'); | 
					
						
							|  |  |  |       element.setAttribute('barbar', 'value-barbar'); | 
					
						
							|  |  |  |       element.connectedCallback(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(strategy.connectedElement).toBe(element); | 
					
						
							|  |  |  |       expect(strategy.getInputValue('fooFoo')).toBe('value-foo-foo'); | 
					
						
							|  |  |  |       expect(strategy.getInputValue('barBar')).toBe('value-barbar'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  |     it('should listen to output events after connected', () => { | 
					
						
							| 
									
										
										
										
											2018-03-06 14:02:25 -08:00
										 |  |  |       const element = new NgElementCtor(injector); | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  |       element.connectedCallback(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       let eventValue: any = null; | 
					
						
							| 
									
										
										
										
											2019-06-14 12:19:09 +02:00
										 |  |  |       element.addEventListener('some-event', (e: Event) => eventValue = (e as CustomEvent).detail); | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  |       strategy.events.next({name: 'some-event', value: 'event-value'}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(eventValue).toEqual('event-value'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should not listen to output events after disconnected', () => { | 
					
						
							| 
									
										
										
										
											2018-03-06 14:02:25 -08:00
										 |  |  |       const element = new NgElementCtor(injector); | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  |       element.connectedCallback(); | 
					
						
							|  |  |  |       element.disconnectedCallback(); | 
					
						
							|  |  |  |       expect(strategy.disconnectCalled).toBe(true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       let eventValue: any = null; | 
					
						
							| 
									
										
										
										
											2019-06-14 12:19:09 +02:00
										 |  |  |       element.addEventListener('some-event', (e: Event) => eventValue = (e as CustomEvent).detail); | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  |       strategy.events.next({name: 'some-event', value: 'event-value'}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(eventValue).toEqual(null); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:06:35 +03:00
										 |  |  |     it('should listen to output events during initialization', () => { | 
					
						
							|  |  |  |       const events: string[] = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const element = new NgElementCtor(injector); | 
					
						
							|  |  |  |       element.addEventListener('strategy-event', evt => events.push((evt as CustomEvent).detail)); | 
					
						
							|  |  |  |       element.connectedCallback(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(events).toEqual(['connect']); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should not break if `NgElementStrategy#events` is not available before calling `NgElementStrategy#connect()`', | 
					
						
							|  |  |  |        () => { | 
					
						
							|  |  |  |          class TestStrategyWithLateEvents extends TestStrategy { | 
					
						
							|  |  |  |            events: Subject<NgElementStrategyEvent> = undefined!; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            connect(element: HTMLElement): void { | 
					
						
							|  |  |  |              this.connectedElement = element; | 
					
						
							|  |  |  |              this.events = new Subject<NgElementStrategyEvent>(); | 
					
						
							|  |  |  |              this.events.next({name: 'strategy-event', value: 'connect'}); | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const strategyWithLateEvents = new TestStrategyWithLateEvents(); | 
					
						
							|  |  |  |          const capturedEvents: string[] = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const NgElementCtorWithLateEventsStrategy = | 
					
						
							|  |  |  |              createAndRegisterTestCustomElement({create: () => strategyWithLateEvents}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const element = new NgElementCtorWithLateEventsStrategy(injector); | 
					
						
							|  |  |  |          element.addEventListener( | 
					
						
							|  |  |  |              'strategy-event', evt => capturedEvents.push((evt as CustomEvent).detail)); | 
					
						
							|  |  |  |          element.connectedCallback(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          // The "connect" event (emitted during initialization) was missed, but things didn't break.
 | 
					
						
							|  |  |  |          expect(capturedEvents).toEqual([]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          // Subsequent events are still captured.
 | 
					
						
							|  |  |  |          strategyWithLateEvents.events.next({name: 'strategy-event', value: 'after-connect'}); | 
					
						
							|  |  |  |          expect(capturedEvents).toEqual(['after-connect']); | 
					
						
							|  |  |  |        }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  |     it('should properly set getters/setters on the element', () => { | 
					
						
							| 
									
										
										
										
											2018-03-06 14:02:25 -08:00
										 |  |  |       const element = new NgElementCtor(injector); | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  |       element.fooFoo = 'foo-foo-value'; | 
					
						
							|  |  |  |       element.barBar = 'barBar-value'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(strategy.inputs.get('fooFoo')).toBe('foo-foo-value'); | 
					
						
							|  |  |  |       expect(strategy.inputs.get('barBar')).toBe('barBar-value'); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2020-05-20 11:10:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     it('should properly handle getting/setting properties on the element even if the constructor is not called', | 
					
						
							|  |  |  |        () => { | 
					
						
							|  |  |  |          // Create a custom element while ensuring that the `NgElementStrategy` is not created
 | 
					
						
							|  |  |  |          // inside the constructor. This is done to emulate the behavior of some polyfills that do
 | 
					
						
							|  |  |  |          // not call the constructor.
 | 
					
						
							|  |  |  |          strategyFactory.create = () => undefined as unknown as NgElementStrategy; | 
					
						
							|  |  |  |          const element = new NgElementCtor(injector); | 
					
						
							|  |  |  |          strategyFactory.create = TestStrategyFactory.prototype.create; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          element.fooFoo = 'foo-foo-value'; | 
					
						
							|  |  |  |          element.barBar = 'barBar-value'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          expect(strategy.inputs.get('fooFoo')).toBe('foo-foo-value'); | 
					
						
							|  |  |  |          expect(strategy.inputs.get('barBar')).toBe('barBar-value'); | 
					
						
							|  |  |  |        }); | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-20 11:10:26 +03:00
										 |  |  |     it('should capture properties set before upgrading the element', () => { | 
					
						
							|  |  |  |       // Create a regular element and set properties on it.
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:06:35 +03:00
										 |  |  |       const {selector, ElementCtor} = createTestCustomElement(strategyFactory); | 
					
						
							| 
									
										
										
										
											2020-05-20 11:10:26 +03:00
										 |  |  |       const element = Object.assign(document.createElement(selector), { | 
					
						
							|  |  |  |         fooFoo: 'foo-prop-value', | 
					
						
							|  |  |  |         barBar: 'bar-prop-value', | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       expect(element.fooFoo).toBe('foo-prop-value'); | 
					
						
							|  |  |  |       expect(element.barBar).toBe('bar-prop-value'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Upgrade the element to a Custom Element and insert it into the DOM.
 | 
					
						
							|  |  |  |       customElements.define(selector, ElementCtor); | 
					
						
							|  |  |  |       testContainer.appendChild(element); | 
					
						
							|  |  |  |       expect(element.fooFoo).toBe('foo-prop-value'); | 
					
						
							|  |  |  |       expect(element.barBar).toBe('bar-prop-value'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(strategy.inputs.get('fooFoo')).toBe('foo-prop-value'); | 
					
						
							|  |  |  |       expect(strategy.inputs.get('barBar')).toBe('bar-prop-value'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should capture properties set after upgrading the element but before inserting it into the DOM', | 
					
						
							|  |  |  |        () => { | 
					
						
							|  |  |  |          // Create a regular element and set properties on it.
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:06:35 +03:00
										 |  |  |          const {selector, ElementCtor} = createTestCustomElement(strategyFactory); | 
					
						
							| 
									
										
										
										
											2020-05-20 11:10:26 +03:00
										 |  |  |          const element = Object.assign(document.createElement(selector), { | 
					
						
							|  |  |  |            fooFoo: 'foo-prop-value', | 
					
						
							|  |  |  |            barBar: 'bar-prop-value', | 
					
						
							|  |  |  |          }); | 
					
						
							|  |  |  |          expect(element.fooFoo).toBe('foo-prop-value'); | 
					
						
							|  |  |  |          expect(element.barBar).toBe('bar-prop-value'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          // Upgrade the element to a Custom Element (without inserting it into the DOM) and update a
 | 
					
						
							|  |  |  |          // property.
 | 
					
						
							|  |  |  |          customElements.define(selector, ElementCtor); | 
					
						
							|  |  |  |          customElements.upgrade(element); | 
					
						
							|  |  |  |          element.barBar = 'bar-prop-value-2'; | 
					
						
							|  |  |  |          expect(element.fooFoo).toBe('foo-prop-value'); | 
					
						
							|  |  |  |          expect(element.barBar).toBe('bar-prop-value-2'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          // Insert the element into the DOM.
 | 
					
						
							|  |  |  |          testContainer.appendChild(element); | 
					
						
							|  |  |  |          expect(element.fooFoo).toBe('foo-prop-value'); | 
					
						
							|  |  |  |          expect(element.barBar).toBe('bar-prop-value-2'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          expect(strategy.inputs.get('fooFoo')).toBe('foo-prop-value'); | 
					
						
							|  |  |  |          expect(strategy.inputs.get('barBar')).toBe('bar-prop-value-2'); | 
					
						
							|  |  |  |        }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should allow overwriting properties with attributes after upgrading the element but before inserting it into the DOM', | 
					
						
							|  |  |  |        () => { | 
					
						
							|  |  |  |          // Create a regular element and set properties on it.
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:06:35 +03:00
										 |  |  |          const {selector, ElementCtor} = createTestCustomElement(strategyFactory); | 
					
						
							| 
									
										
										
										
											2020-05-20 11:10:26 +03:00
										 |  |  |          const element = Object.assign(document.createElement(selector), { | 
					
						
							|  |  |  |            fooFoo: 'foo-prop-value', | 
					
						
							|  |  |  |            barBar: 'bar-prop-value', | 
					
						
							|  |  |  |          }); | 
					
						
							|  |  |  |          expect(element.fooFoo).toBe('foo-prop-value'); | 
					
						
							|  |  |  |          expect(element.barBar).toBe('bar-prop-value'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          // Upgrade the element to a Custom Element (without inserting it into the DOM) and set an
 | 
					
						
							|  |  |  |          // attribute.
 | 
					
						
							|  |  |  |          customElements.define(selector, ElementCtor); | 
					
						
							|  |  |  |          customElements.upgrade(element); | 
					
						
							|  |  |  |          element.setAttribute('barbar', 'bar-attr-value'); | 
					
						
							|  |  |  |          expect(element.fooFoo).toBe('foo-prop-value'); | 
					
						
							|  |  |  |          expect(element.barBar).toBe('bar-attr-value'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          // Insert the element into the DOM.
 | 
					
						
							|  |  |  |          testContainer.appendChild(element); | 
					
						
							|  |  |  |          expect(element.fooFoo).toBe('foo-prop-value'); | 
					
						
							|  |  |  |          expect(element.barBar).toBe('bar-attr-value'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          expect(strategy.inputs.get('fooFoo')).toBe('foo-prop-value'); | 
					
						
							|  |  |  |          expect(strategy.inputs.get('barBar')).toBe('bar-attr-value'); | 
					
						
							|  |  |  |        }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-20 11:10:24 +03:00
										 |  |  |     // Helpers
 | 
					
						
							| 
									
										
										
										
											2020-06-13 11:06:35 +03:00
										 |  |  |     function createAndRegisterTestCustomElement(strategyFactory: NgElementStrategyFactory) { | 
					
						
							|  |  |  |       const {selector, ElementCtor} = createTestCustomElement(strategyFactory); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // The `@webcomponents/custom-elements/src/native-shim.js` polyfill allows us to create
 | 
					
						
							|  |  |  |       // new instances of the NgElement which extends HTMLElement, as long as we define it.
 | 
					
						
							|  |  |  |       customElements.define(selector, ElementCtor); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return ElementCtor; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function createTestCustomElement(strategyFactory: NgElementStrategyFactory) { | 
					
						
							| 
									
										
										
										
											2020-05-20 11:10:26 +03:00
										 |  |  |       return { | 
					
						
							|  |  |  |         selector: `test-element-${++selectorUid}`, | 
					
						
							|  |  |  |         ElementCtor: createCustomElement<WithFooBar>(TestComponent, {injector, strategyFactory}), | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-20 11:10:24 +03:00
										 |  |  |     @Component({ | 
					
						
							|  |  |  |       selector: 'test-component', | 
					
						
							|  |  |  |       template: 'TestComponent|foo({{ fooFoo }})|bar({{ barBar }})', | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |     class TestComponent { | 
					
						
							|  |  |  |       @Input() fooFoo: string = 'foo'; | 
					
						
							|  |  |  |       // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |       @Input('barbar') barBar!: string; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @Output() bazBaz = new EventEmitter<boolean>(); | 
					
						
							|  |  |  |       @Output('quxqux') quxQux = new EventEmitter<Object>(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     @NgModule({ | 
					
						
							|  |  |  |       imports: [BrowserModule], | 
					
						
							|  |  |  |       declarations: [TestComponent], | 
					
						
							|  |  |  |       entryComponents: [TestComponent], | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |     class TestModule implements DoBootstrap { | 
					
						
							|  |  |  |       ngDoBootstrap() {} | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class TestStrategy implements NgElementStrategy { | 
					
						
							|  |  |  |       connectedElement: HTMLElement|null = null; | 
					
						
							|  |  |  |       disconnectCalled = false; | 
					
						
							|  |  |  |       inputs = new Map<string, any>(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       events = new Subject<NgElementStrategyEvent>(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       connect(element: HTMLElement): void { | 
					
						
							| 
									
										
										
										
											2020-06-13 11:06:35 +03:00
										 |  |  |         this.events.next({name: 'strategy-event', value: 'connect'}); | 
					
						
							| 
									
										
										
										
											2020-05-20 11:10:24 +03:00
										 |  |  |         this.connectedElement = element; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       disconnect(): void { | 
					
						
							|  |  |  |         this.disconnectCalled = true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       getInputValue(propName: string): any { | 
					
						
							|  |  |  |         return this.inputs.get(propName); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       setInputValue(propName: string, value: string): void { | 
					
						
							|  |  |  |         this.inputs.set(propName, value); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2020-05-20 11:10:25 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |       reset(): void { | 
					
						
							|  |  |  |         this.connectedElement = null; | 
					
						
							|  |  |  |         this.disconnectCalled = false; | 
					
						
							|  |  |  |         this.inputs.clear(); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2020-05-20 11:10:24 +03:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class TestStrategyFactory implements NgElementStrategyFactory { | 
					
						
							|  |  |  |       testStrategy = new TestStrategy(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-20 11:10:27 +03:00
										 |  |  |       create(injector: Injector): NgElementStrategy { | 
					
						
							|  |  |  |         // Although not used by the `TestStrategy`, verify that the injector is provided.
 | 
					
						
							|  |  |  |         if (!injector) { | 
					
						
							|  |  |  |           throw new Error( | 
					
						
							|  |  |  |               'Expected injector to be passed to `TestStrategyFactory#create()`, but received ' + | 
					
						
							|  |  |  |               `value of type ${typeof injector}: ${injector}`); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-20 11:10:24 +03:00
										 |  |  |         return this.testStrategy; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2018-02-28 09:45:11 -08:00
										 |  |  | } |