Reputation: 15239
I need to add the isBold
property to an Angular component
<child-component isBold />
Remark the following
I prefer do not use square brackets [] around the property name if used as true
flag (as in the code above, long version would be isBold = true
).
However I would like to be able to use it as an input property
<child-component [isBold]="parentBooleanOrFunction" />
the code bellow breaks the first requirement
@Input() isBold: boolean = true
Is there a way, in Angular 13, to do it without writing additional helper functions?
I note I read the similar question here, but the selected solution needs additional code or Material usage I have not.
Upvotes: 1
Views: 944
Reputation: 6706
To achieve that, I would suggest creating your own coercion
functions/types similar to the Angular CDK functions/types (If you don't need to add the @angular/cdk
to your project dependencies), which are very easy to implement than creating a directive for each Input:
For example, the Boolean Property from @angular/cdk/coercion
:
/**
* Type describing the allowed values for a boolean input.
* @docs-private
*/
export type BooleanInput = string | boolean | null | undefined;
/** Coerces a data-bound value (typically a string) to a boolean. */
export function coerceBooleanProperty(value: any): boolean {
return value != null && `${value}` !== 'false';
}
Then you can use them directly in any component, like the following:
@Input()
get isBold(): boolean {
return this._isBold;
}
set isBold(isBold: BooleanInput) {
this._isBold = coerceBooleanProperty(isBold);
}
private _isBold = false;
<child-component isBold />
<child-component [isBold]="parentBooleanOrFunction" />
You can find the full list of Angular CDK coercion
functions/types under angular/components/src/cdk/coercion/
:
https://github.com/angular/components/tree/main/src/cdk/coercion
UPDATE:
If you don't want to use any helper functions/types, you can handle it like the following as mentioned in Deprecated APIs and features at Angular 13:
@Input() get isBold(): boolean {
return this._isBold;
}
set isBold(value: boolean | '') {
this._isBold = value === '' || value;
}
private _isBold = false;
When a getter/setter pair is being used for the input it may be desirable to let the setter accept a broader set of types than what is returned by the getter, for example when the setter first converts the input value. However, until TypeScript 4.3 a getter/setter pair was required to have identical types so this pattern could not be accurately declared.
Since TypeScript 4.3 the limitation has been removed; setters can now accept a wider type than what is returned by the getter. This means that input coercion fields are no longer needed, as their effects can be achieved by widening the type of the setter.
Read more about "Input setter coercion" deprecation in Angular 13 here: https://angular.io/guide/deprecations#input-setter-coercion
Upvotes: 1
Reputation: 32517
You can use directive to do that but it will not work as an ordinary @Input
Working examople on stackblitz
Create input directive
@Directive({
selector: '[isBold]'
})
export class IsBoldDirective {
@Input() isBold:boolean;
constructor() { }
ngOnInit(){
if(this.isBold!==false){
this.isBold=true; // defaults to true
}
}
}
Inject it into the component
@Component({
selector: 'app-testing',
templateUrl: './testing.component.html',
styleUrls: ['./testing.component.css']
})
export class TestingComponent {
constructor(@Self() @Optional() private isBold:IsBoldDirective) { }
get value(){
return this.isBold?.isBold ?? true; // this 'true' is the default value if isBold is not there
}
}
and use it like this
Absence: <app-testing></app-testing>
Presence: <app-testing isBold></app-testing>
Set value: <app-testing [isBold]="false"></app-testing>
with result
Absence:
true
Presence:
true
Set value:
false
Upvotes: 0