Responding directly to your question
Is it correct to put an event inside another event?
If it is correct, the trick is to know when you should do it and when not. First consider that there are several types of events, not just the 'click'
, which can fulfill different functions.
When is a good practice?
When done in a controlled manner
An example is the ready event that only triggers when the page loads. Trying to link an event before it is triggered can result in the page not being fully loaded, the object to which you are trying to add the event (click) is not yet available and your code fails. The fact that this event is triggered only once guarantees that no more events click
per accident will be added to the same element.
Always avoid creating events indiscriminately since that only leads to memory leaks and the same code running over and over again.
Events consume memory and it is very easy to lose track because it is difficult to know, for example, how many events of a type have a specific element associated 1 . Besides its indiscriminate use can lead to the same code being executed several times without you noticing.
I'll give you an example where you can do it; If the button to which you are trying to add the event does not exist yet and is created as a result of the execution of the first event. In this scenario, the only alternative is to create the element first so that the event can be added later.
$('#button1').click(function() {
const button2 = $('<button>Click me</button>');
button2.click(function() {
// Haz algo
});
$('#placeholder').append(button2)
});
Another alternative that is very similar to the exposed code is when the content of the event is generated from a certain algorithm (which depends on the input of the user, for example), something like a factory of events. In that case always remember to unlink the events that you have previously added.
$('#button1').click(function() {
const data = $('#input').val()
const button2 = generaBoton(data);
const evento = generaEvento(data);
button2.click(evento);
});
In any case, it is important to remember that events can (and should) be unlinked if the function with which you generated them is stored
let evento = null;
const button1 = $('#button1');
const button2 = $('#button2');
button1.click(function() {
// Si ya se generó lo eliminas para que no se duplique
if (evento) {
button2.off('click', evento)
}
// Conservas una referencia al evento
evento = function() {
// Haz algo
};
button2.click(evento);
})
Many times the syntax $(selector).off('evento')
is used as an escape valve to eliminate all of a type without having to store the function but the use of this mechanism requires caution since you could end up eliminating another one that you do not want to eliminate (remember that it can be another event besides click
).
By correcting your example, first I must point out that to whom you are linking the event is not the button but the div
. The event is executed anyway because it makes bubble from the button to div
. Try to change
// Inserta el botón como contenido del div
$('#button').html(button);
for
// Inserta el botón fuera y justo después del div
$('#button').after(button);
and check that nothing happens when you click.
$(document).ready(function() {
//Primer input file
$(document).on('change', '#file', function() {
let file = $(this);
let nameFile = file[0].files[0].name;
let button = '<button type="button">Clic input 1</button>';
$('#button').after(button);
$('#button').click(function() {
console.log('CLICK IN FIRST INPUT FILE!');
});
});
//Segundo input file
$(document).on('change', '#file2', function() {
let file = $(this);
let nameFile = file[0].files[0].name;
let button = '<button type="button">Clic input 2</button>';
$('#button2').html(button);
});
$('#button2').click(function() {
console.log('CLICK IN SECOND INPUT FILE!');
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="file" id="file" name="file" />
<div id="button"></div>
<div style="margin-top:20px"></div>
<input type="file" id="file2" name="file2" />
<div id="button2"></div>
If we fix the code
//Primer input file
$(document).on('change', '#file', function () {
let file = $(this);
let nameFile = file[0].files[0].name;
// No almacenes una cadena sino que crea un elemento html
let button = $('<button type="button">Clic input 1</button>');
$('#button').html(button);
// Agrega el evento al boton creado, no al div
button.click(function () {
console.log('CLICK IN FIRST INPUT FILE!');
});
});
You will notice that the problem disappears and it is because by replacing the content of div
you also destroy the button and therefore release the event. This is the reason why when you create it again it only triggers once.
If you still want to run it on an element that you will not destroy (for example the div
as you had previously)
$(document).ready(function() {
//Primer input file
$(document).on('change', '#file', function() {
let file = $(this);
let nameFile = file[0].files[0].name;
let button = '<button type="button">Clic input 1</button>';
$('#button').html(button);
// Elimina el evento antes de agregar uno nuevo
$('#button').off('click');
$('#button').click(function() {
console.log('CLICK IN FIRST INPUT FILE!');
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="file" id="file" name="file" />
<div id="button"></div>
and the problem disappears but considering that now you know the cause it is evident that the second variant in your original code is preferable since you save the step of unlinking and linking the event for each click on an element that is always available and therefore it is something you can do only once.
1 This depends on the internal jQuery code and you should never use it in production. You could update the version and let this code stop working.