jQuery, duplicate click event

Asked

Viewed 5,072 times

3

I saw here that nay can do Singleton in javascript.

I have a problem with that feeling, I have the following instruction:

$("#mSalvar").click(function(){
    man.bSalvarClick();
});

This generates a duplicate record when the user clicks to load the page without it being finished, ie the user force and the script is loaded more than once, so the instruction of this event is executed more than once, would be able to make that instruction run only once in a guaranteed way ?

Edit: Another case would be a query button, where I have to leave the button always enabled, only when the script is duplicated it does N ajax queries instead of one per click.

As image below I gave only 1 click on the button and see how many times the query was executed:

inserir a descrição da imagem aqui

I make the js file call this way:

<html>
<head>...</head>
<body>...
<script type='text/javascript'>
    document.getElementsByTagName("head")[0].appendChild('jConsultaManifesto.js');
</script>
</body>
</html>

This file that has HTML and calls . js is called through a menu, which makes the . load() of this file, only there are some users who can’t wait for the page to load, so it is busy to click on the menu before the page to load and the script is duplicated, I can’t use the menu for the user not to click if they ask me.

  • You can disable the button after the first click. $(this).prop('disabled', true).

  • @Kaduamaral I’ve done one up to one. Hide(), the problem is that the script calls the function because it is already duplicated, that is to say 1 click on the screen and the script as it is duplicated runs twice the same instruction

  • The problem then is not the click, but the loading of the script, right? How is loading the script?

  • @Kaduamaral I give an append on the write file at the end of the html where the page is being loaded Document.getelementsbytagname("head")[0]. appendchild(fileref);

  • You can edit your reply by adding this code and an example of content from fileref? Is text or a DOM element?

5 answers

2


You can create a function that loads the scripts and check whether the script has already been loaded:

$(document).on('click', '.load', function(event){
    event.preventDefault();
    
    var script = $(this).data('script');
    var src = $(this).data('src');
    
    if ($('script[data-name="'+script+'"]').length == 0 ){
        
        $('head').append(
            $('<script />').attr('type', 'text/javascript')
            .attr('src', src)
            .attr('data-name', script)
        );
        
        console.log(script, 'carregado.')
        
    } else {
        console.log(script, 'já foi carregado' );
    }
});
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<button class="btn btn-primary load" data-src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js" data-script="bootstrap">Carregar Bootstrap</button>

<button class="btn btn-primary load" data-src="jConsultaManifesto.js" data-script="consulta-manifesto">Carregar Consulta Manifesto</button>

  • It seems that so solves, I will test more calmly, I have to see the question if the.js file load another page with the same variables, would duplicate the event? I have to do more tests as soon as possible I return, plus your solution is an excellent idea, thanks already

  • 2

    Adding functions to check if the element has already been loaded is a solution but this will give you a lot of headache later because the problem is simple, there are two calls of the same method, or you are loading the same scripts more than once, or jquery is also being loaded more than once, if you do not remove this duplicity you will have to do a check for each method after.

2

If I understand correctly, your program loads HTML and scripts dynamically for each page you open. It should be something like a Single Page Application.

Well, the first step is to understand the strategies you can adopt to load the pages.

Load all at start

Depending on the size and use of the system, a strategy may be to concatenate all Htmls into one and all Scripts into a single script.

The final size will be larger, but once loaded, the system will have a much faster response time.

If this strategy is feasible, you just need to ensure that the script boot will be done once.

Load on demand

This is the strategy you are now adopting. Each accessed page loads its own HTML and Javascript.

The mistake you are making, however, is to load the HTML and Javascript to each access. You must ensure that they are reused in later accesses.

In the case of Script it is easy. Instead of manually adding to the DOM, create a function in the main script where pages may require a specific script.

For example, it follows a very rudimentary implementation:

var scripts = {};
function require(pagina, src) {
    if (src in scripts) {
        //carregar script de "src"
        scripts[src] = true;
    }
}

Use AMD

Better yet, you can use AMD and end up with duplicate code for good. Then the management of scripts in modules will be fully managed by a reliable library and following the standard of the web currently.

Note that AMD is a standard that can have different implementations.

You can make each page an AMD module, for example:

define('myModule', ['dep1', 'dep2'], function (dep1, dep2) {

    //Define the module value by returning a value.
    return function () {};
});

So whenever you need to access a module just do so:

var $ = require('jQuery');
var myModule = require('myModule');

The AMD manager ensures that the module will be downloaded and booted only once.

End up with dynamic pages

Maybe your HTML is being rendered on the server. For a responsive application, it would be much better to leave static HTML templates and do the bind of data obtained via Ajax calls to a REST endpoint.

Advantages include:

  • Best performance
  • Lower amount of traffic data
  • Most consistent system API
  • Avoid another layer of technology to generate dynamic pages, that always general some kind of problem
  • Scalability greatly facilitated

The downside is that you need to be very careful not to end up with too much complicated code in Javascript.

Beware of the events

Placing event handlers directly into the elements, especially on pages that can load multiple times, is always a problem.

An alternative is not to bind directly to the element, but to use the function appropriately on jQuery. Example:

$('#main-content').on('click', '#btn-salvar', function() {...})

In the past the 'live' function was used to add events to elements that were not yet in the DOM, but now the form above is used.

The idea is that the event will be triggered whenever any button with id=btn-salvar is clicked inside an element with id=main-content. Regardless of whether the button exists, it will be created or recreated inside that element.

  • I didn’t know this AMD, I’ll give a study, thank you!

1

This probably occurs by a duplicate stream of your application.

The easiest way to prevent the problem is to remove the event assignments, to ensure that it does not run more than once, using unbind():

$("#mSalvar").unbind("click").click(function(){ // faça algo });

On singletons, one practical way to implement is to create a static class and assign the instance of an object to it. It’s not actually a Singleton, because javascript will not deal with whether your Singleton name is unique, but in practice, it works similar to a:

var SingletonCtrlCliente = {
     InstanciaSolitaria : null
 }

 $(function(){
      SingletonCtrlCliente.InstanciaSolitaria = new CtrlCliente();
 });

 function CtrlCliente(){
    // função pública
    this.facaAlgo = function(){

    }

    // função privada
    function definaEventoDeBotao(){

    }
 }

1

I recently discovered that I can make the click event stop propagating among other functions that are also called through the same event would be like this:

$('seletor').click(function(evt){  evt.stopImmediatePropagation(); });

http://api.jquery.com/event.stopimmediatepropagation/

  • Interesting did not know, put an example as in jQuery documentation to enrich the answer. ;)

0

Simply add a lock, and leave your element disabled in the interface:

var salvou = false;
$("#mSalvar").click(function(){
    if (salvou) {
       return;
    }

    man.bSalvarClick();
    $(this).prop( "disabled", true );
    salvou = true;
});
  • so resolves, but then I have to create a flag variable for each event click of the program, would not have another way to ensure that the event click is unique, without having to create these flags and then have to keep checking them

  • had not tested with the query where the button needs to be enabled, so I withdrew the vote, but thanks for the effort, if you have another idea let me know, thanks again

Browser other questions tagged

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