an ASP.NET Open Source CMS & eCommerce platform
Search:
Skip Navigation LinksHome > DotShoppingCart Blog > Customization > Customize Category List Block
Customize Category List Block
Default Category List Block The default implementation of category list block is giving your store shopper the smart product navigation. When shopper selects a category, the category opens up its sub categories and usefully links like narrow by price ranges or narrow by manufacturers etc. The remaining top level categories move to the bottom.

In this article I show you one way of customizing your own category list block. One of our customers wanted to show the top level categories initially. When shopper clicks one top level category, its sub categories expand. Click the same category again to collapse the sub categories. Here is the code archiving this.

You can download the full code for V3 and code fro V2.

Change Store/Blocks/CategoryList.ascx:

<asp:Panel id="pnlBlockContent" runat="server">

    <asp:Repeater id="rptCategories" runat="server">

        <ItemTemplate>

            <div class="browsebox">

                <dsc:CategoryRow runat="server" category='<%# Container.DataItem %>' showproductcount='<%# categoryListData.ShowProductCount %>'

                    imagewidth='<%# categoryListData.ImageWidth %>' imageheight='<%# categoryListData.ImageHeight %>' oncategorylinkclick="return ToogleSubCategories(this);" />

                <asp:Repeater id="rptSubCategories" runat="server" datasource='<%# Eval("SubCategories") %>' visible='<%# (int)Eval("ShowLevels") > 1 %>' >

                    <ItemTemplate>

                        <div class="subcategory" style='<%# (null != current) && (((Category)Container.DataItem).CategoryId == current.CategoryId) ? "" : "display:none;" %>'>

                            <dsc:CategoryRow runat="server" category='<%# Container.DataItem %>' showproductcount='<%# categoryListData.ShowProductCount %>'

                                imagewidth='<%# categoryListData.ImageWidth %>' imageheight='<%# categoryListData.ImageHeight %>' />

                        </div>  

                    </ItemTemplate>

                </asp:Repeater>

            </div>

        </ItemTemplate>

    </asp:Repeater>

</asp:Panel>

<script language="javascript" type="text/javascript">

    function ToogleSubCategories(link) {

        var subDivs = link.parentNode.getElementsByTagName('div');

        for (var i = 0; i < subDivs.length; i++) {

            var div = subDivs[i];

            var display = div.style.display == "none" ? "" : "none";

            div.style.display = display;

        }

 

        return false;

    }

</script>

Change Store/Blocks/CategoryList.ascx.cs and remove unneccessary code:

    protected Category current = null;

 

    protected void Page_Load(object sender, EventArgs e) {

        EnableViewState = WebUtils.IsPageEditorEnable();

        editor.BlockUserControl = this;

 

        if (null != Data) {

            categoryListData = Utils.FromXml<CategoryListData>(Data.ToString());

        }

 

        if ((null != HeaderData) && HeaderData.Enabled)

            pnlBlockContent.CssClass = "blockContent";

        if (ShowEditor) {

            pnlBlockContent.CssClass += " BlockEditPanel";

            editor.BlockTitle = string.Format("Category List {0}", BlockId);

            chkShowProductCount.Checked = categoryListData.ShowProductCount;

            ntbImageWidth.Value = categoryListData.ImageWidth;

            ntbImageHeight.Value = categoryListData.ImageHeight;

            vdsEdit.ValidationGroup = editor.ValidationGroup = ntbImageWidth.ValidationGroup = ntbImageHeight.ValidationGroup = this.ClientID;

        }

 

        Category[] categories;

        string requestPath = Utils.GetParameter("p", null);

        bool isCategoryPage = (!string.IsNullOrEmpty(requestPath)) &&

            (requestPath.Equals("Store/Category", StringComparison.OrdinalIgnoreCase) || requestPath.Equals("Category", StringComparison.OrdinalIgnoreCase));

 

        string categoryPath = isCategoryPage ? Utils.GetParameter("n", null) : null;

        categories = Category.GetCategories(0, 2);

        if (!string.IsNullOrEmpty(categoryPath)) {

            current = Category.GetCategoryByCategoryPath(categoryPath);

            if (null == current)

                Response.Redirect(SiteNavigation.Error404Page);

        }

        rptCategories.DataSource = categories;

        rptCategories.DataBind();

    }

Change Store/Blocks/CategoryRow.ascx:

<a id="lnkCategory" runat="server" class="bar" href='<%# SiteNavigation.GetRewriterUrl("Category", Category.ParentFullPath.ToString(), Category.Name.ToString()) %>'>

    <span><%# Category.Name %><span id="Span1" runat="server" class="ProductCount"

        visible='<%# ShowProductCount %>' >(<%# Category.Count %>)</span>

        <img id="Img1" runat="server" alt='<%# Category.Name %>' align="middle"

            src='<%# FileController.GetImageUrl((int?)Category.ImageId, ImageWidth, ImageHeight) %>' visible='<%# ShowImage && (null != Category.ImageId) %>' />

    </span>

</a>

Create the following property to Store/Blocks/CategoryRow.ascx.cx:

     public string OnCategoryLinkClick {

        set { lnkCategory.Attributes["onclick"] = value; }

    }

You can download the full code for V3 and code fro V2.

Thank you Luke. This is very helpful. Now what if we wanted to navigate to the top level category, as well as open the menu of subcategories, when we click on the top level category item. For example, clicking on Blackberry would immediately navigate to the top level Blackberry page but would also open the Blackberry subcategory page. Would this just be an additional step in the ToggleSubCategories function?
 
Linden
The default implementation does exact that. The only difference is that the clicked category bubbles up to the top. You could easily change the code to make it stay at the original position.
Well, not exactly. The default implementation does not collapse and expand the subcategories. I really like the implementation you demonstrated in this article. I would just like to navigate to the selected parent category as well as expand the subcategories. I could be wrong but I think it could be done by adding just one line to the end of the ToggleSubCategories function but I'm not sure where to get the correct path to navigate to.
Ok, I get what you want. You can add page redirect to ToggleSubCategories. But when page reloads you need to keep the selected category open. You could use RegisterStartupScript to throw a ToggleSubCategories call against the current category when page loads. To get the correct category page check CategoryRow.ascx.
 
I decided to take a slightly different approach. Now when I mouse over a main category the subcategories are expanded. Clicking on the category navigates to the category page. The mouse-over script closes all other subcategory listings so that only one category is showing its subcategories at once. This still does not address the issue of all category lists being closed when the page reloads but I'm happy with the results for now. Here's what I changed from the code above.
 
In Store/Blocks/CategoryRow.ascx.cs add property
 
    public string OnCategoryLinkMouseOver
    {
        set { lnkCategory.Attributes["onmouseover"] = value; }
    }
Replace the script block in Store/Blocks/CategoryList.ascx with
 
<script language="javascript" type="text/javascript">
    function DisplaySubCategories(link) {
        var catDivs = link.parentNode.parentNode.getElementsByTagName('div');
        for (var i = 0; i < catDivs.length; i++)
        {
            var catDiv = catDivs[i];
            var subDivs = catDiv.getElementsByTagName('div');
            for (var j = 0; j < subDivs.length; j++)
            {
                var div = subDivs[j];
                div.style.display = "none";
            }
        }
        var subDivs = link.parentNode.getElementsByTagName('div');
        for (var i = 0; i < subDivs.length; i++)
        {
            var div = subDivs[i];
            div.style.display = "";
        }
        return false;
    }
   
    function NavigateCategory(link)
    {
        window.navigate(link);
        return false;
    }
</script>
 
And modify the CategoryRow control in Store/Blocks/CategoryList.ascx as follows
 
<dsc:CategoryRow runat="server" category='<%# Container.DataItem %>'
  showproductcount='<%# categoryListData.ShowProductCount %>'
  imagewidth='<%# categoryListData.ImageWidth %>' imageheight='<%# categoryListData.ImageHeight %>'
  oncategorylinkclick="return NavigateCategory(this);"
  oncategorylinkmouseover="return DisplaySubCategories(this);" />
 
 
good job
good job
OK
OK
I copied the code and it does not worked the way. When we expand a category and press on a sub category which has the priduct then it does not work. it seems it works for a two level cat-product not more than 2 levels.
 
P.S. I just copied the files in the zip folder.
 
3 ,4,5 or more category
what should i do
Recent Comments
danny jones said ...
Hi... I am inexperiance to build up ECommenrce type sites.I have a little bits knowladge ...
molakaj said ...
What a great approach to the subject, I was looking for. Thanks for these tips http://www ...
jane said ...
Thank you for this useful information.
furnace parts said ...
Congrats on V4.0.....It is so easy to use  
Travis said ...
I just bought DSC Suite V4.5 and it is more solid then ever. I hope I am #1 buyer of this ...