# Constant Bindings
Angular allows for the use of constant @Input() bindings. Let's take a look at the following example:
<button mat-button color="primary">Text</button>
The color is an @Input() binding. Well, the approach mentioned above provides an alternative to achieving the same result:
<button mat-button [color]="'primary'">Text</button>
The @Input() value is considered a string if it's not wrapped in square brackets ([]).
However, there is a pitfall with the latest approach. Evaluation means that Angular needs to check whether the binding was changed in the previous cycle. Square brackets are evaluated during each change detection cycle. If the binding was modified, the component is marked as dirty, and change detection is executed on it.
Let's examine the compiled code when using square brackets:
// <button mat-button [color]="'primary'">Text</button>
function Component_Template(rf, ctx) {
if (rf & RenderFlags.Created) {
ɵɵelementStart(0, 'button', 0);
ɵɵtext(1, 'Text');
ɵɵelementEnd();
}
if (rf & RenderFlags.Update) {
ɵɵproperty('color', 'primary'); // 👈👈
}
}
We should keep in mind that ɵɵproperty functions internally call bindingUpdated, which utilizes Object.is to compare the previous and current values. This comparison occurs in every change detection cycle. Suppose you have a component with 20 or more bindings. In that case, all 20+ bindings will be evaluated during each change detection cycle for that particular component.
Let's remove the square brackets and examine the compiled code:
// <button mat-button color="primary">Text</button>
function Component_Template(rf, ctx) {
if (rf & RenderFlags.Create) {
ɵɵelementStart(0, 'button', 0);
ɵɵtext(1, 'Text');
ɵɵelementEnd();
}
}
Well, there is no if (rf & RenderFlags.Update) condition which is run on each update. The Ivy compiler has stored the color value on the component definition constants property. This can be checked by running the following command:
ng.getComponent($0).constructor.ɵcmp.consts;
It's called one-time string initialization. You should omit square brackets in these cases:
- when the binding accepts strings
- when the binding is a fixed value that will never change in the future
Have you heard of the @Attribute decorator? The attribute decorator is used as a replacement for constant string bindings. Let's look at the following example:
// This is how you'd normally write it
export class ButtonComponent {
@Input() tabindex: string;
}
// This is how it'd look like with the use of the `@Attribute` decorator
export class ButtonComponent {
constructor(@Attribute('tabindex') tabindex: string) {}
}
And yes, the value is already available in the constructor (not in ngOnInit). There is a difference between these two approaches.
The Ivy compiler will generate the inputs property on the component definition for the ButtonComponent, which would look as follows:
// @Input() tabindex: string
ButtonComponent.ɵcmp = ɵɵdefineComponent({
inputs: { tabindex: 'tabindex' },
});
So, if you have 20 string bindings, the inputs object will contain 20 properties. This can result in more code, especially if your application has thousands of components.
The @Attribute decorator is replaced with the ɵɵinjectAttribute function:
// constructor(@Attribute('tabindex') tabindex: string) {}
ButtonComponent.ɵfac = () => {
return new ButtonComponent(ɵɵinjectAttribute('tabindex'));
};
But the component definition won't have inputs property.
Caretaker note: the
codelyzerhas had theno-attribute-decoratorrule for the past five years. This seems like it was mistakenly added by Minko because there is no explanation nor link to the Angular style guide why the@Attributedecorator shouldn't be used. This decorator is used internally by@angular/routerand@angular/commonpackages.
# Impact

As we can see, the ɵɵproperty function will be called during each change detection cycle for a single binding. It is evident that the execution time of this function will increase when there are numerous child components with multiple bindings.
# Conclusion
That approach may not provide significant performance benefits with a small number of calls, such as 10, 20, or even 30. However, it is worth considering the use of one-time string initialization in order to achieve the following advantages:
Reduce the amount of generated code and the number of ɵɵproperty runtime calls. This can lead to improved overall performance, especially when dealing with complex components that have a large number of bindings.
Particularly useful for heavy components like grids, which can contain thousands of cells and rows. By utilizing one-time string initialization, the overhead associated with evaluating and updating numerous bindings during each change detection cycle can be significantly reduced.
Overall, the one-time string initialization technique can be a valuable optimization strategy in scenarios where performance improvements are desired, especially in components with a high number of bindings or in situations where rendering large datasets efficiently is crucial.