Reputation: 1779
I'm trying to get the count of elements with a certain class beneath a parent or grandparent element but my selector is not working.
Here is my HTML:
<div id="adv0" class="collapse">
<div class="advContent">
<div class="editor-label measure">
<label for="Height">Height*</label>
</div>
<span class="field-validation-error" data-valmsg-for="Height" data-valmsg-replace="true"><span class="" for="Height">A height is required.</span></span>
</div>
</div>
Here is the Jquery code I'm using:
var tabs = $('.collapse').not('.in');
console.log("tabs.length: " + tabs.length);
$(tabs).each(function () {
console.log("number of errors: " + $(this).find('.field-validation-error').length);
if ($(this).find('.field-validation-error').length > 0) {
id = "#" + $(this).attr('id');
$(id).collapse('show');
}
});
When I check the ID attribute of $(this), it returns "adv0", so I know $(this) is the proper starting point.
Any help would be greatly appreciated.
EDIT
I've added the complete unedited HTML in case I missed something:
<div class="advGroup">
<div class="advHeader" data-toggle="collapse" data-target="#adv0"><a href="javascript:;"><i class="icon-chevron-down"></i>Physical properties <span class="advanced">(advanced)</span></a></div>
<div style="height: auto;" id="adv0" class="in collapse">
<div class="advContent">
<div class="editor-label measure">
<label for="Height">Height*</label>
</div>
<div class="editor-field controls controls-row measure">
<input data-val-required="A height is required." class="input-small90 input-validation-error" data-val="true" data-val-number="The field Height must be a number." id="Height" name="Height" placeholder="0" value="" type="text">
<select class="input-small122" id="HeightUnitId" name="HeightUnitId" onclick="setHeightUnit()">
<option value="2">inches</option>
<option value="3">centimeters</option>
<option value="4">pixels</option>
</select>
<span class="field-validation-error" data-valmsg-for="Height" data-valmsg-replace="true"><span class="" for="Height">A height is required.</span></span>
</div>
<div class="editor-label measure">
<label for="Width">Width*</label>
</div>
<div class="editor-field measure">
<input data-val-required="A width is required." class="input-small90 input-validation-error" data-val="true" data-val-number="The field Width must be a number." id="Width" name="Width" placeholder="0" value="" type="text"> <span class="MesureUnit">inches</span>
<span class="field-validation-error" data-valmsg-for="Width" data-valmsg-replace="true"><span class="" for="Width">A width is required.</span></span>
</div>
<div style="display: none;" class="editor-label depth">
<label for="Depth">Depth</label>
<a data-original-title="Depth" href="javascript:;" class="tip" data-toggle="popover" data-content="Applies to 3 dimensional products only. This would not apply to prints for example." title=""><i class="icon-info-sign"></i></a>
</div>
<div style="display: none;" class="editor-field depth">
<input class="input-small90" data-val="true" data-val-number="The field Depth must be a number." id="Depth" name="Depth" placeholder="0" value="" type="text"> <span class="MesureUnit">inches</span>
<span class="field-validation-valid" data-valmsg-for="Depth" data-valmsg-replace="true"></span>
</div>
<div style="display: none;" class="editor-label weight">
<label for="Weight">Weight</label>
<a data-original-title="Weight" href="javascript:;" class="tip" data-toggle="popover" data-content="If you plan on using weight-based shipping then adding weight is mandatory for any non-print products." title=""><i class="icon-info-sign"></i></a>
</div>
<div style="display: none;" class="editor-field controls controls-row weight">
<input class="input-small90" data-val="true" data-val-number="The field Weight must be a number." id="Weight" name="Weight" placeholder="0" value="" type="text">
<select class="input-small122" id="WeightUnitId" name="WeightUnitId"> <option value="1">ounces</option>
<option value="2">grams</option>
</select>
<span class="field-validation-valid" data-valmsg-for="Weight" data-valmsg-replace="true"></span>
</div>
</div>
</div>
EDIT
The following was added to show that the code is wrapped in a listener that fires when the form validator finds an error:
$(document).ready(function () {
$("form").bind("invalid-form.validate", function () {
clearTimeout(t);
hideLoader();
$('#formErrorNotice').show().delay(1500).fadeOut();
var tabs = $('.collapse').not('.in');
console.log("tabs.length: " + tabs.length);
tabs.each(function () {
var $this = $(this),
thisErrors = $this.find('.field-validation-error'),
thisId = '#' + $this.attr('id');
console.log("current tab ID: " + thisId);
console.log("number of errors: " + thisErrors.length);
if (thisErrors.length) {
$(thisId).collapse('show');
}
});
});
This line within the same block fires when it should:
$('#formErrorNotice').show().delay(1500).fadeOut();
So I believe this is firing at the proper time.
Upvotes: 0
Views: 2166
Reputation: 1779
So the issue was that the unobtrusive validator had not updated the error classes at the time the function was called, so getting the errors was not possible unless using a timeOut. Not a huge fan of timeouts, I looked deeper and found that the validator contains an errorMap property which shows the element and its error. Once I had the elements with errors, I could simply scan up to their parents and open the collapsed div, like so:
$("form").bind("invalid-form.validate", function (form, validator) {
//expose errors in collapsed divs
for (var i in validator.errorMap) {
//console.log(i, ":", validator.errorMap[i]);
target = $("#" + i).parents(".collapse");
$(target).collapse('show');
}
});
Upvotes: 1
Reputation: 8623
I don't see any problem with your code at the moment, let's reformat it a bit:
var tabs = $('.collapse').not('.in');
console.log("tabs.length: " + tabs.length);
tabs.each(function () {
var $this = $(this),
thisErrors = $this.find('.field-validation-error'),
thisId = '#' + $this.attr('id');
console.log("current tab ID: " + thisId);
console.log("number of errors: " + thisErrors.length);
if (thisErrors.length) {
$(thisId).collapse('show');
}
});
Or working fiddle: http://jsfiddle.net/Rq8y7/
Does it work now? And what's the debug message in console after you run above code?
Upvotes: 2