Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I hide empty nested repeaters?

In an asp.net page, I have nested repeaters to show up to four levels of my sitemap.

The question: How can I tell the nested repeaters not to show a node if the node has no children? More specifically, when a nested repeater has no children, it renders as a pair of <ul></ul> tags -- that's what I need to hide from the rendered list.

What works: The HTML and script presented here renders the web.sitemap correctly as a clean unordered list, only with empty UL tags where a node has no children.

What I have tried (unsuccesfully) so far:

  • I have looked into jQuery. Although I found the correct jQuery command to remove empty <ul> pairs, the webresource makes absolutely sure to overwrite jQuery commands. (Which also makes it impossible for me to use jQuery to remove classes that litter a rendered asp:menu). In other words, I have not yet found a way for jQuery to clean up something produced by an asp.net control.
  • I found forum posts, but they all seem to have repeated the same two-level depth repeater without any removal of childless nodes.
  • I double-checked my web.sitemap file and made sure I had nothing in the source that would contribute to this. No issues there at the source.

Looking around, I found a very promising post here: Hide child and parent repeater when child repeater is empty. Adapting it to VB.NET and adding a null detection if-then statement, I have:

Protected Sub HideIfEmpty(sender As Object, e As RepeaterItemEventArgs) Handles Repeater0.ItemDataBound
    If e.Item.ItemType = ListItemType.Item Then
        If e.Item.FindControl("Repeater4") IsNot Nothing Then

            If (DirectCast(e.Item.FindControl("Repeater3"), Repeater).Items.Count = 0) Then
                e.Item.Visible = False
            End If

        End If

    End If
End Sub

Based on a comment, I also tried a PreRender sub. It presented a sitemap list with the same empty UL tags. Use of breakpoints did not identify why it was not working as desired.

This is the aspx code:

<asp:SiteMapDataSource ID="siteMapDataSource1" runat="server" ShowStartingNode="false" />
<asp:Repeater runat="server" ID="Repeater0" DataSourceID="SiteMapDataSource1">
    <HeaderTemplate>
        <ul>
            <li>
                <asp:HyperLink ID="HyperLink4" runat="server" NavigateUrl="~/index.aspx">Homepage</asp:HyperLink>
            </li>
    </HeaderTemplate>
    <ItemTemplate>
        <li>
            <asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl='<%# Eval("Url") %>'><%# Eval("Title") %></asp:HyperLink>
            <asp:Repeater ID="Repeater1" runat="server" DataSource='<%# DirectCast(Container.DataItem, SiteMapNode).ChildNodes%>'>
                <HeaderTemplate>
                    <ul>
                </HeaderTemplate>
                <ItemTemplate>
                    <li>
                        <asp:HyperLink ID="HyperLink2" runat="server" NavigateUrl='<%# Eval("Url") %>'><%# Eval("Title") %></asp:HyperLink>
                        <asp:Repeater ID="Repeater2" runat="server" DataSource='<%# DirectCast(Container.DataItem, SiteMapNode).ChildNodes%>'>
                            <HeaderTemplate>
                                <ul>
                            </HeaderTemplate>
                            <ItemTemplate>
                                <li>
                                    <asp:HyperLink ID="HyperLink3" runat="server" NavigateUrl='<%# Eval("Url") %>'><%# Eval("Title") %></asp:HyperLink>
                                    <asp:Repeater ID="Repeater3" runat="server" DataSource='<%# DirectCast(Container.DataItem, SiteMapNode).ChildNodes%>' OnPreRender="HideIfEmpty">
                                        <HeaderTemplate>
                                            <ul>
                                        </HeaderTemplate>
                                        <ItemTemplate>
                                            <li>
                                                <asp:HyperLink ID="HyperLink3" runat="server" NavigateUrl='<%# Eval("Url") %>'><%# Eval("Title") %></asp:HyperLink>
                                            </li>
                                        </ItemTemplate>
                                        <FooterTemplate>
                                            </ul>
                                        </FooterTemplate>
                                    </asp:Repeater>
                                </li>
                            </ItemTemplate>
                            <FooterTemplate>
                                </ul>
                            </FooterTemplate>
                        </asp:Repeater>
                    </li>
                </ItemTemplate>
                <FooterTemplate>
                    </ul>
                </FooterTemplate>
            </asp:Repeater>
        </li>
    </ItemTemplate>
    <FooterTemplate></ul></FooterTemplate>
</asp:Repeater>

This is the rendered HTML:

<ul id="menu_Main" class="sm sm-blue">
<li>
    <a id="Repeater0_HyperLink4" href="index.aspx">Homepage</a>
</li>

<li>
    <a id="Repeater0_HyperLink1_0">Data Manager Documents</a>

    <ul>

        <li>
            <a id="Repeater0_Repeater1_0_HyperLink2_0" href="/Data_Manager/Skill_Journal.aspx">Skill Journal</a>

            <ul>
            </ul>

        </li>

        <li>
            <a id="Repeater0_Repeater1_0_HyperLink2_1">Test Pages</a>

            <ul>

                <li>
                    <a id="Repeater0_Repeater1_0_Repeater2_1_HyperLink3_0" href="/Data_Manager/xslt_test.aspx">XSLT Test</a>

                    <ul>
                    </ul>

                </li>

            </ul>

        </li>

    </ul>

</li>

<li>
    <a id="Repeater0_HyperLink1_1">Incident Report</a>

    <ul>

        <li>
            <a id="Repeater0_Repeater1_1_HyperLink2_0" href="http://wales:4885/IncidentReport/IncidentReport.aspx">Add/Edit/View</a>

            <ul>
            </ul>

        </li>

        <li>
            <a id="Repeater0_Repeater1_1_HyperLink2_1" href="http://wales:4885/IncidentReport/V1_History.aspx">Archive</a>

            <ul>
            </ul>

        </li>

    </ul>

</li>

<li>
    <a id="Repeater0_HyperLink1_2" href="/Ordering_Database/Ordering_Database.aspx">Ordering Database</a>

    <ul>

        <li>
            <a id="Repeater0_Repeater1_2_HyperLink2_0" href="/Ordering_Database/Reports.aspx">Reports</a>

            <ul>
            </ul>

        </li>

        <li>
            <a id="Repeater0_Repeater1_2_HyperLink2_1" href="/Ordering_Database/Stats.aspx">Stats</a>

            <ul>
            </ul>

        </li>

        <li>
            <a id="Repeater0_Repeater1_2_HyperLink2_2" href="/Ordering_Database/View_Items.aspx">View Items</a>

            <ul>
            </ul>

        </li>

        <li>
            <a id="Repeater0_Repeater1_2_HyperLink2_3" href="/Ordering_Database/Manage_Items.aspx">Manage Items</a>

            <ul>
            </ul>

        </li>
        <li>
            <a id="Repeater0_Repeater1_2_HyperLink2_4">Utility</a>
            <ul>
            </ul>
        </li>
    </ul>
</li>    

In summary, the sitemap that is rendered into a nested unordered list is correct, but still produces empty UL tags that should be removed on the server side.


1 Answers

For this system, this is what worked for me as true server side answer.

In the script:

<script>
Private Sub Hide_The_Orphans(ByVal sender As Object, ByVal e As RepeaterItemEventArgs)
    Dim rpt As Repeater = CType(sender, Repeater)

    If rpt IsNot Nothing Then
        If rpt.Items.Count = 0 Then
            rpt.Visible = False
        Else
            rpt.Visible = True
        End If
    End If
End Sub
</script>

In the body (I also changed changed the asp:hyperlink tags to <a> tags to clean up all those hyperlink IDs in the rendered HTML):

<nav>
                <asp:SiteMapDataSource ID="siteMapDataSource1" runat="server" ShowStartingNode="false" />
                <asp:Repeater runat="server" ID="Repeater0" DataSourceID="SiteMapDataSource1">
                    <HeaderTemplate>
                        <ul id="menu_Main" class="sm sm-blue">
                            <li>
                                <a href='<%# Page.ResolveClientUrl("~/index.aspx")%>'>Homepage</a>
                            </li>
                    </HeaderTemplate>
                    <ItemTemplate>
                        <li>
                            <a href='<%# Eval("Url") %>'><%# Eval("Title") %></a>
                            <asp:Repeater ID="Repeater1" runat="server" DataSource='<%# DirectCast(Container.DataItem, SiteMapNode).ChildNodes%>' OnItemDataBound="Hide_The_Orphans">
                                <HeaderTemplate>
                                    <ul>
                                </HeaderTemplate>
                                <ItemTemplate>
                                    <li>
                                        <a href='<%# Eval("Url") %>'><%# Eval("Title") %></a>
                                        <asp:Repeater ID="Repeater2" runat="server" DataSource='<%# DirectCast(Container.DataItem, SiteMapNode).ChildNodes%>' OnItemDataBound="Hide_The_Orphans">
                                            <HeaderTemplate>
                                                <ul>
                                            </HeaderTemplate>
                                            <ItemTemplate>
                                                <li>
                                                    <a href='<%# Eval("Url") %>'><%# Eval("Title") %></a>
                                                    <asp:Repeater ID="Repeater3" runat="server" DataSource='<%# DirectCast(Container.DataItem, SiteMapNode).ChildNodes%>' OnItemDataBound="Hide_The_Orphans">
                                                        <HeaderTemplate>
                                                            <ul>
                                                        </HeaderTemplate>
                                                        <ItemTemplate>
                                                            <li>
                                                                <a href='<%# Eval("Url") %>'><%# Eval("Title") %></a>
                                                            </li>
                                                        </ItemTemplate>
                                                        <FooterTemplate>
                                                            </ul>
                                                        </FooterTemplate>
                                                    </asp:Repeater>
                                                </li>
                                            </ItemTemplate>
                                            <FooterTemplate>
                                                </ul>
                                            </FooterTemplate>
                                        </asp:Repeater>
                                    </li>
                                </ItemTemplate>
                                <FooterTemplate>
                                    </ul>
                                </FooterTemplate>
                            </asp:Repeater>
                        </li>
                    </ItemTemplate>
                    <FooterTemplate></ul></FooterTemplate>
                </asp:Repeater>
            </nav>

And to prove to myself it's a true server side solution, this is from "view source code."

                        <ul id="menu_Main" class="sm sm-blue">
                            <li>
                                <a href='index.aspx'>Homepage</a>
                            </li>

                        <li>
                            <a href=''>Data Manager Documents</a>

                                    <ul>

                                    <li>
                                        <a href='/Data_Manager/Skill_Journal.aspx'>Skill Journal</a>

                                    </li>

                                    <li>
                                        <a href=''>Test Pages</a>

                                                <ul>

                                                <li>
                                                    <a href='/Data_Manager/.aspx'>Sitemap test</a>

                                                </li>

                                                <li>
                                                    <a href='/Data_Manager/xslt_test.aspx'>XSLT Test</a>

                                                </li>

                                                </ul>

                                    </li>

                                    </ul>

                        </li>

                        etc....

The places were you see empty href tags is because those specific nodes are more like folder containers, so that's design and not bug.

Another plus for this approach is that there is only one sub that can get used by any of the repeaters, rather than having to use a chained approach as I earlier attempted.


Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!