Navigating ngMessages in Angular - Retrieving Data from Multiple Form Fields

Struggling to implement a custom validation function in Angular's ngMessages.

My goal is to ensure that the total of two input values always amounts to 100.

I've crafted a new directive named totalOneHundred, set to trigger on form changes. However, I'm stuck on accessing values of other form inputs from the link: callback.

Sharing my code below for review. Is there a key step I'm overlooking? Any suggestions for a more efficient approach (like a sum() function in the controller paired with ng-show) are welcome.

Your insights are appreciated.

The form:

<!-- input box to be validated -->
<input type="number" class="form-control" name="lowBound" ng-model="ctrl.lowBound" total-one-hundred required>

<!-- validation messages -->
<div ng-messages="form['lowBound'].$error" role="alert">
    <div ng-message="required">Cannot be empty</div>
    <div ng-message="totalOneHundred">Sum of tasks must = 100</div>
</div>

<!-- input box to be validated -->
<input type="number" class="form-control" name="highBound" ng-model="ctrl.highBound" total-one-hundred required>

<!-- validation messages -->
<div ng-messages="form['highBound'].$error" role="alert">
    <div ng-message="required">Cannot be empty</div>
    <div ng-message="totalOneHundred">Sum of tasks must = 100</div>
</div>

The directive:

return {
    restrict: "A",

    require: ["^^form", "ngModel"],

    link: function(scope, element, attributes, controllers) {

        // Initially, form is assigned the actual form controller...
        const form = controllers[0];
        const model = controllers[1];

        model.$validators.totalOneHundred = function (modelValue, form, element, scope) {

          // Yet, the form value here shows "1".
          // The modelValue represents the triggering input's value,
          // but how do I tap into the other form inputs?
          return true;

        };

    }
};

Answer №1

Initially, I took the provided code and applied it to this JSFiddle. A sum() function within the parent controller calculates the total, which is then passed to the total-one-hundred directive as an argument. Here is an example of how it is used:

<input type="number" class="form-control" name="lowBound" ng-model="ctrl.lowBound"
    total-one-hundred="ctrl.sum()" required />

Unfortunately, there seems to be an issue with the functionality. Each input field is displaying an error stating "Sum of tasks must = 100". When a field is updated to correct the total, the validation message disappears for that specific field, but it remains visible for the other fields.


EDIT: It is possible for this setup to work correctly with some adjustments. By adding a watch for the total sum in each validation directive, and reapplying validation on the field when changes occur, we can address the issue. Here is the updated link function:

  link: function(scope, element, attributes, controllers) {
      const model = controllers[0];
      var totalEvaluator = $parse(attributes['totalOneHundred']);

      scope.$watch(totalEvaluator, function(newval, oldval) {
        if( newval !== oldval ) {
            model.$validate();
        }
      })

      model.$validators.totalOneHundred = function (modelValue) {
        return totalEvaluator(scope) === 100;
      };
  }

(Please note that this approach adds extra watches per field!)

However, this solution may still result in multiple calls to the sum() function, which could be resource-intensive. Optimizing this by watching the inputs of the function and only calling it when necessary could improve performance.

An updated version of the JSFiddle can be found here: https://jsfiddle.net/m8ae0jea/1/. While I personally prefer model validation as mentioned in the last paragraph, it's essential to be aware of all available options and their implications.


This issue highlights a common challenge with cross-field validations: determining where the validation logic should reside. If possible, restructuring the model to validate the entire object can simplify the process. The provided example demonstrates how Angular's custom controls can be used for this purpose in this JSFiddle.

In this updated model, individual fields are combined into an object with its own validation messages:

this.model = {
    lowBound: <a number>,
    highBound: <a number>
};

An editor for the entire model is then utilized, along with its associated messages:

<model-editor name="entireModel" ng-model="ctrl.model" form="form"
    total-one-hundred="ctrl.sum()"></model-editor>
<div ng-messages="form['entireModel'].$error" role="alert">
  <div ng-message="totalOneHundred">Sum of tasks must = 100</div>
</div>

This validation method ensures that the total validation applies to the entire model as a whole.

While the second example functions correctly with a single validation message for the total, some developers may find it limiting. In my opinion, Angular's validation is better suited for simple tasks, whereas more complex scenarios, such as this one, may benefit from implementing model validation and integrating the results with Angular. To address these needs, tools like egkyron can be a valuable resource.

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

Parsing JSON data to extract values stored in a two-dimensional array

In order to develop a basic version of Tic Tac Toe, I decided to store game data in a JSON file. Here is an example of how the file is structured: [ { "turn": "x", "board": [ [ " ...

Learning how to access JavaScript variables within a Ruby on Rails view

Our team has been working on a javascript code that captures the URL of a selected image and stores it in a JavaScript variable called "src". The goal is to access this variable within a Rails view in order to obtain the ID of the selected image. We attemp ...

Stop the logging of http errors in the browser console

I'm in the process of finding a way to prevent displaying http request and response errors in my application. For instance, when a flawed request is sent to my server, I prefer not to have the error message show up on the browser console. Even though ...

Discover the location by determining the distance from established points

Before I get redirected to this particular question, let me clarify that while I've come across it, I am unable to comprehend its content (I wish I could). What I'm really seeking is a straightforward method (bearing in mind my limited math skill ...

Troubleshooting Safari compatibility issues with Twitter Direct Messages in Angular

I am attempting to create a Twitter direct message with predetermined text already filled in. My current method involves using window.open() to prepare the message. window.open(https://twitter.com/messages/compose?text=${this.helloWorld}); helloWorld = ...

Is it possible for numerous directives to utilize an isolated scope on a single element?

Is it possible for two directives on the same element to share an isolated scope that is separate from their parent? Can they both access properties bound to this isolated scope? For instance, if there are two directives on an element <e-directive a-d ...

Tips for maximizing performance in ember-data through r.js

After making the switch to ember-data#canary, I encountered a problem with r.js failing. [Error: Error: ENOENT, no such file or directory '/scripts/lib/ember-data/ember-data/core.js' In module tree: app/main app/app embe ...

Tips for minimizing the transfer time of large arrays using ajax

https://i.stack.imgur.com/IP0oe.pngDescription I am currently working on transferring a JSON object from the server to the client using PHP and JavaScript via AJAX. The JSON object contains a large array (200x200) of integers. The server is running on lo ...

What is the significance of the underscore prefix in package.json properties?

Can you explain the significance of prefixing properties with an underscore in package.json? What is the reason behind using underscores in this context? "_from": "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="6b190e0a081 ...

Data loading issue with asp.net mvc Ajax

I am currently facing an issue while attempting to fetch data from the controller using ajax. Controller [HttpGet] public ActionResult GetServices() { var data = _bbdb.ListServices.Where(d => d.Status == true).ToList(); return Json(data, JsonR ...

What is the process for implementing a version folder for my @types/definition?

Is there a way to access the typings for react-router in my project? My package.json file currently has this dependency: { "@types/react-router": "^4.0.3" } However, it seems to be using the standard index.d.ts file from DefinitelyTyped library which i ...

Ways to fix the error "Response must contain an array at." when creating a dropdown menu

I encountered an error while trying to create a dropdown menu. I referred to the documentation available at The response must include an array at " . ". Although I came across some links with potential solutions, none of them seemed to work for me: https ...

Showing the Datepicker from jQuery right in the middle of the screen

Here's the generated code as default: <div id="ui-datepicker-div" class="ui-datepicker ui-widget ui-widget-content ui-helper- clearfix ui-corner-all ui-datepicker-multi ui-datepicker-multi-2" style="width: 34em; position: absolute; left: ...

Passing props to a wrapped component when utilizing a higher order component in React

While exploring the react documentation, I came across a section on Higher-Order Components that included an example of logging props for a specific component. function logProps(WrappedComponent) { return class extends React.Component { componentWillR ...

Exclude the file and directory patterns from being watched with PM2: ignore folder

I need help with configuring pm2 to stop monitoring folders that have names like cache or tmp. I've tried multiple approaches in my app.json configuration file: {"apps": [{ "name": "BSTAT", "script": &q ...

Simplify your bootstrap Input field code by utilizing components or a similar method in Vue.js

Using a single file component with a pug template, I am faced with multiple input fields that have the same formatting. Here is an example: .input-group.input-group-sm .input-group-addon Purchase Price input.form-control(v-model='purchase_ ...

Attempting to prevent the use of the <p> tag solely before the text

My toggle function is not working correctly in my FaQ section. When a user clicks on a topic, the bottom section should appear, but the <p> tag is being displayed across the entire line instead of just one word.. Here is an image to help illustrate ...

Guide on how to capture tweets from particular Twitter profiles

I'm currently experimenting with the twitter npm package to stream tweets from specific accounts, but I'm facing some challenges. After reviewing the Twitter API documentation, I must admit that I am a bit perplexed. To fetch details about a pa ...

Using AngularJS to bind objects with a checkbox

I am dealing with a nested list of objects that can go up to three levels deep. Each object contains another nested object, and this nesting can continue to multiple levels. I am interested in binding these objects directly to checkboxes so that when I che ...

The process of uploading a React App to Heroku resulted in a critical error: "FATAL ERROR: Heap limit reached, Allocation failed - JavaScript heap out of memory."

There's a puzzling issue that I believe I have the solution to (paying for more bandwidth on Heroku), but the root of the problem eludes me and it's truly frustrating. Any assistance in pinpointing the cause would be greatly appreciated! Hopefull ...