PDA

View Full Version : [CLOSED] Very slow response for Checkboxgroup Script



jwf
Mar 28, 2013, 8:52 PM
I am currently trying to replicate a pattern we used extensively in the 1.0 release in the 2.0 version.

We want a top level checkbox that filters a checkbox group.

In the 1.0 version, I tied my listener to the checkbox's checked event, in 2.0 I've changed it to use the change event. Other than that the approach is the same, but in 1.0 this script ran near instantly, and in 2.0 I'm seeing a good 5-6 second delay. I can't understand what's causing it. Any help or advise in implementing this behavior would be most welcome.

Below is a simple example which can be used to reproduce the issue.


<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Topics.aspx.cs" Inherits="LW4.OnlineLibrary.Admin.Web.Topics" %>
<%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>
<!DOCTYPE html>


<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Checkboxgroup Show/Hide Test</title>
<ext:ResourcePlaceHolder runat="server" ID="ResourcePlaceHolder1" />
<style type="text/css">
.hideInput input
{
display: none;
}
</style>
<script type="text/javascript">
function filterRelations(field, newValue, oldValue, eOpts) {
var count = 0;
var noSelection;
var group = Ext.getCmp("cbgTopicRelations");


for (i = 0; i < group.items.items.length; i++) {


if (group.items.items[i].id == "topicRelation_0") {
noSelection = group.items.items[i];
}
else {
if (newValue == false) {
group.items.items[i].show();
}
else {
if (!group.items.items[i].checked) {
group.items.items[i].hide();
}
else {
group.items.items[i].show();
count++;
}
}
}
}


if (count == 0 && newValue == true)
noSelection.show();
else
noSelection.hide();
}
</script>
<script runat="server">
public class Topic
{
public int TopicID { get; set; }
public string Title { get; set; }
}

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
var topics = new List<Topic>();
topics.Add(new Topic() { Title = "Topic One", TopicID = 1 });
topics.Add(new Topic() { Title = "Topic Two", TopicID = 2 });
topics.Add(new Topic() { Title = "Topic Three", TopicID = 3 });
topics.Add(new Topic() { Title = "Topic Four", TopicID = 4 });
topics.Add(new Topic() { Title = "Topic Five", TopicID = 5 });
topics.Add(new Topic() { Title = "Topic Six", TopicID = 6 });
topics.Add(new Topic() { Title = "Topic Seven", TopicID = 7 });
topics.Add(new Topic() { Title = "Topic Eight", TopicID = 8 });
topics.Add(new Topic() { Title = "Topic Nine", TopicID = 9 });
topics.Add(new Topic() { Title = "Topic Ten", TopicID = 10 });
topics.Add(new Topic() { Title = "Topic Eleven", TopicID = 11 });
topics.Add(new Topic() { Title = "Topic Twelve", TopicID = 12 });
topics.Add(new Topic() { Title = "Topic Thirteen", TopicID = 13 });
topics.Add(new Topic() { Title = "Topic Fourteen", TopicID = 14 });
topics.Add(new Topic() { Title = "Topic Fifteen", TopicID = 15 });
topics.Add(new Topic() { Title = "Topic Sixteen", TopicID = 16 });
topics.Add(new Topic() { Title = "Topic Seventeen", TopicID = 17 });
topics.Add(new Topic() { Title = "Topic Eighteen", TopicID = 18 });
topics.Add(new Topic() { Title = "Topic Nineteen", TopicID = 19 });
topics.Add(new Topic() { Title = "Topic Twenty", TopicID = 20 });
topics.Add(new Topic() { Title = "Topic Twenty One", TopicID = 21 });
topics.Add(new Topic() { Title = "Topic Twenty Two", TopicID = 22 });
topics.Add(new Topic() { Title = "Topic Twenty Three", TopicID = 23 });
topics.Add(new Topic() { Title = "Topic Twenty Four", TopicID = 24 });
topics.Add(new Topic() { Title = "Topic Twenty Five", TopicID = 25 });


#region No Selection Checkbox
Checkbox noSelection = new Checkbox();
noSelection.ID = "topicRelation_0";
noSelection.ClientIDMode = System.Web.UI.ClientIDMode.Static;
noSelection.BoxLabel = "No Relations Selected";
noSelection.Cls = "hideInput";
cbgTopicRelations.Items.Add(noSelection);
#endregion


foreach (Topic topic in topics)
{
Checkbox cb = new Checkbox();
cb.ID = string.Format("topicRelation_{0}", topic.TopicID);
cb.ClientIDMode = System.Web.UI.ClientIDMode.Static;
cb.BoxLabel = topic.Title;
cbgTopicRelations.Items.Add(cb);
}
}
}
</script>
</head>
<body>
<form id="form1" runat="server">
<ext:ResourceManager runat="server" ID="ResourceManager1" Theme="Gray">
</ext:ResourceManager>


<asp:ScriptManager runat="server" ID="ScriptManager1">
<Scripts>
<asp:ScriptReference Path="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" />
</Scripts>
</asp:ScriptManager>


<ext:Window runat="server" ID="window1" Title="Test" Height="400" Width="450">
<Items>
<ext:Panel runat="server" ID="panelRelations" Title="Relations" Frame="false" Border="false" Padding="0" AutoScroll="true">
<TopBar>
<ext:Toolbar ID="Toolbar2" runat="server">
<Items>
<ext:Checkbox runat="server" ID="cbFilterCheckedRelations" BoxLabel="Show Selected Relations Only <i>(Uncheck to see all available options)</i>" StyleSpec="margin-left: 10px; margin-top: 6px" Checked="true">
<Listeners>
<Change Fn="filterRelations" />
</Listeners>
</ext:Checkbox>
</Items>
</ext:Toolbar>
</TopBar>
<Items>
<ext:Panel runat="server" ID="panelRelationChecks" ClientIDMode="Static" Border="false" Padding="15" Layout="FitLayout">
<Items>
<ext:CheckboxGroup runat="server" ID="cbgTopicRelations" ClientIDMode="Static" StyleSpec="margin-left: 10px; border-style: none;" ColumnsNumber="2" Vertical="true" Padding="5">
</ext:CheckboxGroup>
</Items>
</ext:Panel>
</Items>
<Listeners>
<AfterRender Handler="filterRelations(null, #{cbFilterCheckedRelations}.checked, null, null);" />
</Listeners>
</ext:Panel>
</Items>
</ext:Window>
</form>
</body>
</html>

jwf
Mar 28, 2013, 9:50 PM
I was able to resolve my performance issues by switching to jquery - I will include the solution below.

However, I would still appreciate an explanation of what is going on with my original script - are calls to .show()/.hide() so expensive?


function filterRelations(field, newValue, oldValue, eOpts) {
var count = 0;
var noSelection;


$("#cbgTopicRelations .x-checkboxgroup-form-item").each(function (index, element) {
if (this.id == "topicRelation_0")
noSelection = this;
else {
var cb = $(this).find(".x-form-checkbox");
if (newValue == false) {
$(this).css("display", "block");
}
else {
if (Ext.getCmp(this.id).checked) {
$(this).css("display", "block");
count++;
}
else {
$(this).css("display", "none");
}
}
}
});


if (count == 0 && newValue == true)
$(noSelection).css("display", "block");
else
$(noSelection).css("display", "none");
}

geoffrey.mcgill
Mar 28, 2013, 9:58 PM
Thanks for the great sample demonstrating how to reproduce. We are investigating.

Are you using Ext.NET 2.1 or the latest from SVN?

jwf
Mar 28, 2013, 10:13 PM
I am using 2.1 via nuget.

Also my jquery solution was not as clever as I thought, as it seems to break subsequent displays of the group. So I still need some help solving this :)

jwf
Mar 28, 2013, 11:27 PM
I think I have found a true solution, after reading this page: http://www.sencha.com/forum/showthread.php?153565-ExtJS-Performance-Best-Practices/page2

I think what is happening is that after each show/hide, the container (checkboxgroup) is recalculating its layout. Following the advice in the thread, I modified my function to suspend layout before modifying the display state of the individual checkboxen:


function filterRelations(field, newValue, oldValue, eOpts) {
var count = 0;
var noSelection;
var group = Ext.getCmp("cbgTopicRelations");
var topicID = "topicRelation_" + Ext.getCmp("gridTopics").getSelectionModel().getSelection()[0].data.TopicID;


group.suspendLayout = true;


for (i = 0; i < group.items.items.length; i++) {


if (group.items.items[i].id == "topicRelation_0") {
noSelection = group.items.items[i];
}
else if (group.items.items[i].id == topicID) {
// prevent self-tagging
group.items.items[i].hide();
}
else {
if (newValue == false) {
group.items.items[i].show();
}
else {
if (!group.items.items[i].checked) {
group.items.items[i].hide();
}
else {
group.items.items[i].show();
count++;
}
}
}
}

if (count == 0 && newValue == true)
noSelection.show();
else
noSelection.hide();

group.suspendLayout = false;
group.doLayout();
}

I need to do some more testing, but hopefully you can confirm that this is the correct solution.

Baidaly
Mar 29, 2013, 3:49 AM
Hello!

Yes, usually suspending layout helps. This performance issue happens due to more complex layout mechanism in Ext JS which is more convenient but still has some performance issues.

Please, keep us updated!

Daniil
Mar 29, 2013, 4:38 AM
Hello,

I think suspending layout is a single way to sort it out. And, generally, it is an "official" way. They wrote about it in the performance guide as well.
http://docs.sencha.com/ext-js/4-2/#!/guide/performance

jwf
Mar 29, 2013, 7:58 PM
Thanks for responses.

For now, suspending the events is acceptable. You can close this thread or leave it open if you wish to pursue performance enhancements for this type of strategy.