What causes the `attr.$observe` callback to not be triggered when the value is modified?

I created a validation directive called multiple-pattern which accepts multiple validation regular expressions:

link: function (scope, elm, attr, ctrl) {
    if (!ctrl) return;

    let validators = [];
    attr.$observe('multiplePattern', function (patterns) {
        // does not trigger after value change
        var parsed = scope.$eval(patterns);

However, I am puzzled as to why the $observe callback is not activated when the variable on the controller validationRegexps is modified (the ng-repeat's callback is triggered when the regexp variable changes):

$scope.regexp = '^\\S*$';
$scope.validationRegexps = {'nospaces': '^\\S*$', 'nofirstnumber': '^[A-Za-z]'};

setTimeout(function () {
    $scope.$apply(function () {
        $scope.regexp = '[^abc]';
        $scope.validationRegexps = {'noabc': '[^abc]'};
    })
}, 5000);

Usage:

<div ng-pattern="regexp" multiple-pattern="validationRegexps"></div>

Answer №1

When using the <code>$observe method, it functions similarly to $watch. However, the main distinction between the two lies in the fact that $watch processes a string value or an expression and evaluates it on each digest cycle. On the other hand, $observe is designed for handling interpolated expressions such as {{validationRegexps}}.

If you want attr.$observe to work properly, make sure you are utilizing attributes with interpolated content like {{}}.

HTML

<div ng-pattern="regexp" multiple-pattern="{{validationRegexps}}"></div>

Answer №2

Upon examining the source code, it appears that there is a unique handling of the value assigned to ng-pattern. This particular handling allows for the proper functioning of $observe without requiring interpolation:

var ALIASED_ATTR = {
  'ngMinlength': 'minlength',
  'ngMaxlength': 'maxlength',
  'ngMin': 'min',
  'ngMax': 'max',
  'ngPattern': 'pattern'
};


forEach(ALIASED_ATTR, function(htmlAttr, ngAttr) {
  ngAttributeAliasDirectives[ngAttr] = function() {
    return {
      priority: 100,
      link: function(scope, element, attr) {
        //special case ngPattern when a literal regular expression value
        //is used as the expression (this way we don't have to watch anything).
        if (ngAttr === "ngPattern" && attr.ngPattern.charAt(0) == "/") {
          var match = attr.ngPattern.match(REGEX_STRING_REGEXP);
          if (match) {
            attr.$set("ngPattern", new RegExp(match[1], match[2]));
            return;
          }
        }

        scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) {
          // here the value is already interpolated
          attr.$set(ngAttr, value);
        });
      }
    };
  };
});

In contrast to non-interpolated values in other scenarios involving the use of $observe:

  $observe: function(key, fn) {
    var attrs = this,
        $$observers = (attrs.$$observers || (attrs.$$observers = createMap())),
        listeners = ($$observers[key] || ($$observers[key] = []));

    listeners.push(fn);
    $rootScope.$evalAsync(function() {
      if (!listeners.$$inter && attrs.hasOwnProperty(key) && !isUndefined(attrs[key])) {
        // not interpolated value is passed down here
        fn(attrs[key]);
      }
    });

    return function() {
      arrayRemove(listeners, fn);
    };
  }

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 image is loaded correctly through the image picker, however, it is not displaying on the screen

When I click the button to pick an image from the gallery in this code, it is supposed to load the phone's gallery and display the selected image in the image component. Even though the image gets loaded properly (confirmed through test logs), it does ...

Tips for utilizing .html?q= as a hyperlink shortening method

I've been thinking, is there a way to create a simple JavaScript shortening tool where I can manually input the code for JavaScript? Like this: function shortenUrl() { window.location.href = "http://link.com"; } In this code snippet, 12345 repre ...

What is the process for converting/executing TypeScript into JavaScript?

Having trouble running https://github.com/airgram/airgram Encountering this warning message from the post (node:9374) Warning: To load an ES module, set "type": "module" Have already added {"type": "module"} To pa ...

Typescript does not allow for extending an interface with a data property even if both interfaces have the same data type

I've encountered a peculiar problem with Typescript (using Visual Studio 2012 and TypeScript v0.9.5) that I could use some help clarifying. The code snippet below functions correctly: interface IA { data: any; } interface IB { data: any; } ...

A TypeScript-enabled functional React component utilizing an onClick event handler for an anchor tag

I am working on a React component in TypeScript: interface Props { children: React.ReactNode; href: string; onClick?: (e: any) => void; } const Input: React.FC<Props> = ({ children, href, onClick }) => ( <a className="A" href={href ...

What is causing the Jquery form submit event to not trigger?

I am attempting to use jQuery to submit a form. I need the form submit event to be triggered when jQuery submits the form. However, the submit event handler is not being called successfully after the form is submitted. Here is the code snippet: <html ...

Monitoring the usage of a specific component's screen time in a React Application

Is it possible to accurately track the time a specific component is rendered with certain props and while being on an active screen in React? I've had trouble finding a suitable library for this task. What would be the most effective approach to tackl ...

Utilize JSON text importing for template literals in Node.js

When it comes to my node js projects, I usually opt for using a text.json file and requiring it rather than hardcoding static text directly into my code. Here's an example: JSON file { "greet": "Hello world" } var text = require('./text.json ...

Adjust the color of scrollspy links as you scroll

Check out this example code snippet at http://jsbin.com/huhavejipepi/2/edit?html,js. I'm looking to update the color of the links in the top fixed navbar. When the user is at the top of the page, all the links should be black. As they scroll down, onl ...

What methods can I use to prevent multiple calls to isValid in this particular jQuery validation scenario?

I am currently working on validating a field with the following requirements: No validation when the user first lands on the page Validation triggers when the user clicks on the Name Query field, and it validates on both key up and focus out events The f ...

Utilizing a StyledComponents theme within a Component

When creating a style called Link, the theme is contained inside of this.props. How can the theme be extracted from props and passed into the Link styled component? Error: ReferenceError - theme is not defined import React from 'react'; impo ...

Tips for implementing a hash map in JavaScript for seamless looping and deletion operations

I attempted to build a hashtable in JavaScript var map ={}; // the key is string values that I'm unsure about when I want to access // values are objects I am looking to iterate through the contents of the map. I would like to remove a specific p ...

Steps for transforming data into the desired JSON structure

After receiving my data through an API call using Angular's $http service, the structure looks like this: {"Modules": [{"ModuleId":"4b601ab6-7086-4094-a9dc-392a69cfbaa3","ModuleName":"Membership"}, {"ModuleId":"82372172-6d82-453a-9752-39d ...

New and personalized bindings in knockout.js for dynamically updating a dropdown menu based on the selection in another dropdown menu

I have been using knockout for a few months now and have been getting along just fine. However, I recently encountered an issue where I cannot update the options within a SELECT tag because the ajax methods that retrieve data from the server are inside a ...

Tips for modifying an array element with the help of hooks in React

I am working with an array of checkboxes that contain boolean values, and I need to update the elements when they are changed. However, instead of getting a filled array like [false, false, false, false, true], I end up with [empty × 4, true] const [che ...

Make sure to wait for any unfinished Promises before displaying the Page

I have been working on a web project for a Twitch community in node.js. Utilizing the Twitch API, I gather profile pictures and other information to create an array of objects before rendering the page. However, I encounter a situation where the profile pi ...

Guide on setting up Facebook Ads for IOS with React Native

I'm encountering an issue in React Native while attempting to launch my app on IOS, where a warning message is displayed: "Module AdChoiceManager requires main queue setup since it overrides 'init' but doesn't implement 'requiresM ...

Display data when clicking on Tailwind

I am currently displaying a sub menu on hover using Tailwind CSS. However, I am wondering how I can achieve the exact same functionality by triggering an onclick event instead of hovering over the menu. Here is a DEMO showcasing the current setup. CODE: ...

Guide to emphasize the active navigation tab in a particular scenario

Utilizing this template for JavaScript to choose the appropriate navigation using JQuery, with reference to this API. Snippet of my current code: index.php <html> <head> <title>ChillSpot Alpha 1.2.3</title> &l ...

Is it possible to display or hide a spinner within a span using Javascript and AJAX?

When submitting a contact form, I want to display and hide a spinner on the submit button. The spinner should be visible while the form is being submitted and hidden once the submission is complete. Below is the code for my submit button with the spinner: ...