AngularJS: How to monitor variables without using $watch

I recently came to understand that Javascript operates on a "Call by sharing" principle, which means that everything is passed by value but the original contents of an object can still be modified. To illustrate this concept, consider the following scenario:

function changeObjectProperties(obj) {
    obj.p = 20;
}

var obj = { p: 10; }
changeObjectProperties(obj);
console.log(obj.p); // outputs 20 because it's been changed!

This realization led me to wonder if Angular could leverage this mechanism to monitor variables without relying on $scope.$watch. Surprisingly, it turned out to work quite well.

controllers.js:

.controller('Listener', function($scope, UserService) {
    $scope.user = UserService.getUser();
})

.controller('Changer', function($scope, UserService) {

    // let's say there's a button in the UI that updates the email address
    $scope.buttonClick = function() {
        UserService.setEmail('<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="16707979567477643875797b">[email protected]</a>');
    }
});

services.js:

.factory('UserService', function() {
    var user = {
        name: 'Foo',
        email: '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a2c7dac3cfd2cec7e2c7dac3cfd2cec78cc1cdcf">[email protected]</a>'
    };

    return {
        getUser: function() { return user; },
        setEmail: function(email) { user.email = email; }
    };
});

The $scope.user variable inside the Listener controller gets updated whenever the user clicks the button in the Changer controller. If this variable is displayed in the HTML, the change will be visible.

The main drawback is that the object itself cannot be altered, as updating the object reference would disconnect the Listener controller from the correct reference.

I tried searching for information on whether this approach is commonly used and considered good practice, but I couldn't find much. Perhaps I'm not using the right terminology. So, are people actually utilizing this technique? Is it deemed a best practice or are there potential pitfalls I should be aware of?

Answer №1

To minimize unnecessary watches, it's beneficial to utilize the base language effectively. It's important to note that avoiding watches entirely is not feasible, as Angular relies on them to track the model. Simply placing something on scope will prompt Angular to watch it for changes and update the UI accordingly. Understanding and managing the digest loop mechanism can help in reducing or eliminating superfluous watchers.

By adopting a JavaScript-first strategy for coordinating state and object transitions, explicit watchers can be circumvented, as Angular's internal watches within the digest loop will capture any modifications made.

Your approach aligns with my discussion on the common mistake of overusing $watch among AngularJS developers, as highlighted in my article:

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

The appearance of the image is distorted once it is inserted into the carousel

I am currently working on a carousel that contains 5 images with varying heights and widths. However, I am experiencing some issues with the way the images are displayed - some are stretched while others are centered within the carousel. My goal is to ens ...

Tips for keeping a Youtube video playing even after the page is refreshed

Is it possible to save the current position of a Youtube video and have it resume from that point when the page is refreshed, instead of starting from the beginning? I am considering using cookies to store the last position or utilizing GET. Although my w ...

Ensure that the number is valid using Express Validator in Node.js

One thing that I've noticed when using express validator is the difference between these two code snippets: check('isActive', 'isActive should be either 0 or 1').optional({ checkFalsy : false, nullable : false }).isInt().isIn([0, 1 ...

Is it possible to have the Target='_blank' attribute open the link in a new window instead of a new tab?

Is there a way to achieve this? When using Firefox, the link opens in a new tab, which I prefer to avoid users having to adjust settings in their browsers. I am looking for a solution where a pop-up contact form appears whenever a user clicks on 'co ...

Display all the names of the files from various file inputs in a unified notification

I have developed a function that checks if the selected file names already exist in the database. It currently alerts a message for each file name found in the database, which can be overwhelming with multiple files. I am looking for suggestions on how t ...

Error in jQuery Ajax post request caused by a keyword in the posted data

I understand why the post is failing, but I'm at a loss on how to fix it and I haven't been able to find any solutions online. I am removing references to jEditable in an attempt to simplify things, as this issue occurs even without the jEditable ...

Modifying the CSS style of an element on PageA by clicking a button on PageB

For my app, I am incorporating tabs. I want to implement a user button that, when clicked on tab-detail.html, will update the CSS of an element located on its parent tab page, tab.html. .controller('TabCtrl', function($scope,Tabs) { $scope.t ...

Error: Unhandled promise rejection - The function get is not part of this.categoryMap

I am facing an issue with calling functions of the Map (get, set, keys, etc) within my function. The map I am working with is returned from a firebase query. Here's a snippet of my code: categoryMap = new Map<Number, String>(); //called onInit ...

Selecting radio buttons in IE11 using JQuery

The code snippet below is used for handling form submission: $(".submitButton").click(function(event){ if ($(this).hasClass("disabled")){ event.preventDefault(); return false; } if (!$(this).hasClass("disabled")){ $('.invoice-form&a ...

Troubleshooting audio playback issues with create-react-app's componentDidMount method

When I set up my create-react-app project, I successfully imported jQuery as $ and used it in the componentDidMount() lifecycle hook. Within the render() method, I included: audio ref="bgAudio" source src={this.state.bgAudio} and initialized the stat ...

Is there any variation in the Stripe payments Workflow when utilizing the Connect-API?

I have a question about simplifying the implementation of the Stripe API for multiple products on a single page. Currently, I have a webpage with 20 different items and I am utilizing Stripe Connect. Instead of creating individual forms for each product i ...

Getting Started with Angular 2 Installation

Looking for a straightforward way to incorporate Angular2 into a single HTML file without using Bower, NPM, NuGet, or other complex methods? EDIT: Thanks to Dieuhd's suggestion, I was able to make Angular 2.0 work using the following script referenc ...

Deleting entries from a selection of items in a list generated from an auto-fill textbox

I have successfully implemented an auto-complete Textbox along with a styled div underneath it. When the client selects an item from the Textbox, it appears in the div after applying CSS styling. Now, I am looking to create an event where clicking on the s ...

Utilizing React.js to Sort Through JSON Data

I'm currently working with the following state: constructor(props){ super(props); this.state = { open: false, customers:[], customer:{}, products:[], product:{}, ...

Creating a cascading select menu based on the selected value of another select menu

I am in the process of creating a menu that displays two lists for regions: one <select> for selecting the region and another <select> for choosing from available municipalities within that region. I have set up a <form> and I utilize Jav ...

Input only the necessary numeral

As someone who is just beginning to learn javascript, I am tasked with creating an input field that allows for the input of 'AND', 123, or (). I attempted using RegExp to achieve this. function requiredletter(inputtxt) { var letters =/&bso ...

Generating an array by iterating through each object within an array of objects

I am working with a JSON structure and I need to separate it into two arrays. The first array should include all the values from the key "employee only" to "Annual OOP max / entire family" from each object in the JSON array. The second array should contain ...

Calculating the length of an array in Vue/Nuxt using a custom plugin: Watch vs Computed

I am trying to show the length of an array within my Vue component. The array is nested within a Vue plugin. Each time I initiate an API Call, I add a new element to this array located here: this.$apiCall.apiCallCache Is it possible to monitor changes i ...

Context Provider executing SetInterval twice

For some reason, the below code in global.js is running twice when I run my react app, but I can't figure out why. I have used setInterval to test, and the intervals are always running two times. Perhaps I am not initializing correctly. Even after rem ...

Is the 'Document' term not recognized within expressjs?

I'm having trouble implementing a query selector in an ExpressJS application and it's not working // search products router.post('/search', function(req, res) { var db = req.db; var elasticlunr = require(&apo ...