Discovering the property name of an object in Angular using $watch

Is there a way to monitor an object for changes in any of its properties, and retrieve the name of the property that changed (excluding newValue and oldValue)?

Can this be accomplished?

Answer №1

Although this question was posted two years ago, I recently encountered the same issue and wanted to share my solution. In previous versions like 1.2, you could access the changed property by referencing this.exp in the watch function. However, this method was deprecated for performance reasons. The simplest way to retrieve the changed property is by iterating through the new and old objects and comparing their values based on the property name.

$scope.settings = {
    'opt1' : 'something',
    'opt2' : 'something else',
    'opt3' : 'another something',
};

$scope.$watchCollection('settings', function(newObj, oldObj) {

    // Iterate through the new object and compare
    angular.forEach(newObj, function(val, key) {
        if(newObj[key] !== oldObj[key]) {

            // settings[key] has been changed
        }
    });

}, true);

Answer №2

Unfortunately, it is not possible to directly access all the detailed information about changes in a watched object in Angular. The system only provides the new and previous values of the object being observed.

This can be noticed by examining the internal workings of the Angular digest loop:

// This section includes only the essential part of the code

if ((watchers = current.$$watchers)) {
  while (/* iterate over watchers */) {
    // Comparing the current value with the last known value
    if ((value = watch.get(current)) !== (last = watch.last)) {
      // The callback function is triggered with the entire values (new and last) as parameters.
      watch.fn(value, ((last === initWatchVal) ? value : last), current);
    }
}

If you really need a comprehensive comparison of object properties, one approach could be to manually enumerate the properties and compare them individually. Alternatively, you may consider using a third-party library for this purpose. A quick search on NPM led me to this option: deep-diff (which is also available through Bower). If you decide to utilize it, the implementation could resemble the following:

$scope.$watch('watchedObject', function(newValue, oldValue) {
  var differences = diff(newValue, oldValue);
  // At this point, you can examine the differences array to identify any specific changes
});

Answer №3

Observing an object is a challenging task if you don't have the variable name in your $scope.

Imagine you have an object that you wish to monitor at $scope.myobject. The first step is to go through its properties:

var objProperties = []
angular.foreach(myobject, function(value, key) {
    objProperties.push("myobject." + key);
});
objExpression = "[" + objProperties.join(",") + "]";
//objExpression will look like "[myobject.a, myobject.b, myobject.c, ...]"

Next, you need to watch over this array:

$scope.$watch(objExpression, function(newValue, oldValue){
    //perform iteration here
});

A crucial point to remember is that you have to compare the elements of the newValue array with the ones in the oldValue array and reference objProperties to determine which field has actually changed.

This method may not be the most elegant solution...

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Adding HTML content to a DOM element using Angular

Looking to create a directive that can dynamically append HTML content within a div element. Specifically, I need this directive to handle HTML data fetched from the server using an $http post request. <div id="invoice_template_preview" ng-bind-h ...

Efficiently managing modules with requirejs and Backbone.Marionette

After organizing the file structure of my web app, utilizing RequireJs and Backbone.Marionette, it now looks like this: |- main.js |- app.js |- /subapp1 |- subapp1.js |- subapp1.router.js |- /subapp2 |- subapp2.js | ...

The content inside the bootstrap modal is not visible

My goal is to trigger a modal window when a specific div is clicked using bootstrap modal. However, upon clicking the div, the screen darkens but the modal body fails to appear. Code: <html> <head> <title></title> ...

Finding the appropriate method to access a template variable reference in a designated row of an Angular Material table (Angular 7)

Currently, I am working on implementing a more intricate version of a behavior inspired by Angular Material's tutorials. In my simplified example, an Angular Material table is populated with data from a string array. The first column contains input fi ...

`res.render when all data queries are completed``

When I make an app.get request in my server.js file, I retrieve a dataset from MongoDB and then render my page while passing the data to it. Here is an example: //page load app.get('/', (req, res) => { //find all data in test table ...

Ways to display additional selected values in a select menu

I have a basic form on my website that includes options like: Select 1 and Select 2. I would like to set it up so that if I select value Home in Select 1, the value in Select 2 changes to something like residence. How can I achieve this using a database? ...

jQuery for Revealing or Concealing Combinations of Divs

UPDATE: Check out this answer. I have a complex query related to jQuery/JavaScript. I came across a post dealing with a similar issue here, but my code structure is different as it does not involve raw HTML or anchor tags. Essentially, I am working on ...

Guide on linking JavaScript files in Node.js

I am having trouble getting my javascript to work properly. My javascript files are located in the public/javascripts directory. app.js app.use(express.static(path.join(__dirname, 'public'))); views/layout.pug doctype html html head ti ...

angular 2 checkbox for selecting multiple items at once

Issue I have been searching for solutions to my problem with no luck. I have a table containing multiple rows, each row having a checkbox. I am trying to implement a "select all" and "deselect all" functionality for these checkboxes. Below is an example o ...

How to extract and compare elements from an array using Typescript in Angular 6

I have created a new Angular component with the following code: import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { HttpClient } from '@angular/common/http'; @Compone ...

Maintain parental visibility with children when navigating to a different page

I am currently working on a vertical accordion menu that opens on hover, stays open, and closes when other items are hovered. The great assistance I received from @JDandChips has been instrumental in getting this feature up and running. Now, my main focus ...

Implement a bootstrap modal to pop up upon successful form validation using the formvalidation.io

Dealing with a form that can take a significant amount of time to submit due to posting data to multiple APIs is not uncommon. Normally, I display a message in a bootstrap modal asking the user to wait patiently without clicking the back button. This modal ...

Create an element that can be dragged without the need to specify its position as absolute

I am having an issue where elements I want to drag on a canvas are not appearing next to each other as expected. Instead, they are overlapping: To make these elements draggable, I am utilizing the dragElement(element) function from https://www.w3schools.c ...

Provider Template Fails to Trigger $Scope Logic

I'm working with angular ui-router and I want to display a different template for a specific state depending on a variable in the main body scope. However, when I include this conditional using $scope.data, nothing happens. The console.log() doesn&apo ...

Ways to maneuver the vehicle by using the left or right key inputs

I am a beginner with canvas and game development. I am currently working on a project where a car moves in a straight line, but I want to add functionality for the car to turn anti-clockwise when the left key is pressed, and clockwise when the right key is ...

Parsing JSON sub items in Android application using Java

Here is a snippet of my PHP file: <?php $myObj = array( "name"=>"John" , "age"=>"30" , "post"=>[ "title"=>"What is WordPress" , "excerpt"=>"WordPress is a popular blogging platform" , ...

Guide on displaying link parameter information on a separate webpage using only JavaScript

While doing some research, I came across an issue. I have a page called specifications.html with three links: details.html?id=1, details.html?id=2, and details.html?id=3. My goal is to display the details of each link when someone clicks on it. For examp ...

Setting up a Variable with an Object Attribute in Angular

I am attempting to create a variable that will set a specific property of an object retrieved through the get method. While using console.log in the subscribe function, I am able to retrieve the entire array value. However, as a beginner, I am struggling ...

The handler for errors in DRW consistently generates the message "Error" instead of providing specific information about the issue at hand

FiltersManager.getAllServices({ callback : updateServiceFilter, errorHandler : function(message) { alert(message); } }); Although I throw an exception when an error occurs in th ...

Solving the Problem of Input Values with Jquery and Javascript

I am facing a challenge in making a div vanish with the class 'backarea' while simultaneously displaying another div with the class 'successLog' on the screen. The catch here is that I want this transition to occur only when specific us ...