Edit: jqueryval is the culprit (unobtrusive huh?). Not sure why it's affecting anything, as we disabled it on the checkboxes in the settings. However, commenting the reference makes the loadtime unnoticable. I've tried several fixes with no luck.
This is the function that causes the slowdown, line 532 in jquery.validate.js
elements: function() {
*snip*
return $( this.currentForm )
.find( "input, select, textarea" )
.not( ":submit, :reset, :image, [disabled], [readonly]" )
.not( this.settings.ignore ) //performance murderer
*snip*
},
*Note - I snipped the filter function that comes after this, because in testing I didn't use it and still got the slowdown, so it's not really relevant.
I am also removing the checkboxes from validation:
$.validator.setDefaults({
ignore: ":hidden, input[type=checkbox]" //do not validate checkboxes
});
I have an mvc app that is going to be posting around 2000+ checkboxes back to the server. This is normally not a problem, interactions with the site via jquery selectors run perfectly fine, and load times are fast. However, submit causes some kind of reflow issue where every single textbox and their labels offsetHeight and offsetWidth get checked. This compounds to an over 5 second load time on creating and saving edits.
Start...
End...
(I'm pretty sure it just gave up at the end there, but there's like 2000 more events you can scroll it for minutes)
The initial load is going to hurt but as the users use the site more, many of these checkboxes will become "disabled" which I understand to mean that they will no longer post back. Unfortunately, disabling these textboxes is not causing the number of elements to post back to drop. I have a feeling this is MVC related, but here's the code:
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<fieldset>
<legend><input type="submit" value="Create"/> | @Html.ActionLink("Back to List", "Index", "CatManager")</legend>
@if (Model.CategoryViewModel.ChildCategoryNodes.Any())
{
for (int i = 0; i < Model.CategoryViewModel.ChildCategoryNodes.Count(); i++)
{
@Html.HiddenFor(model => model.CategoryViewModel.ChildCategoryNodes[i].Id)
@Html.HiddenFor(model => model.CategoryViewModel.ChildCategoryNodes[i].Description)
<label @(Model.CategoryViewModel.ChildCategoryNodes[i].CategoryId != null ? "disabled" : "")>
@if (!Model.CategoryViewModel.ChildCategoryNodes[i].AlreadyTaken)
{
@Html.CheckBoxFor(model => model.CategoryViewModel.ChildCategoryNodes[i].Selected, new Dictionary<string, object> {{"data-id", Model.CategoryViewModel.ChildCategoryNodes[i].Id}, {"data-description", Model.CategoryViewModel.ChildCategoryNodes[i].Description}})
}
else
{
@Html.CheckBoxFor(model => model.CategoryViewModel.ChildCategoryNodes[i].Selected, new Dictionary<string, object>{{"data-id", Model.CategoryViewModel.ChildCategoryNodes[i].Id}, {"data-description", Model.CategoryViewModel.ChildCategoryNodes[i].Description}, {"disabled","disabled"}})
}
@Model.CategoryViewModel.ChildCategoryNodes[i].Id - @Model.CategoryViewModel.ChildCategoryNodes[i].Description
</label>
}
}
</fieldset>
}
Anyone have any idea how to reduce the amount of junk that's being posted back, or how to avoid this mega-slow offset reflow?
Edit: As usual, I'm getting harassed by people who think they know what's going on here but they clearly don't, so here's some example code that runs in less than a second that's operating on my dom every time a character is typed into a textbox.
$("#filter").on("keyup", function() {
ValidateTextBoxes();
});
function ValidateTextBoxes() {
$("input[type=checkbox]").each(function() {
var val = $("#filter").val();
var id = $(this).data("id");
var description = $(this).data("description");
if (val != null && id != null && description != null) {
if (id.toString().indexOf(val.toString()) > -1 || description.toString().toLowerCase().indexOf(val.toString().toLowerCase()) > -1){
$(this).parent().show();
} else {
$(this).parent().hide();
}
}
});
}
So THANKS, no more comments about the number of elements PLEASE.