Javascript problem with closures triggering on click

After going through numerous solutions for the "closure" problem, I still can't find one that addresses my specific issue.

In the JavaScript code below, a JSON file is fetched and processed, followed by form validation based on the data.

The issue arises when submitting the form and running the validate function. Instead of seeing two errors as expected, only the error for the last field is displayed in the console.

This seems to be a closure problem, which has been consuming my entire day without a successful resolution. The code snippet with the click event at the end...

For now, I am only focusing on validating the minimum length rule.

// Fetch and store the json file
function loadJSON(callback) {
  var xobj = new XMLHttpRequest();
  xobj.overrideMimeType("application/json");
  xobj.open('GET', 'js/rules.json');
  xobj.onreadystatechange = function () {
    if (xobj.readyState == 4 && xobj.status == "200") {
      // Using an anonymous callback due to asynchronous nature of .open method
      callback(xobj.responseText);
    }
  };
  xobj.send(null);
}

// Load the json...
loadJSON(response);

// Declare global variables...
var lookup = [], errors = [], i, e, id, lookupId, minLength;

function response(responseData) {
  // Convert json data into objects
  var rulesSet = JSON.parse(responseData);

  // Iterate over objects
  for (i = 0; i < rulesSet.length; i++) {
    // Create a lookup for each object for future use
    lookup[rulesSet[i].id] = rulesSet[i];
  }

  // Loop through form elements and store ids

  // Validate the form
  function validate(e) {
    var elements = document.getElementsByTagName('input');
    for (e = 0; e < elements.length; e++) {
      id = elements[e].getAttribute('id');
      lookupId = lookup[id].rules;
      var rules;
      // Process rules of the matched IDs
      for (rules of lookupId){
        // Check for min length rule
        if(rules.name === 'min_length') {
          minLength = rules.value.toString();
          // Verify validity of the rule (existence of number)
          if(isNaN(minLength) || minLength.length === 0){
            // Log an error
          // Check min length and report an error if invalid
          } else if(!checkMinLength(minLength, id)) {
            errors[errors.length] = id + " - You must enter more than " + minLength + " characters";
          }
        }
      }
      // If there are errors, display them
      if (errors.length > 0) {
        reportErrors(errors);
        //e.preventDefault();
      }
    }
  }
  validate();

  // Verify field length
  function checkMinLength(minLength, id){
    var val = document.getElementById(id).value;
    if(val < minLength){
      return false;
    }
    return true;
  }

  // Error reporting
  function reportErrors(errors){
    for (var i=0; i<errors.length; i++) {
        var msg = errors[i];
    }
    console.log(msg);
  }

  $('#email-submit').on('click',function(e){
      validate(e);
  });

}

Below is the JSON content that is loaded...

[
  {
    "id": "search",
    "rules": [
      {
        "name": "min_length",
        "value": "5"
      },
      {
        "name": "email"
      }
    ]
  },
  {
    "id": "phone-number",
    "rules": [
      {
        "name": "min_length",
        "value": 8
      }
    ]
  },
  {
    "id": "surname",
    "rules": [
      {
        "name": "min_length",
        "value": 10
      }
    ]
  }
]

Finally, here's the basic form that requires validation...

<form action="index.html" name="searchForm" id="search-form">
            <label for="search">Email</label>
  <input type="text" id="search" name="email" placeholder="Enter email">
  <input type="text" id="phone-number" name="name" placeholder="Enter name">
        <button type="submit" id="email-submit">Submit</button>
    </form>

Answer №1

The code performs the exact instructions provided

// Error reporting
function reportErrors(errors){
  for (var i=0; i<errors.length; i++) {
    var msg = errors[i];  <-- variable set on each iteration
  }
  console.log(msg);  <-- displays the last value from the last iteration
}

It's necessary to move the console statement inside the for loop

// Error reporting
function reportErrors(errors){
  for (var i=0; i<errors.length; i++) {
    var msg = errors[i];  
    console.log(msg);  
  }
}

Alternatively, you can skip the looping process altogether

// Error reporting
function reportErrors(errors){
  console.log(errors.join("\n"));        
}

There's also a logic issue where a function is being declared inside a for loop

function response(responseData) {
  // omitted code //

  var elements = document.getElementsByTagName('input');
  for (e = 0; e < elements.length; e++) {
    function validate(e) {  <-- THIS SHOULD NOT BE IN THE FOR LOOP

Similar to the error message situation, only the final outcome will be retained...

Answer №2

Develop a more structured system without the need for closure.

var submitButton = document.querySelector('#email-submit')

function validate (evt) {
  async function loadRules (url) {
    var rawData = await fetch(url)
    return await rawData.json()
  }

  function reportErrors (error) {
    evt.preventDefault()
    // Reporting logic implemented here
  }

  function evaluate (rules) {
    // Implement your validation rules here
    // Rules are loaded into the 'rules' object
    // For example, access rules[0]['rules'].name
  }

  loadRules('js/rules.json').then(evaluate)
}

submitButton.addEventLister('click', validate)

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

Discovering the JSON path for a field that includes periods, like "session.content", is essential for navigating through the data

When making a REST API call, I am encountering an issue with parsing the response in Java. The specific problem lies with "session.content", as it appears to be null when trying to access it using "fields.'[session.content]'". This results in a p ...

When switching between activities in ANDROID STUDIO, the local json file keeps resetting

I have encountered a problem with my Android app. In my second activity, I am reading and modifying a local JSON file. Everything works as expected until I switch back to the mainActivity and then return to the second activity. It appears that the changes ...

Using knockout.js to bind each item in a JSON array to a <td> element

Imagine I have a web service that returns a C# List serialized to JSON. In the client, the viewmodel receives a JSON array like this: [ {"Id": 1, "Name": "John", "Age": 30}, {"Id": 2, "Name": "Mike", "Age": 25}, {"Id": 3, "Name": "Lana", "Age" ...

Trouble with React Material Modal TransitionProps triggering onEntering event

Currently, I am in the process of updating Material UI to version 5. Initially, I encountered an error stating that onEntering is deprecated and should be replaced with transitionprops. There is a specific method (let's name it doSomething) that I wa ...

Confirming the existence of a folder with AngularJS

Currently, I am attempting to determine if a folder exists so that I can make decisions on which files to include using ng-include. This is what I have so far: $scope.isVisible = { buttons: checkForClientOverwride('buttons'), it ...

I encounter an error message stating "Cannot read property 'push' of undefined" when trying to add an item to a property within an interface

I have a model defined like this : export interface AddAlbumeModel { name: string; gener: string; signer: string; albumeProfile:any; albumPoster:any; tracks:TrackMode[]; } export interface TrackMode { trackNumber: number; ...

Are you considering using requestAnimationFrame on your iPhone?

Can the requestAnimationFrame function be used on an iPhone running iOS 5.1? Based on my research, it seems that mobile Safari does not support this method, regardless of whether or not a vendor prefix is used. ...

Fade or animate the opacity in jQuery to change the display type to something other than block

I am currently using display: table and display: table-cell to vertically align multiple divs. However, I have encountered an issue when animating the opacity with jQuery using either fadeTo() or fadeIn. The problem is that it always adds inline style di ...

What is the best way to access an external array using ng-repeat in AngularJS?

My dataset consists of 3 separate arrays. "areas": { "default": [ { "area": "Master Bedroom", "uuid": "986e3f42-1797-49ae-b060-181a33b9", "description": "", "new": [ { "value": "986e3f42-1797-49ae-b060-181a3 ...

Creating a JSON object in Ruby: A beginner's guide

Currently working on generating a JSON file using Ruby. In this process, I am trying to define the object "companies" within the JSON structure. Expected output: {"companies":[ {\"label\":\"Wayfair \",\"values\":[54]}, ...

Exclude unresolved Promises

I have a collection of Promise instances that I would like to iterate through in order to identify and remove the rejected Promises. Desired outcome: const promises = [ failedPromise, successPromise, successPromise, ]; const resolvedPromises = pro ...

There is an issue with the left-hand side in this JavaScript

Currently encountering an issue with the code line $('#cps').val() = time;. To clarify, I am aiming to assign the value of variable time to cps instead of comparing them. var amount = 0; $("#cps").click(function() { amount = amount + 1; ...

What is the best method for encrypting a file using node.js?

I am in the process of finding a way to encrypt various types of files like txt, mp3, or any other file in node.js while utilizing socket.io. My goal is to develop an application that can securely send files to another client, so I wish to encrypt the file ...

"Error message: Undefined index error when trying to decode JSON

In my database, there's a JSON file named articles.json which contains data as follows: { "articles": [ { "id": 1, "title": "a" } ] } Now, I have written a script to decode this JSON file: <?php include "inc/header. ...

The click event fails to provide $event upon being clicked

Within my HTML structure in an angular 7 application, I have the following setup: My goal is to trigger the GetContent() function when any text inside the div is clicked. Strangely, when clicking on the actual text, $event captures "Liquidity" correctly. ...

Creating a grid with individual node delays in CSS animations using ReactJS

Struggling with a CSS animation issue in ReactJs. I suspect the problem, but unsure how to solve it. I'm rendering a 5x5 grid and displaying it using this function: DisplayNodes = () => { const {grid} = this.state; // get the node array fro ...

Safari is causing issues with HTML5 Video playback

I have a client with a media-heavy website containing numerous video and audio files. While the videos load perfectly on Chrome, Firefox, and IE, they do not load on Safari for Windows. Here's a snippet of the code: <video controls="controls" type ...

Troubleshooting issues with Firebase integration in a Node.js environment

I am currently encountering difficulties implementing Firebase in my Node.js project. Below is the code snippet that I am attempting to execute on Node. var firebase = require("firebase"); var admin = require("firebase-admin"); var serviceAccount = requi ...

Issue with rendering object in Three.js ply loader

Just starting out with three.js and Angular 13, using three.js v0.137.0. I'm attempting to load and preview a ply file from a data URL, but all I see after rendering is a bunch of lines, as shown in this screenshot - how the ply file renders. The .pl ...

Is it possible to capture a webpage screenshot using a mocha/phantomjs unit test?

My current setup involves using grunt-mocha to execute unit tests with phantomJS. I'm aware of the numerous capabilities that phantomJS offers. Is there a way to utilize these features within a mocha test? I have already checked the typical location ...