| 593 | } |
| 594 | |
| 595 | override setInput(name: string, value: unknown): void { |
| 596 | if (this._hasInputBindings && ngDevMode) { |
| 597 | throw new RuntimeError( |
| 598 | RuntimeErrorCode.INVALID_SET_INPUT_CALL, |
| 599 | 'Cannot call `setInput` on a component that is using the `inputBinding` or `twoWayBinding` functions.', |
| 600 | ); |
| 601 | } |
| 602 | |
| 603 | const tNode = this._tNode; |
| 604 | this.previousInputValues ??= new Map(); |
| 605 | // Do not set the input if it is the same as the last value |
| 606 | // This behavior matches `bindingUpdated` when binding inputs in templates. |
| 607 | if ( |
| 608 | this.previousInputValues.has(name) && |
| 609 | Object.is(this.previousInputValues.get(name), value) |
| 610 | ) { |
| 611 | return; |
| 612 | } |
| 613 | |
| 614 | const lView = this._rootLView; |
| 615 | const hasSetInput = setAllInputsForProperty(tNode, lView[TVIEW], lView, name, value); |
| 616 | this.previousInputValues.set(name, value); |
| 617 | const childComponentLView = getComponentLViewByIndex(tNode.index, lView); |
| 618 | markViewDirty(childComponentLView, NotificationSource.SetInput); |
| 619 | |
| 620 | if (ngDevMode && !hasSetInput) { |
| 621 | const cmpNameForError = stringifyForError(this.componentType); |
| 622 | let message = `Can't set value of the '${name}' input on the '${cmpNameForError}' component. `; |
| 623 | message += `Make sure that the '${name}' property is declared as an input using the input() or model() function or the @Input() decorator.`; |
| 624 | reportUnknownPropertyError(message); |
| 625 | } |
| 626 | } |
| 627 | |
| 628 | override get injector(): Injector { |
| 629 | return new NodeInjector(this._tNode, this._rootLView); |