2

In my project I have a generic class and some other components which inherited from that.

BaseRdnInput.ts:

   @Injectable()
    export abstract class BaseRdnInput implements ControlValueAccessor, Validator {
    
      @Input() rdnModel?: any | Array<any>;
      @Output() rdnModelChange: EventEmitter<any | Array<any>> = new EventEmitter<any | Array<any>>();
      // many code after...
    }

RdnInputComponent.ts:

@Component({
  // tslint:disable-next-line:component-selector
  selector: 'rdn-input',
  templateUrl: './rdn-input.component.html'
})
export class RdnInputComponent extends BaseRdnInput implements OnInit, AfterViewInit {
 // many code after...
constructor(public changeDetectorRef: ChangeDetectorRef) {
    super(changeDetectorRef);
  };
// many code after
}

Then I am using this component in ContractComponent.html:

<rdn-input [(rdnModel)]='headerEntity.saleNo'></rdn-input>

By this line of code I get this error :

Can't bind to 'rdnModel' since it isn't a known property of 'rdn-input'.

  1. If 'rdn-input' is an Angular component and it has 'rdnModel' input, then verify that it is part of this module.
  2. If 'rdn-input' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.
  3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.

It was working fine before I upgrading. My question is very similar to this one: Angular2 RC5: Can't bind to 'Property X' since it isn't a known property of 'Child Component'. I got that there are some setps to avoid this error and the most important is: checking if we add @input to the property of sub class or adding attr to the biding property of parent. if you see I have already added @input in BaseRdnInput.ts:. and I don't want to use attr because it will stop that property from being passed down to nested directives. Is there anyway to pass this?

atiyar
  • 7,762
  • 6
  • 34
  • 75
Ali Eshghi
  • 1,131
  • 1
  • 13
  • 30
  • What happens when you change your super class decorator to @Directive ? – MikeOne Mar 01 '21 at 21:42
  • @MikeOne why should I do that? how I do that? – Ali Eshghi Mar 01 '21 at 21:44
  • You don't need the `@Injectable()` on an abstract class – Batajus Mar 01 '21 at 21:46
  • You need a decorator with newer versions Angular if you want to use things like Input or @Hostbinding. – MikeOne Mar 01 '21 at 21:49
  • Eshgi simply replace the Injectable decorator with @Directive – MikeOne Mar 01 '21 at 21:50
  • @MikeOne the reason why I add injectable is this error : Class is using Angular features but is not decorated. Please add an explicit Angular decorator so I should use component or directive as your recommendation or injectable. However, I changed it to directive, but error not vanished... – Ali Eshghi Mar 01 '21 at 21:53
  • Worth a try... maybe a module issue? Is this component declared correctly in a module and is the module itself imported correctly? – MikeOne Mar 01 '21 at 21:57
  • @MikeOne yes, be sure , it is working when use ng serve. but in normal way I got this error, I even checked if I added formmodule to module, is that somthing related to inheritance ? – Ali Eshghi Mar 01 '21 at 22:01
  • @MikeOne I was thinking if I have to add something to supper() , may it doesn't understand input of parent – Ali Eshghi Mar 01 '21 at 22:03
  • Shouldn’t be. I use this quite a lot (but with Component or Directive, never with Injectable) – MikeOne Mar 01 '21 at 22:28
  • "_It was working fine before I upgrading_" - what was the previous version, and what is the current version? – atiyar Mar 02 '21 at 00:04

2 Answers2

2

I'm the one who wrote the accepted answer on the question you linked. Haven't worked with Angular in a looong time so bear with me, but I did some troubleshooting and possibly figured it out.

It's definitely an inheritance thing. I found this answer to a relevant question:

If a class inherits from a parent class and does not declare a constructor, it inherits the parent class constructor, and with it the parameter metadata of that parent class.

Because RdnInputComponent defines its own constructor, it's not inheriting the decorator metadata of the base class. If you remove the constructor, it then complains that BaseRdnInput doesn't have its own decorator and suggests, as did @Yngve B-Nilsen, adding @Directive(). That appears to fix the issue whether RdnInputComponent has a constructor or not (see this stackblitz).

Alternatively, just adding the inherited binded properties to inputs and outputs of the RdnInputComponent metadata seems to work as well (stackblitz), like so:

@Component({
  selector: 'rdn-input',
  templateUrl: './rdn-input.component.html',
  inputs: ['rdnModel'],
  outputs: ['rdnModelChange']
})
export class RdnInputComponent extends BaseRdnInput {
// ...

Hope that helps!

ABabin
  • 2,724
  • 24
  • 30
-1

You need to decorate your base class with @Directive() - not @Injectable

Yngve B-Nilsen
  • 9,606
  • 2
  • 36
  • 50