jQuery, duplicate click event

3

I saw here that no can do singleton in javascript .

I have a problem with this, I have the following statement:

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

This generates a duplicate record when the user clicks load the page without it is finished, ie the user forces and the script is loaded more than once, so the statement of this event is executed more than once, would I have to make this statement 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 one per click.

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

Icallthejsfilethisway:

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

This file that has HTML and makes the call of .js is called through a menu, which does the .load () of this file, only that there are some users that can not wait to wait for the page to load, in the menu before in the page load and the script gets duplicated, I can not press the menu so that the user can not click if they ask me.

    
asked by anonymous 27.07.2015 / 15:40

5 answers

2

You can create a function that loads the scripts and check that 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><buttonclass="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>
    
27.07.2015 / 18:04
2

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

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

Load everything at the beginning

Depending on the size and usage of the system, one strategy may be to concatenate all HTMLs in one and all Scripts in 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 make sure that the script initialization is done once.

Load on demand

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

The error you are making, however, is loading the HTML and JavaScript with each access. You should ensure that they are reused on subsequent hits.

In the case of Script 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, a very rudimentary implementation follows:

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 get rid of duplicate code. There, module script management will be fully managed by a trusted library and currently following the web standard.

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 simply do so:

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

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

End dynamic pages

Maybe your HTML is rendering on the server. For responsive application, it would be far better to leave static HTML templates and bind bind from data obtained via Ajax calls to a REST endpoint.

Advantages include:

  • Better performance
  • Least amount of data trafficked
  • More consistent system API
  • Avoid another layer of technology to generate dynamic pages, which 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 events

Placing event handlers directly on elements, even more on pages that can load multiple times is always a problem.

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

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

The 'live' function used to add events to elements that were not already in the DOM, but now the form above is used.

The idea is that the event will fire 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 within that element.

    
11.09.2015 / 06:08
1

This is most likely due to a duplicate flow 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, a practical way to implement is by creating a static class and assigning the instance of an object to it. It is not a singleton in fact, since javascript will not handle if the name of your singleton is unique, but in practice it works similar to one:

var SingletonCtrlCliente = {
     InstanciaSolitaria : null
 }

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

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

    }

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

    }
 }
    
29.07.2015 / 14:45
1

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

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

link

    
10.09.2015 / 19:36
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;
});
    
27.07.2015 / 15:52