In-depth Analysis of Element Show/Hide in Angular: Comparing *ngIf vs [hidden] and this Binding Issues

Nov 05, 2025 · Programming · 18 views · 7.8

Keywords: Angular | *ngIf | [hidden] | this binding | element show hide

Abstract: This article provides a comprehensive examination of two primary methods for showing and hiding elements in Angular: the *ngIf and [hidden] directives. Through analysis of a practical case involving setTimeout function's this binding problem, it explains the working principles, applicable scenarios, and performance impacts of both directives. The article combines DOM manipulation, component lifecycle, and event handling mechanisms to offer complete solutions and best practice recommendations, helping developers better understand Angular's reactive data binding mechanism.

Problem Background and Phenomenon Analysis

In Angular application development, dynamic showing and hiding of elements is a common interaction requirement. Developers typically use *ngIf or [hidden] directives to achieve this functionality, but various unexpected issues may arise in practical applications.

Consider this typical scenario: after a user performs a save operation, a success message needs to be displayed and automatically hidden after 3 seconds. The initial implementation code is as follows:

<div *ngIf="edited" class="alert alert-success alert-dismissible fade in" role="alert">
    <strong>List Saved!</strong> Your changes has been saved.
</div>

The corresponding component logic:

export class AppComponent implements OnInit {
    public edited = false;
    
    saveTodos(): void {
        this.edited = true;
        setTimeout(function() {
            this.edited = false;
            console.log(this.edited);
        }, 3000);
    }
}

Superficially, this code appears logical: set edited to true to show the message, then set to false after 3 seconds to hide it. However, in practice, the message does not hide as expected after 3 seconds, even though the console log shows this.edited indeed becomes false, but the interface doesn't update accordingly.

Root Cause: JavaScript's this Binding Mechanism

The core issue lies in JavaScript's dynamic binding characteristic of the this keyword. In the setTimeout callback function, the reference of this changes and no longer points to the component instance, but rather to the global object (window in browser environments).

When executing this.edited = false, it actually modifies the edited property of the global object, not the component instance's property. Therefore, although the console outputs false, Angular's change detection system doesn't detect the change in the component instance's edited property, preventing interface updates.

Solution: Properly Binding this Context

There are multiple methods to solve this problem, with the most direct being using the Function.prototype.bind() method:

saveTodos(): void {
    this.edited = true;
    setTimeout(function() {
        this.edited = false;
    }.bind(this), 3000);
}

bind(this) ensures that this in the callback function always points to the component instance. In modern JavaScript development, arrow function syntax is more recommended:

saveTodos(): void {
    this.edited = true;
    setTimeout(() => {
        this.edited = false;
    }, 3000);
}

Arrow functions automatically bind the this context from their definition scope, avoiding the complexity and potential errors of manual binding.

In-depth Comparison of *ngIf and [hidden]

Working Principle of *ngIf Directive

*ngIf is a structural directive that completely adds or removes elements from the DOM based on expression truthiness. When the expression is false, the corresponding element and its children are completely removed from the DOM tree; when the expression becomes true, they are recreated and inserted into the DOM.

Advantages of this mechanism include:

However, there are also limitations:

Working Mechanism of [hidden] Attribute

[hidden] is an attribute binding that hides elements through CSS's display: none, while the elements remain in the DOM. When [hidden]="true", the browser doesn't render the element, but the DOM structure remains unchanged.

Advantages of this approach include:

Potential issues:

Practical Application Scenario Analysis

Scenarios Suitable for *ngIf

*ngIf is the better choice in the following situations:

For example, cancel operation in edit forms:

<div *ngIf="isEditing" class="edit-form">
    <!-- Edit form content -->
</div>

Scenarios Suitable for [hidden]

The following situations are more appropriate for [hidden]:

For example, message notification components:

<div [hidden]="!showMessage" class="alert">
    <!-- Notification message -->
</div>

Special Considerations in *ngFor Loops

When controlling individual element display states within *ngFor loops, the best practice is to include the state as a property of the iterated object:

<div *ngFor="let item of items">
    <div *ngIf="item.isEdited" class="alert">
        <strong>Item Updated!</strong> {{item.name}} has been modified.
    </div>
</div>

Corresponding component code:

export class AppComponent {
    items = [
        { name: 'Item 1', isEdited: false },
        { name: 'Item 2', isEdited: false },
        { name: 'Item 3', isEdited: false }
    ];
    
    updateItem(index: number): void {
        this.items[index].isEdited = true;
        setTimeout(() => {
            this.items[index].isEdited = false;
        }, 3000);
    }
}

Performance Optimization Recommendations

Based on deep understanding of both directives, the following optimization strategies can be formulated:

Conclusion

Showing and hiding elements in Angular involves considerations at multiple levels: JavaScript's this binding mechanism, directive working principles, performance impacts, and specific application scenarios. Proper understanding of these concepts is crucial for developing high-quality Angular applications.

Key takeaways:

By deeply understanding these concepts and applying them appropriately, developers can create more stable, efficient, and user-friendly Angular applications.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.