initiating AngularJS ng-model pipeline on blur event

My $parser function restricts the number of characters a user can enter:

  var maxLength = attrs['limit'] ? parseInt(attrs['limit']) : 11;

  function fromUser(inputText) {
      if (inputText) {
          if (inputText.length > maxLength) {
              var limitedText = inputText.substr(0, maxLength);
              ngModel.$setViewValue(limitedText);
              ngModel.$render();
              return limitedText;
          }
      }
      return inputText;
  }

  ngModel.$parsers.push(fromUser);

I am facing an issue where I need to apply this directive to an input element with

ng-model-options="{updateOn: 'blur'}"
. Currently, the $parser runs only after the user clicks out of the input field. Is there a way to make it execute as the user types?

(function (angular) {
    "use strict";
    angular.module('app', [])
    .controller("MainController", function($scope) {
      $scope.name = "Boom !";
      $scope.name2 = "asdf";
    }).directive('limitCharacters', limitCharactersDirective);

    function limitCharactersDirective() {
        return {
            restrict: "A",
            require: 'ngModel',
            link: linkFn
        };

        function linkFn(scope, elem, attrs, ngModel) {
            var maxLength = attrs['limit'] ? parseInt(attrs['limit']) : 11;

            function fromUser(inputText) {
                if(inputText) {
                    if (inputText.length > maxLength) {
                        var limitedText = inputText.substr(0, maxLength);
                        ngModel.$setViewValue(limitedText);
                        ngModel.$render();
                        return limitedText;
                    }
                }
                return inputText;
            }

            ngModel.$parsers.push(fromUser);
        }
    }

})(angular);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.js"></script>

<div ng-app="app">
  without ng-model-options: <input type="text" ng-model="name" limit-characters limit="7" />
  
  <br>
  with ng-model-options <input type="text" ng-model="name2" ng-model-options="{updateOn: 'blur'}" limit-characters limit="7" />
</div>

Answer №1

When a user enters data into an input field, the $setViewValue function is internally invoked. According to the Angular documentation, here is what $setViewValue accomplishes:

Upon calling $setViewValue, the new value is prepared for processing through the $parsers and $validators pipelines. If no specific ngModelOptions are designated, the prepared value is sent directly through the $parsers pipeline. Subsequently, the $validators and $asyncValidators are executed, and the value is assigned to $modelValue. Finally, the assigned value reflects in the expression defined in the ng-model attribute, triggering all registered change listeners from the $viewChangeListeners collection.

If the ngModelOptions directive includes updateOn but doesn't specify the default trigger, these actions will wait until one of the listed updateOn events occurs on the DOM element.

In essence, $parsers are exclusively employed during actual model change commits (such as blur in your situation).

A simple approach to address your issue would be avoiding the use of $parsers to restrict character count. Explore alternative solutions in this query.

By following the top-rated answer, you can adjust your directive as shown below:

function limitCharactersDirective() {
    return {
        restrict: "A",
        require: 'ngModel',
        link: linkFn
    };

    function linkFn(scope, elem, attrs, ngModel) {
        var maxLength = attrs['limit'] ? parseInt(attrs['limit']) : 11;
        angular.element(elem).on("keypress", function(e) {
            if (this.value.length == maxLength) e.preventDefault();
        });
    }
}

Refer to this working example on JSFiddle.

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

Update the class of the appropriate navigation tab when the corresponding div is scrolled into view

After reading similar questions and doing some research on scrollspy, I don't think it will provide the functionality I need. It seems to only support bootstrap style highlighting. If there is more to it that I'm not aware of, please inform me! ...

IE displaying "slow script" alert due to Knockout malfunction

Within my grid of observables and computed observables, the first row serves as a multiplier for all subsequent rows. Users can modify this percentage rate and Knockout automatically updates all relevant values accordingly. Additionally, I require a textbo ...

Having trouble with Simplemodal showing link content in the modal window

Having trouble getting the modal window to display content from another link? I'm pretty sure I've connected them correctly using the right classes. This is the basic JavaScript provided by . jQuery(function ($) { // Load dialog on page load //$ ...

Navigate to a specific section on a different page

Is it possible to navigate directly to an anchor on a different page (Page B)? On Page B, there is a list of items displayed as follows: <div ng-repeat='item in items'>{{item}}</div> I am looking to include an anchor within one of ...

What is the best way to select an element based on its relationship to another Element object using a selector?

I am currently developing a small library in which I require the ability to select a relative element to the targeted element using the querySelector method. For instance: HTML <div class="target"></div> <div class="relative"></div& ...

Passing a function into the compile method in AngularJS: A comprehensive guide

I have created a directive called pagedownAdmin with some functionality to enhance the page editor: app.directive('pagedownAdmin', ['$compile', '$timeout', function ($compile, $timeout) { // Directive logic here... }]); ...

Generate dynamic Bootstrap Carousel slides with unique hashtag URLs

I've been attempting to connect to various slides within a bootstrap carousel from a different page but have had no success. Here is an example of what I'm trying to achieve: <a href="services#slide2">Link to Slide 2</a> For refere ...

Angular Unit Testing: Executing Multiple expectGET's within a Singular Test

I am facing an issue with a unit test that fails to read the JSON in the second request properly This is my implementation of the Config factory (function() { 'use strict'; angular.module('commercial.factories').factory(&apos ...

Guide on making a versatile partial "template" in AngularJS

I possess an extensive array of items, each with their own unique set of details. Within my main view/partial, I present a lengthy list of item names for user selection. Upon clicking on an item, my aim is for the page to transition to a partial acting as ...

jQuery is not updating the div as expected

While typing out this question, I'm hoping to uncover a solution that has eluded me so far. However, just in case... About a year ago, I successfully implemented something similar on another website and went through the code meticulously. Surprisingl ...

What is the best way to handle a specific submit button using jQuery/Ajax?

I created a web page with 4 submit buttons that all call the same PHP page process.php using jQuery/Ajax. I trigger this PHP page using the onClick event as shown below: <div class="col-md-12"> <input type="hidden" name="_token" value="<?p ...

Localization for Timeago JS Plugin

Currently, I have integrated the jQuery TimeAgo plugin into my project and included the following code snippet for localization in Portuguese: // Portuguese jQuery.timeago.settings.strings = { suffixAgo: "atrás", suffixFromNow: "a partir de agora", ...

Create a typescript class object

My journey with Typescript is just beginning as I delve into using it alongside Ionic. Coming from a background in Java, I'm finding the syntax and approach quite different and challenging. One area that's giving me trouble is creating new object ...

How can I detect a click event on an SVG element using JavaScript or jQuery?

Currently, I am developing a web application that utilizes SVG. However, I have encountered an issue: I am struggling to add a click event to each element within the SVG using jQuery. The problem arises when attempting to trigger the event; it seems like t ...

What is the reason that utilizing $("input").first() does not function properly on Google Forms?

While practicing with Selenium, I encountered an issue while using this Google form. Specifically, I found that I couldn't select the first input field by using $("input").first() To confirm this issue, I turned to the web browser (Firefox) console t ...

Error 403: ACCESS DENIED - The server comprehended the inquiry, yet declines to carry it out

Encountering a persistent 403 error when making an AJAX call to an API. This issue is specific to Microsoft Edge, while other browsers like IE, Chrome, Firefox, and Safari work without any errors. The page doesn't utilize bootstrap, as there have be ...

Identifying whether a webpage has integrated Google Analytics

I am working with a node server. I provide a Url in the request and utilize cherio to extract the contents. My current goal is to identify whether the webpage uses Google Analytics. How can I achieve this? request({uri: URL}, function(error, response, bod ...

What is more costly in terms of performance: toggling the visibility of a DOM node or adding/removing a DOM node?

When it comes to calling, which is the more costly operation? Displaying and hiding a DOM node Creating and deleting DOM nodes Let's assume we only have one or a few (less than 5) nodes that require manipulation, and the application is running on a ...

Storing JavaScript variables in a database: A step-by-step guide

For the past few days, I've been working with CakePHP and trying to save a javascript variable into a MySQL database using AJAX (jQuery). Here's the code I've been using: <!-- document javascripts --> <script type="text/javas ...

How to Utilize the Vue Instance With the 'this'

Trying to implement this in my VueJs methods results in an error message: this is undefined It seems like arrow functions may not be suitable as their this does not bind to the expected context. Switching to a regular function still causes the same err ...