I was 100% sure this code works, but in one special case it fails - spent an hour to find the bug (could not reproduce it on JSFiddle). Finally I found the cause, but I do not know why this happens. It happens only when I hide the file inputs and the result is: whichever file I change the first label is selected and changed, please take a look:
var activateFileSelection = function( container ) {
var container = container || $('body');
container.find(':file').each(function(i) {
var thisInput = $(this);
var thisLabel = thisInput.siblings('label');
if (thisLabel.length > 0 && !thisLabel.hasClass('file-input-label')) {
var thisLabelDefaultText = thisLabel.html();
thisLabel.addClass('file-input-label');
thisInput.on('change', function(e) {
if (thisInput.val()) {
thisLabel.html(thisInput.val());
} else {
thisLabel.html(thisLabelDefaultText);
};
});
};
});
};
activateFileSelection();
input {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<label for="myfile">select 1</label>
<input id="myfile" type="file" />
</div>
<div>
<label for="myfile">select 2</label>
<input id="myfile" type="file" />
</div>
<div>
<label for="myfile">select 3</label>
<input id="myfile" type="file" />
</div>
Also on JSFiddle.
If the input is not hidden, everything works fine: fiddle.
As nevermind noted below, duplicate input IDs may have something with the issue, still in script I do not address and IDs. Also, the change of each file input triggers the change of label text, but wrong one.
The layout of the HTML code may suggest that each label is linked to the input field next to it, but it is not the case. Since the for
attribute of the three labels is "myfile"
, all three labels are in fact linked to the first input field, the one that is found with document.getElementById("myfile")
.
Therefore, when you click on any label, the first input field is used. The adjacent label, obtained with thisInput.siblings('label')
in your code, is then updated after the file selection. That is true even when the 3 input fields are visible.
On the other hand, if you click directly on an input field, that input field is used and the corresponding label is updated.
The following snippet sends a message to the console to indicate which file input is used.
var activateFileSelection = function (container) {
var container = container || $('body');
container.find(':file').each(function (i) {
var thisInput = $(this);
var thisLabel = thisInput.siblings('label');
if (thisLabel.length > 0 && !thisLabel.hasClass('file-input-label')) {
var thisLabelDefaultText = thisLabel.html();
thisLabel.addClass('file-input-label');
thisInput.on('change', function (e) {
console.log("Input used: " + thisInput.data("field"));
if (thisInput.val()) {
thisLabel.html(thisInput.val());
} else {
thisLabel.html(thisLabelDefaultText);
};
});
};
});
};
activateFileSelection();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Test by clicking on label 3 vs clicking on input field 3:</p>
<div>
<label for="myfile">select 1</label>
<input id="myfile" type="file" data-field="input1" />
</div>
<div>
<label for="myfile">select 2</label>
<input id="myfile" type="file" data-field="input2" />
</div>
<div>
<label for="myfile">select 3</label>
<input id="myfile" type="file" data-field="input3" />
</div>
You need to use the proper ID for your label.
var activateFileSelection = function( container ) {
var container = container || $('body');
container.find(':file').each(function(i) {
var thisInput = $(this);
var thisLabel = thisInput.siblings('label');
if (thisLabel.length > 0 && !thisLabel.hasClass('file-input-label')) {
var thisLabelDefaultText = thisLabel.html();
thisLabel.addClass('file-input-label');
thisInput.on('change', function(e) {
if (thisInput.val()) {
thisLabel.html(thisInput.val());
} else {
thisLabel.html(thisLabelDefaultText);
};
});
};
});
};
activateFileSelection();
input {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<label for="myfile1">select 1</label>
<input id="myfile1" type="file" />
</div>
<div>
<label for="myfile2">select 2</label>
<input id="myfile2" type="file" />
</div>
<div>
<label for="myfile3">select 3</label>
<input id="myfile3" type="file" />
</div>
EDIT: I understand your question now. I'm not sure what the cause is. It's likely just a bug with how the browser interprets it is my guess. The proper way to do it is to add unique IDs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With