In AngularJS and Angular, updating the UI based on external events (like document.click) can be tricky when those events aren’t part of the framework’s internal lifecycle. This is particularly relevant when integrating third-party libraries or manually binding DOM events via jQuery or vanilla JavaScript.
$('html').click(function(e) {
scope.close();
});
scope.close = function() {
scope.isOpen = false;
};
<div ng-show="isOpen">My Div</div>
In this scenario, the close() method sets isOpen to false. However, AngularJS doesn’t update the view because the change occurs outside its digest cycle.
AngularJS relies on its digest cycle to detect and propagate changes in the scope. This cycle is triggered by Angular-aware mechanisms like ng-click, $http, $timeout, etc.
When you use a raw jQuery event handler ($(‘html’).click(…)), AngularJS isn’t aware of any model changes made in the handler, so the view doesn’t update even though the model has.
You must notify AngularJS (or Angular) that a change has occurred outside its normal detection mechanisms.
Use $scope.$apply() or $scope.$evalAsync() to manually trigger the digest cycle:
$('html').click(function(e) {
scope.$apply(function() {
scope.close();
});
});
Use @HostListener or NgZone to ensure changes are registered by Angular’s change detection system.
angular.module('myApp', [])
.controller('MainCtrl', function($scope) {
$scope.isOpen = false;
$scope.close = function() {
$scope.isOpen = false;
};
$('html').click(function() {
$scope.$apply(function() {
$scope.close();
});
});
});
<div ng-app="myApp" ng-controller="MainCtrl">
<div ng-show="isOpen">My Div</div>
</div>
import { Component, NgZone } from '@angular/core';
@Component({
selector: 'app-root',
template: `<div *ngIf="isOpen">My Div</div>`
})
export class AppComponent {
isOpen = true;
constructor(private ngZone: NgZone) {
document.addEventListener('click', () => {
this.ngZone.run(() => {
this.isOpen = false;
});
});
}
}
Note: Direct DOM access like document.addEventListener is not recommended in Angular. See the section below for a better approach using @HostListener.
This is the preferred Angular-native way to listen for global events like clicks on the document.
import { Component, HostListener } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<div *ngIf="isOpen" class="popup">
My Div
</div>
`,
styles: [`.popup { border: 1px solid black; padding: 10px; }`]
})
export class AppComponent {
isOpen = true;
close() {
this.isOpen = false;
}
@HostListener('document:click', ['$event'])
onDocumentClick(event: MouseEvent) {
this.close();
}
}
Work with our skilled Angular developers to accelerate your project and boost its performance.
Hire Angular Developers