Validate Json API response

1

In the last days I have had a problem that I have not been able to solve, I hope to get your help, please. The problem is this: I am creating a page which has a module in which inputs are created dynamically but each of those inputs must return a json to me by calling the API that generates that json by ajax and GET method, I have to validate that each string entered is correct or failing to get a response GET 404 NOT FOUND I was trying to solve with http request but only validates the first input of all that are created, I have entered the validation in a for cycle in which are all the values of the inputs but always execute the ajax code at the end of the whole process.

What happens in the code is that the for cycle is executed without executing the code part ajax , since the code ajax is executed after executing the for. This confuses me a lot, I hope your help

Code

function procesar(){

    var array = [];
    var maximo = 1300;
    var char2 = CKEDITOR.instances['semblanza'].getData().length;
    var maximolineas = 1300;
    var char2lineas = CKEDITOR.instances['lineas'].getData().length;
    var maximoproy = 1300;
    var char2proy =     CKEDITOR.instances['proyectos_vigentes'].getData().length;
    var cv = document.getElementById('cv').value;
    var lineas = document.getElementById('lineas').value;
    var semblanza = document.getElementById('proyectos_vigentes').value;
    var doiarray = document.getElementsByName('doi2[]');
    variable = true;

    for(var i = 0; i < doiarray.length; i++){

        var data = "http://api.crossref.org/works/"+doiarray[i].value;

        if(doiarray[i] != "" && variable == true){

            $.ajax({
                type: 'GET',
                url: data,
                success: function(data, textStatus) {
                    if(variable=true ){
                        alert(variable+"3");
                        variable= true;
                    }

                },error: function(xhr, textStatus, errorThrown){
                    variable = false;
                    alert("No se debe enviar formulario")
                    if(xhr.status=='405' || xhr.status=='404'){
                        alert("Ingresa una cadena valida")
                    }
                    console.log("No");
                }
             });

        }else{

            if(maximo>=char2 && maximolineas>=char2lineas && maximoproy>=char2proy){
                 variable = true;
                 alert(variable+"6");
             }else{
                 variable = false;
                 alert(variable+"8");
                 alert("Numero de caracteres sobrepasados")
             } 
         } 
     }

     if (variable == true ){
        document.forms['data'].submit()
     }
  }
    
asked by Jesus Regalado 25.03.2017 в 16:58
source

2 answers

2
  

Always execute the ajax code at the end of the whole process. What happens in the code is that the for cycle is executed without the part of the ajax code being executed, since the ajax code is executed after the for execution. This confuses me a lot, I'm waiting for your help.

There are several concetos that are escaping in your question. One, is the concept of asynchrony and the other, in how var works in ES5.

Asynchrony

Asynchronous code is understood as the code that does not maintain a synchronization flow between instructions. A synchronous code maintains a relationship between the execution of a process and the expected response; whereas an asynchronous code does not have any relationship. An asynchronous code does not "wait" for the response of an execution; instead, it "moves ahead of this (future)" to know what to do when it happens.

The most practical and basic example of an asynchronous code are callbacks:

function doSomeTask(cb) {
  ...
  cb(result);
}

A callback is a function that will handle the response once it is obtained. It's like saying: do something, when you finish, execute this .

An important concept about asynchronous code is that there is no way to know when the response will occur, since it depends on several factors, including external (latency, etc.) and the flow of the program will continue without course wait for that answer. This is one of the reasons why the Promise specification was proposed for ES6.

Scope and scope of variables

In ECMAScript 5, 2006 version until mid 2015, there was only one way to declare variables and this was by means of var . But there was a problem: the variables declared with var do not have a scope of fixed scope , they are always limited to two: scope of function and global scope.

When you declare a variable, in the place where it is declared, its scope remains the function where it is declared or, failing that, window . Take the following code as an example:

function doSomeTask () {
  if (true) {
    var x = 123;
  } else {
    // x sigue disponible aquí
  }
}

This is called hoisting and it happens like this because of language design issues. The reality is that x is not declared as a local variable, if not, as a function. In this way, the previous function is interpreted in the following way:

function doSomeTask () {
  var x;

  if (true) {
    x = 123;
  } else {
    // por eso x es visible aquí
  }
}

What does this have to do with your problem? Well, nothing, but indirectly, it has to do.

  

When you use a variable declared with var within a for and it is used within a callback, this variable will be taken as reference , being in all the iterations, the value of the last iteration.

There are two solutions to this problem:

  • Use a closure
  • Use let (ES6)

Using a closure or an IIFE what you do create a new execution environment in each iteration and the variable is passed as a parameter and as is public knowledge, the variables in JavaScript are passed by value.

for (var i = 0; i < 10; i++) {
  (function (x) {
    // proceso asíncrono
  })(i);
}

The other option is much cleaner:

for (let i = 0; i < 10; i++) {
  // proceso asíncrono
}

However, when you want to perform asynchronous processes sequentially , one option is to make the code synchronous / blocking. You can do this by using recursion.

function validateInput(index = 0) {
  if (doiarray.length - 1 === index) { return; }

  var data = "http://api.crossref.org/works/"+doiarray[index].value; 

  if (doiarray[index] !== "" && variable === true) {
    $.ajax({
     url: data,
     ...
    })
    .done(function (res) {
      ..
      validateInputs(index + 1);
    })
    .fail(function (xhr, status, err) {
      ..
      validateInputs(index + 1);
    });
  } else {
    ...
    validateInputs(index + 1);
  }
}

The function will run again and again until all the elements of doiarray have been traversed. It is a practical and direct way to do what you want.

    
answered by 01.04.2017 в 05:02
1

I've noticed that this answer and this other have not been enough so you definitely understand what an asynchronous code consists of. I will try to explain it with some simple examples before seeing the errors in your code, because until you understand this concept I think that you should not continue working with calls Ajax .

In an asynchronous code each operation does not wait for the response of another to be evaluated. The operations are evaluated at the same time and the result of each of these will be when you receive the answer (this will happen after your code has been fully evaluated). For example, analyze the following snippet:

var variable = true;

setTimeout(function() {

  if (variable === true) {

    console.log("perfecto, el valor es true");

  }

}, 1000);

variable = false;

The previous code is evaluated completely at the beginning, but the condition that evaluates whether the variable variable has value true will be done when the setTimeout is executed and this will be executed after a second and at that moment the variable will have value false since the end of the code has been declared thus, therefore the console.log that is within the condition will never be executed.

Now evaluate the following snippet:

for (var i = 0; i < 4; i++) {

  setTimeout(function () {

    console.log("la variable i tiene valor " + i);

  }, 2000);

}

Each of the setTimeout that are within the cycle is evaluated in each iteration but will not execute its code until two seconds pass. When the two seconds have elapsed the four setTimeout will trigger and at that moment the value of the variable i will be 4 (it is the value in which the cycle ends).

Well, in a similar way, a call Ajax works asynchronously (by default a call Ajax is asynchronous). It is a call you are making to a server and it will return the answer at some point, but that moment will always be after all your code has been evaluated. Therefore, the following code:

var variable = true;

$.get("/rest/api/", function() {

    if (variable === true) {

        console.log("perfecto, el valor es true");

    }

});

variable = false;

It will never throw the console.log in the same way that the first example does not launch it.

And the following code:

for (var i = 0; i < 4; i++) {

    $.get("/rest/api/", function () {

        console.log("la variable i tiene valor " + i);

    });

}

It will send you four console.log with the variable i with value 4 and not exactly the four will be executed at the same time.

If you have understood this, then you will have an answer for the next question you ask:

  

What happens in the code is that the for cycle is executed without executing the code part ajax , since the code ajax is executed after executing the for. This confuses me a lot, I hope your help

If this is clear to you, then you should analyze that the function that is executed in each call Ajax will trigger after all your code has been evaluated and a response is received from the server. Therefore, the variable variable does not have to have the same value that it had at the beginning, since it is a global variable and you change its value in else of your condition depending on the value of the others inputs .

On the other hand, you have a small error in the following condition:

if( variable = true ) {
    alert(variable + "3");
    variable = true;
}

The equality operator is == and the strict equality equation is === . With the previous code you are assigning value true to the variable and the condition will always be fulfilled.

    
answered by 01.04.2017 в 03:11