![]()
In AngularJS 1.5+, $onChanges() is a lifecycle hook used in components to detect changes in one-way bound (<) input properties. It executes whenever the component receives new data from its parent.
1. What is $onChanges?
$onChanges(changesObj) is triggered when the bound inputs (<) change. The changesObj argument contains:
currentValue: The new value of the property.previousValue: The old value of the property.isFirstChange(): Returnstrueif it is the first time the property changes.
2. When is $onChanges Triggered?
- When the parent updates a bound (
<) property. - When the component initializes with data from the parent.
- When the reference of an object/array changes.
3. Example of $onChanges in a Component
Parent Component (Passing Data)
app.component('parentComponent', {
template: `
<h2>Parent Component</h2>
<input type="text" ng-model="$ctrl.userName">
<button ng-click="$ctrl.changeUser()">Change User</button>
<child-component name="$ctrl.userName"></child-component>
`,
controller: function() {
this.userName = "John Doe";
this.changeUser = function() {
this.userName = "Jane Smith"; // Changing value
};
}
});
Child Component (Detecting Changes)
app.component('childComponent', {
bindings: {
name: '<'
},
template: `<p>Child Component: {{ $ctrl.name }}</p>`,
controller: function() {
this.$onChanges = function(changes) {
if (changes.name) {
console.log("Old Name:", changes.name.previousValue);
console.log("New Name:", changes.name.currentValue);
}
};
}
});
How it Works:
- Initial Load:
this.name = "John Doe",$onChangesruns withpreviousValue: undefined, currentValue: "John Doe". - Click “Change User” Button:
this.userNameupdates to"Jane Smith", triggering$onChanges. - Console Logs: pgsqlCopyEdit
Old Name: John Doe New Name: Jane Smith
4. $onChanges with Objects & Arrays
If you pass an object or array, $onChanges only triggers when the reference changes, not the values inside.
Example (Object Reference Change)
app.component('parentComponent', {
template: `
<h2>Parent Component</h2>
<button ng-click="$ctrl.updateUser()">Update User</button>
<child-component user="$ctrl.user"></child-component>
`,
controller: function() {
this.user = { name: "John Doe" };
this.updateUser = function() {
this.user = { name: "Jane Smith" }; // New object reference
};
}
});
Child Component
app.component('childComponent', {
bindings: {
user: '<'
},
template: `<p>User Name: {{$ctrl.user.name}}</p>`,
controller: function() {
this.$onChanges = function(changes) {
if (changes.user) {
console.log("Old User:", changes.user.previousValue);
console.log("New User:", changes.user.currentValue);
}
};
}
});
How it Works:
- When
this.user = { name: "Jane Smith" }, the reference changes, triggering$onChanges. - Console logs:
Old User: { name: "John Doe" } New User: { name: "Jane Smith" } - BUT, if we modify
this.user.name = "Jane Smith";,$onChangeswon’t trigger because the reference stays the same.
5. Checking First-Time Changes
Use .isFirstChange() to detect the first value change.
Example
this.$onChanges = function(changes) {
if (changes.name) {
if (changes.name.isFirstChange()) {
console.log("First time setting name:", changes.name.currentValue);
} else {
console.log("Name changed from", changes.name.previousValue, "to", changes.name.currentValue);
}
}
};
6. Key Takeaways
$onChanges(changesObj)is triggered whenever a bound (<) input changes.- Works best with primitives (strings, numbers, booleans).
- Objects and arrays trigger
$onChangesonly when their reference changes. - Use
.isFirstChange()to detect the first change.
7. When to Use $onChanges?
When you need to react to input changes inside a component.
When working with parent-child data flow.
When performing data transformations or API calls based on new input.
Avoid using $onChanges for objects that change frequently without changing reference.
8. Alternative: Using $watch (If Reference Doesn’t Change)
If you want to detect changes within an object, use $watch inside $onInit():
this.$onInit = function() {
this.$watch('$ctrl.user.name', function(newVal, oldVal) {
console.log("User Name Changed:", oldVal, "->", newVal);
});
};
