The $watch function fails to trigger in the directive

Within my controller, I am setting a variable to true using the ng-click directive.

In my custom directive, there is a need to evaluate something when this variable is true. Once evaluated, the directive then sets the variable to false.

The issue I am facing is that I cannot get the $watch function to trigger from the ng-click event.

I have provided a sample fiddle demonstrating the problem. Upon loading the page, the $watch logs true. When the directive is clicked to change it to false, the $watch correctly logs false. However, subsequent clicks do not cause the $watch to fire. Why might this be happening?

http://jsfiddle.net/zcouyvwc/2/

var app = angular.module('myApp', []);

function MyCtrl($scope,$timeout) {

    $scope.boolean = true;

    $scope.setToTrue = function() {
        $timeout(function(){$scope.boolean = true;});
    };
}


app.directive("someDirective",['$timeout',function($timeout) {
return {
    restrict:"A",
    scope:true,
    link: function(scope, element, attrs) {

        scope.$watch("boolean", function() {
         console.log(scope.boolean);
        });

        element.bind('click',function(){
            $timeout(function(){
                scope.boolean = false;
            });

        });
    }
}
}]);

Answer №1

The problem lies in the fact that someDirective is generating a child scope, where setting scope.boolean = false creates a new variable that overshadows the original, leaving the original unchanged.

The recommended solution, as outlined on https://github.com/angular/angular.js/wiki/Understanding-Scopes, suggests:

To avoid this issue with primitives, it's best practice to always include a '.' in your ng-models.

If you modify your code to have

$scope.model = {
    boolean: true
};

As shown in http://jsfiddle.net/9j87njvt/1/, then it should behave as expected.


On another note, I typically only create directives with scope inheritance dependencies if other options are more complex or come with drawbacks. Generally, I prefer passing options through attributes and using scope: {...} in the directive definition for an isolated scope to maintain separation. Additionally, I see you have some uses of $timeout. You might want to consider utilizing scope.$apply() for Angular to execute the digest cycle and recognize changes in the model.

Answer №2

If you find yourself caught in the trap of prototypical scope inheritance, fear not. When you specify scope:true, what happens is that the directive creates a brand new scope that inherits from its parent scope (the one belonging to the controller). This may sound confusing if you're not well-versed with Javascript prototypical inheritance.

But take a breather and try switching to scope:false. By doing this, the directive will simply use the parent scope, resulting in your fiddle functioning smoothly. So unless you have a specific need for a child scope, you can stop right here.

If you decide to venture further, here's what you should know: With prototypical scope inheritance, properties at the top level (such as $scope.something - not $scope.something.deeper) are read from the first scope in the hierarchy where they exist, but changes are always made to the current scope. Initially, the scope hierarchy looks like this:

controller scope (has "boolean" top-level property with value: true)
|
+- directive child scope (is empty)

After some interaction, it transforms into this:

controller scope (has "boolean" top-level property with value: true)
|
+- directive child scope (now has "boolean" top-level property with value: false)

The issue arises when you set up a watch on the directive scope, which continually checks the boolean property in the child scope and finds it perpetually set to

false</code, preventing the watch from triggering.</p>

<p>The solution lies in steering clear of top-level properties. Move the <code>boolean
under an object within the controller scope, such as $scope.data.boolean = true, and adjust the directive accordingly:

scope.$watch("data.boolean", function() { ... });

element.bind('click',function(){
    scope.$apply(function() {
        scope.data.boolean = false;
    ...

While you're making tweaks, consider giving boolean a more descriptive name! (refer to developer10's suggestion)

And remember to opt for $scope.$apply over $timeout.

Answer №3

It's important to note that the term boolean is considered a reserved keyword in most programming languages, meaning it cannot be used as a variable name.

To find a list of other reserved words, check out this resource.

We recommend choosing a different, more descriptive name for your variable and letting us know if you still encounter any issues.

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 a class to a PHP file using AJAX response

I have been developing a website that features a like button attached to user-generated posts. My goal is to update the like count of a post whenever a user likes it, but I am encountering an issue where the entire post gets affected. Below is the code fo ...

Visual Studio is not compatible with AngularJS routing functionality

I am working on my AngularJS project using VS 2015. I've encountered an issue with routing that I can't seem to resolve. Whenever I click on the "Add" hyperlink, the URL in the browser's address bar shows as follows: "http://localhost:21530/ ...

Leveraging $pristine in AngularJS for Form Validation

My form utilizes angular validation, but I want to disable it upon page load. Below is a simplified version of my form: <form ng-submit="vm.submit()" name="form" novalidate> <input class="form-control" ng-model="vm.userName" required /> ...

How to make changes to the state in Vue.js while using v-for loop

Currently, I am retrieving comments from an API and attempting to modify a specific comment from the list. Upon clicking the edit button, a text area appears within the comment box along with a save button, functioning as expected. The issue arises when ...

Easily ajaxify your website without the need for hash or hashbang URLs

Currently enrolled in a web design course, I am eager to explore the world of ajax and how it can enhance our projects. Unfortunately, our instructor focuses solely on design and HTML, leaving us to figure out the more technical aspects on our own. If I m ...

Angular won't function properly when utilizing the <a href> tag

Within one of my template files (located in a folder named "partials"), I have the following code: <a href="index.html">&laquo; Back to search</a> In one of my JavaScript files, I define the routing as follows: var app=angular.module("ap ...

Is there a way to conceal the information entered into an email input field without specifying it as a password type?

`I'm facing a challenge at work where I need to mask the content of the input field like a password, but I'm unsure about the best approach. I tried replacing the last letters with "*" and it worked fine, but running into issues when trying to de ...

Trigger an onchange event to retrieve the object with React autocomplete

When the onchange event occurs, I am expecting to retrieve a vehicle object. However, all I am getting is a vehicle number displayed as a dropdown value. Even when I try to pass an item to get the vehicle object, I still end up with just the vehicle number ...

AngularJS hide/show tab functionality

Presented here are tabs generated from an array using AngularJS and Bootstrap. My goal is to make it so that when a specific tab is clicked, only the content of that tab is displayed. For example, if I click on "Dynamic-2," I want to see the content relat ...

Converting a Binary String to a Buffer in Node.js

I am attempting to convert a sequence of 0 and 1 characters into the corresponding Buffer by interpreting the character stream as UTF-16 encoding. Here is an example: var binary = "01010101010101000100010" The resulting Buffer from this binary string wou ...

Can you explain the concept of (A == B == C) comparison in JavaScript?

Surprisingly, the comparison I expected to fail was this: var A = B = 0; if(A == B == 0) console.log(true); else console.log(false); To my surprise, it doesn't return true. What's even more astonishing is that console.log((A == B == ...

The code is functional with regular arrays, however, it does not support multidimensional arrays

Currently, I am working on developing a Holdem hand evaluator which requires me to create a function that calculates the number of possible combinations of 5 cards from a selection of 7 cards. I have successfully written the "pickNofSet()" function to achi ...

What is the best way to retrieve the previous object value (on value) in Firebase?

Here's a sample code snippet: Firebase Database name: Sonic when changed value name: Sonita FirebaseRef.on('value', function(snapshot) { var previousName = ?; //Sonic var newName = snapshot.val(); //Sonita }); ...

Best practices for defining TypeScript types

In my quest to optimize my TypeScript type definitions, I have scoured countless pages for the best approach. In the past, I kept a typings.ts file tucked away in my project, importing types into each file as needed using: import {IMyCustomType} from &a ...

Resolving the Table Issue with 'onclick' in Javascript

Apologies for the lack of creativity in the title, I struggled to come up with something fitting. Currently, I am engaged in the development of a user-friendly WYSIWYG site builder. However, I have encountered an obstacle along the way. I've devised ...

Discovering the correct way of utilizing Vuelidate's minValue and maxValue functionality

I am having trouble figuring out how to validate for values greater than 0. When using minValue(0), it also accepts the value 0. On the other hand, if I use minValue(1), it does not accept any decimal between 0 and 1. Furthermore, I am facing an issue wit ...

SuperTest app encounters an error: App is not recognized

I am currently delving into the world of test driven development and am taking on the challenge of using supertest to enhance my skills. I am facing an issue where I keep encountering the error message "app is not defined" when making calls to request(app) ...

Incorporating flip and slide transitions for an engaging visual experience

Hey everyone, I'm currently working on creating a web flash card. The functionality I want is for the card to flip when clicked, but if I click on the navigation it should smoothly slide to another card, similar to a slideshow. If anyone has a demo or ...

Mongoose search operation coming up with a blank array

Whenever I utilize $search in mongoose, it returns an empty array. Data Model const mongoose = require('mongoose'); const studentSchema = new mongoose.Schema({ name: { type: String }, }); studentSchema.index({ name: 'text' }); con ...

Detecting the physical screen size based on the user agent in PHP and JavaScript

Is it possible to accurately detect the screen size of mobile browsers using both javascript and php? Given how mobile devices come in all shapes and sizes these days, relying solely on pixels may not be enough. I'm looking for a method that can speci ...