Javascript function being called too early

Asked

Viewed 58 times

2

I have a registration form that has, among others, the following field:

<div id="Aditivo" class="col-xs-12 col-md-2">
            @Html.LabelFor(model => model.NumeroAditivo, new { @class = "control-label" })
            @Html.TextBoxFor(model => model.NumeroAditivo, new { @class = "form-control no-caps", @ng_readonly = "!m.Editavel" })
        </div>

Which should only be displayed when the Template (another field of my Contract form) starts with "Additive".

For this, I created the following javascript function:

    function verificarAditivo() {
        if ($("#ModeloId_chosen").text().startsWith("Aditivo")) {
            $('#Aditivo').show();
            $('#Numero').attr('class', 'col-xs-12 col-md-2');           
        }
        else {
            $('#Aditivo').hide();
            $('#Numero').attr('class', 'col-xs-12 col-md-4');   
        }
}

The function checks whether the selected Model (Modeloid_chosen) starts with "Additive" to then display or hide the created field.

It turns out that this function should also be called as soon as the page is loaded, so I tried to use: $(document).ready(verificarAditivo) and $(window).on("load", function () { verificarAditivo(); }

But both of them didn’t answer because when they called the function, my list of Models...:

<div class="row">
        <div class="col-xs-12 col-md-12">
            @Html.LabelFor(model => model.ModeloId, new { @class = "control-label" })
            @Html.DropDownListFor(model => model.ModeloId, defaultSelect, new
       {
           @class = "form-control chosen-select",
           @data_url = @Url.Action("ListaModelo", "Modelo", new { modeloId = Model.ModeloId }),
           @chosen = true,
           @ng_options = "o.value as o.label group by o.group for o in options.ModeloId track by o.value",
           @onchange = "verificarAditivo(); carregaComplemento('" + @Url.Action("Listar", "Complemento", new { contratoId = Model.ContratoId }) + "?modeloId=' + this.value);",
           @ng_readonly = "!m.Editavel",
           @ng_model = "v.ModeloId",
           @chosen_scope = "m",
           @ng_change = "alterarModelo();"
       })
        </div>
    </div>

...It hasn’t been filled out yet. That is, the function is being called too early and there is still no place to check if the Model starts with "Additive".

I could only "solve" the problem using a setTimeout, but I believe this is not the best solution.

Any idea how to call the function I created once the page is ready but with my Templates list already filled?

EDIT1: I also tried with Angular:

$scope.alterarModelo = function () { verificarAditivo(); }

$scope.$on('$viewContentLoaded', function () { verificarAditivo(); });
  • Hello I suggest you take a look at Promisses this will solve your problem see this video https://www.youtube.com/watch?v=7Bs4-rqbCQc. has this documentation from MDN https://developer.mozilla.org/en-US/Docs/Web/Javascript/Guide/Usando_promises If I had more time I would post the answer, if no one answered, put the night.

  • I will take a look yes, if I can not wait for your reply. Thank you.

2 answers

1


I just realized that you are using Angular, and I don’t know anything about Angular or the language you are using to upload the data, but I will try to help you by giving an example with Jsvanilla and you try to adapt to your reality, come on. First you need to know why this error happens, unlike other programming languages that are multi-threaded() and have by default synchronous processing (como JAVA por exemplo), the JS is the opposite, it is single-thread and the processing happens asynchronously, so often you will end up falling into errors like this because it does not wait for the processing of one method to end to perform another, used to use chained callbacks to solve this problem, but this was seen as bad practice by the community, so that’s why the Promises, they are basically a structure that allows you to run a block of code only when another determined to finish processing, only in a more concise way facilitating maintenance. Let’s take as an example the following code:

let teste = 0;

function exibirValorTeste () {
    console.log(teste);
}

setTimeout (() => {
        teste = 1;
    }, 3000);

exibirValorTeste();

in that code the value displayed in the console would be 0 because the value of the test variable only changes to 1 after 3 seconds, only that the method exibirValorTeste() is called before that, now let’s see the same method using Promises

let teste = 0;

function exibirValorTeste () {
    console.log(teste);
}

new Promise(function(resolve, reject) {
    setTimeout (() => {
        teste = 1;
        resolve();
    }, 3000)
}).then (
    (value) => {
        exibirValorTeste();
    },
  (error) => {
    //pode exibir um alerta de erro por exemplo
  }
);

already in this example it would display 1 on the console because the method exibirValorTeste() is called only when the block of the setTimeout() is finalized, and at this point the test variable would already be with the value 1, to understand the functioning of Promise Let’s divide it into two parts:

new Promise(function(resolve, reject) {
    setTimeout (() => {
        teste = 1;
        resolve();
    }, 3000)
})

At this moment you are instantiating the Promisse, it takes as parameter a função anonima in its constructor, which in turn receives 2 parameters, the resolve serves to signal success and the reject to signal error in your Promise, inside the block of Promise we have the setTimeout() which defines that after 3 seconds the test variable = 1, realize that right after we call the resolve() this signals the Promise that everything went well and that now she can run the block then().

.then (
    (value) => {
        exibirValorTeste();
    },
  (error) => {
    //pode exibir um alerta de erro por exemplo
  }
);

The block then() receives two anonymous functions as parameter the first one is executed when you call the resolve() and must contain the actions of success, and the second is called when you call the reject() and must contain the error actions, Obs: AS DUAS NUNCA SERÃO EXECUTADAS AO MESMO TEMPO, in our example there is only success so we will always fall into the first function, and within the success block we call the function exibirValorTeste()

Some final considerations:

1° - The second parameter of the method then() is optional, if we wanted we could write the then() only with the success parameter.

2° - You can pass values as a parameter to the success and error functions by calling the resolve or the Reject as an example reject(algumValor) or resolve(algumValor), and to use these values just use the received parameters in each respective function, as our test variable was global this was not necessary in our example, so I called the resolve() as empty parentheses.

recommend that you deepen your studies in the Promises because this is a key topic for any JS developer.


Then what you will have to do in your code is to make the loading of your data within a Promise, and your verification method is inside the block then() of that Promise, you may have to stop using the Expression Languages and load the data via a request AJAX, setting the values via JS manually, this part then you will have to hit head to refactoring your code. Good luck, I hope my explanation has helped you.

  • 1

    Thank you very much for the explanations!

0

The event can be used change if it is a select, for other html fields you should look for an event that indicates that the user has just filled in the field, such as events blur in text fields.

Try changing the option selected in the example below:

$('#campo-select').on('change', function() { 
     console.log('A opção selecionada foi: ' + $(this).val())
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select id="campo-select">
  <option value="A">Opção A</option>
  <option value="B">Opção B</option>
</select>

  • I tried this without success: $('#Model'). on('change', Function() { checkAditive(); }); I will search for an event that indicates that the user has just filled the field, but I don’t know if it is applicable and when the page is loaded, a Template is already selected in the field. When the page is already open and the user selects a Template, I can already call the function using @onchange, the problem is to call at the right time when the page has just been loaded.

  • and call on the $(document).ready and no change?

  • $(Document). ready calls the function too early, when the list of Templates is not yet filled.

  • And how that list is filled?

  • I showed there in my post, has an Html.Dropdownlistfor, which receives the data from the "Listtemplate" which is a Jsonresult

Browser other questions tagged

You are not signed in. Login or sign up in order to post.