1

I am currently using this http://blogs.sitepoint.com/hierarchical-data-database-2/ method of storing my data.

My current database rows look like this:

Name | nodeLeft | nodeRight | nodeLevel

Home | 1 | 6 | 1

ContentA | 2 | 5 | 2

ContentB | 3 | 4 | 2

About | 7 | 8 | 1

Now I am using a ASP.NET Repeater to output the data using lists and jsTree:

<asp:Repeater ID="rptContentSectionGetAll" runat="server">
        <HeaderTemplate>
            <div id="contentSectionTree">
                <ul>
                    <li id="contentSectionTreeRoot" rel="root"><a href="#">Root</a>
                        <ul>
        </HeaderTemplate>
        <ItemTemplate>
                            <li id='<%# Eval("ID") %>'>
                                <a href="#"><%# Eval("name") %></a>
                            </li>

        </ItemTemplate>
        <FooterTemplate>
                        </ul>
                    </li>
                </ul>
            </div>
        </FooterTemplate>
 </asp:Repeater>

I need to replace what's in the ItemTemplate with all <li>'s and nested <ul>'s from the code behind.

This is my current code behind:

private DataTable RepeaterDataSource()
    {
        ContentSectionBAL cBAL = new ContentSectionBAL(); 
        DataTable dTable = new DataTable();
        try
        {
            dTable = cBAL.Load();

            int counter = 1;
            var htmlList = "";
            for (int i = 0; i < dTable.Rows.Count; i++)
            {
                htmlList = "<li rel='folder' id='" + dTable.Rows[i]["ID"] + "'>";
                htmlList += "<a href='#'>" + dTable.Rows[i]["name"] + "</a>";

                if (Convert.ToInt32(dTable.Rows[i]["nodeLevel"]) > counter)
                {
                    htmlList = "<ul>";
                    for (int j = 0; j < dTable.Rows.Count; j++)
                    {
                        if (Convert.ToInt32(dTable.Rows[i]["nodeLevel"]) > counter + 1)
                        {
                            htmlList += "<li rel='file' id='" + dTable.Rows[j]["ID"] + "'>";
                            htmlList += "<a href='#'>" + dTable.Rows[j]["name"] + "</a>";
                            htmlList += "</li>";
                        }
                    }
                    htmlList += "</ul>";
                }

                htmlList += "</li>";
                counter = counter + 1;
            }
        }
        catch (Exception ee)
        {
            Session["message"] = ee.Message.ToString();
            Session["messageType"] = "error";
        }

        return dTable;
    }

Shortly after this function I bind it by doing:

private void BindRepeater()
    {
        rptContentSectionGetAll.DataSource = RepeaterDataSource();
        rptContentSectionGetAll.DataBind();
    }

All regular nodes with NO children outputs: <li>name</li> All nodes WITH children needs to output all of it's children in some sort of loop: <li><ul><li></li></ul><li>

Questions I have: 1. What is the proper way to loop through this type of data for proper output? 2. How do I successfully output it in a repeater? [ANSWER]

I know what I have won't work but my brain started frying thinking about it all. Any help would be greatly appreciated.

If you require anything else let me know but this should be it.

Come on guys I need help with the conditionals or math to grab what i want in the correct order.

balexander
  • 23,131
  • 14
  • 45
  • 68

3 Answers3

1

Us the OnItemDataBound event to render your code. Replace the contents of your Item template with

<ItemTemplate>       
    <asp:Literal ID="Literal1" runat="server"></asp:Literal>
</ItemTemplate> 

Then in your ItemDataBound Event handler build the structure you want as a string and assign it to the literal Text property.

((Literal)e.Item.FindControl("Literal1")).Text = MyNewStructureString;
Chad
  • 1,512
  • 1
  • 16
  • 40
1

You could use a nested repeater and avoid writing all the code to output the inner ul. You can declaratively set the datasource of a repeater inside a repeater as long as the list you need is a property of the data item object of the outer repeater.

If this is not possible because the objects are not constructed in this way you can still use the nested repeater approach, just you will have to bind each inner repeater in the ItemDataBound event.

Chris Mullins
  • 6,677
  • 2
  • 31
  • 40
  • Would it work if I had infinite amount of levels able to be generated? – balexander Apr 20 '11 at 16:36
  • 1
    I don't think it would work very well. Probably you would be better off just creating some sort of recursive function to generate the lists and dump them out into a literal control and just skip the repeater all together. – Chris Mullins Apr 20 '11 at 17:26
  • Skip the repeater all together...Not a bad idea. I'll see what I can work with. Thanks for your advice. I can't mark this correct though as it would only work for two nodeLevels. – balexander Apr 20 '11 at 18:26
  • 1
    It will not work for only two level nodes... you can nest as many repeaters inside eachother as you wish, each child repeater would refer to parent's dataitem to get it's property for the child datasource's parameter. It would just be slow. – Dimitri Apr 22 '11 at 01:43
  • Yes but you would have to know how many levels there were before hand I think unless you added them programmatically. – Chris Mullins Apr 22 '11 at 11:36
0

The answer is a combination of Chad and Chris's answers. I ended up dumping the repeater all together and used a series of conditionals and loops in a function to save html in a StringBuilder() and output into a Literal.

Thanks guys.

balexander
  • 23,131
  • 14
  • 45
  • 68