angular: @Directive @Hostbinding cannot set @Input of @Component

I’m submitting a bug

[X] bug report => search github for a similar issue or PR before submitting
[ ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior This is an issue similar to #10499. There seems to be a problem whereby an @Directive cannot set an @Component input property. Meaning if you apply a directive to the component’s tag and have said directive set the component’s input property using an @Hostbinding it throws the following error:

Can't bind to 'X' since it isn't a known property of 'X'.

Expected behavior I hoped it would be possible to set an Component’s input property using a simple Directive. Though I would also understand that if this is by design. If it’s by design then i think the error message reported back to the user should be improved as it doesn’t clearly indicate why it isn’t work as the programmer might expect it to work.

Minimal reproduction of the problem with instructions https://plnkr.co/edit/V2KBlhbv7AciGfEi0lkE

What is the motivation / use case for changing the behavior? There are a few use cases that would be simplified by having the ability for having an @Directive being able to set the component’s Input property without modifications to the source Component. One of the use cases highlighted in the example above resolves around the md-input from @angular/material2 (using an external library over which you have no influence). Where a [disabled] property can be set indicating if the component is disabled. We have wanted to use this together with an role checking directive to disable / enable an input based on the user’s role / permissions.

There are of course other ways like wrapping the md-input and all of the other input’s @angular/material2 provides in our own custom input value access-or components which would do this for us but we thought it would be easier to go down this route instead of wrapping all other inputs.

  • Angular version: 2.0.X 2.4.1

  • Browser: [all | Chrome XX | Firefox XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView ] all

  • Language: [all | TypeScript X.X | ES6/7 | ES5] all

About this issue

  • Original URL
  • State: open
  • Created 7 years ago
  • Reactions: 49
  • Comments: 17 (4 by maintainers)

Commits related to this issue

Most upvoted comments

@schippie Instead of wrapping md-input inside another component you could inject the component instance from the host element instead.

@Directive({
  selector: '[disable-input]'
})
export class DisableInputtDirective {
  @Input('disable-input') role: string;
  
  constructor(@Host() private hostInput: MdInputComponent) {
    
  }
  ngOnChanges() {
    this.hostInput.disabled = (this.role === 'USER');
  }
}

This should work as a temporary solution I guess. Plnkr- https://plnkr.co/edit/yo17tHkWXkMl37LOJvuG?p=preview

Having the exact same issue here. Setting a component input from outside by using a directive with host binding is an elegant pattern, as it makes component-directive interaction easy and allows for more generalization / decoupling of things.

In addition, I wonder why event binding works though, whereas property binding doesn’t.

Any way of seeing some considerations on this? Attribute directives seem like a perfect fit for redux-like or ngrx/store-like containers attaching inputs/outputs to existing components without redundant dom-nodes in case of using @Component instead of @Directive.

I just encountered this issue, were we wanted a directive to set the checked input for <input type="checkbox"> and <md-checkbox> via @HostBinding. It worked for the former, but not the latter. The error message about not having imported the component module was also really misleading.

@ndunks I also need this functionality for <mat-icon [app-icon]="item.name"></mat-icon> case. What is proper way of modifing parent (host) component inputs from directive? When I modify host component input and call detectChanges or markForCheck from directive then ngOnChanges does not trigger at the host component.

Would the Angular team be able to let us know when/if this will part of one the releases?

Now that we have setInput on ComponentRef I think a viable solution is allowing to inject the host ComponentRef and interact with it like with dynamic components. This will allow the directive to work with the component as if an input was bound. I agree it’s less convenient than HostBinding but it’s much better than what we have now (reference component instance and require input get set as ngOnChanges won’t be invoked).

+1 for this case: <mat-icon [app-icon]="item.name"></mat-icon> AppIcon directive to help choose default icon based on name. I hope this will be fixed.

@rusev That’s quite an elegant solution for now indeed, complete forgot about the @Host for a moment indeed. But that does highlight the problem even clearer. It is possible for a Directive to tell the Host component about this change. So I’ll keep the bug report open for now.