I am attempting to write a basic HTML unordered list from hierarchical data. Here's what the data looks like:
public class Task
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string Title { get; set; }
public Collection<Task> Tasks = new Collection<Task>( );
}
List<Task> tasks = new List<Task>( );
tasks.Add( new Task { Id = 1, ParentId = null, Title = "Top task" } );
tasks.Add( new Task { Id = 2, ParentId = 1, Title = "Subtask 1" } );
tasks.Add( new Task { Id = 3, ParentId = 2, Title = "Subtask 2" } );
tasks.Add( new Task { Id = 4, ParentId = 1, Title = "Subtask 3" } );
tasks.Add( new Task { Id = 5, ParentId = 4, Title = "Subtask 4" } );
Here's what I seek to create from the above data:
<ul>
<li>Top task
<ul>
<li>Subtask 1
<ul>
<li>Subtask 2</li>
</ul>
</li>
</ul>
<ul>
<li>Subtask 3
<ul>
<li>Subtask 4</li>
</ul>
</li>
</ul>
</li>
</ul>
I have tried the following posts with some success:
Return unordered list from hierarchical sql data and C# Create HTML unordered list from List using Recursion
Here is the code I have adapted from the first link above, and it mostly works, but if the order of the hierarchical data is changed, the method chokes on the first item that is not a child of the previous parent. For example, if I change the order of the data list as follows, it will skip Subtask 1 and 2:
tasks.Add( new Task { Id = 2, ParentId = 1, Title = "Subtask 1" } );
tasks.Add( new Task { Id = 1, ParentId = null, Title = "Top task" } );
tasks.Add( new Task { Id = 3, ParentId = 2, Title = "Subtask 2" } );
tasks.Add( new Task { Id = 4, ParentId = 1, Title = "Subtask 3" } );
tasks.Add( new Task { Id = 5, ParentId = 4, Title = "Subtask 4" } );
public class Task
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string Title { get; set; }
public Collection<Task> Tasks = new Collection<Task>( );
public Task FindTask( int id )
{
return FindTask( this, id );
}
private Task FindTask( Task task, int id )
{
if( task.Id == id )
{
return task;
}
Task returnTask = null;
foreach( Task child in task.Tasks )
{
returnTask = child.FindTask( id );
if( returnTask != null )
{
break;
}
}
return returnTask;
}
}
List<Task> topTasks = new List<Task>( );
protected void GetHierarchy( int id )
{
List<Task> data = new List<Task>( );
data.Add( new Task { Id = 1, ParentId = null, Title = "Top task" } );
data.Add( new Task { Id = 2, ParentId = 1, Title = "Subtask 1" } );
data.Add( new Task { Id = 3, ParentId = 2, Title = "Subtask 2" } );
data.Add( new Task { Id = 4, ParentId = 1, Title = "Subtask 3" } );
data.Add( new Task { Id = 5, ParentId = 4, Title = "Subtask 4" } );
foreach( var row in data )
{
Task tasks = new Task( );
tasks.Title = row.Title;
tasks.Id = row.Id;
if( row.ParentId == null )
{
topTasks.Add( tasks );
}
else
{
int parentId = row.ParentId.Value;
foreach( Task topTask in topTasks )
{
Task parentTask = topTask.FindTask( parentId );
if( parentTask != null )
{
parentTask.Tasks.Add( tasks );
break;
}
}
}
}
}
protected string Render( )
{
var s = new StringBuilder( );
GetHierarchy( id );
s.Append( "<ul>" );
foreach( Task child in topTasks )
{
RenderTask( s, child );
}
s.Append( "</ul>" );
return s.ToString( );
}
private void RenderTask( StringBuilder s, Task task )
{
s.Append( "<li>" );
s.Append( task.Title );
if( task.Tasks.Count > 0 )
{
s.Append( "<ul>" );
foreach( Task child in task.Tasks )
{
RenderTask( s, child );
}
s.Append( "</ul>" );
}
s.Append( "</li>" );
}
I do not want to use jquery treeview or any other component as this needs to be an independent solution.
Can anyone advise me of a better approach or at the very least help me fix the code that I have implemented above so that the order of the data does not break the recursion?
Thanks in advance.
In the end, I adapted the answer from C# Create HTML unordered list from List using Recursion, which works well. Here is the code I have used:
protected string WriteList( )
{
var s = new StringBuilder( );
List<Task> tasks = new List<Task>( );
tasks.Add( new Task { Id = 2, ParentId = 1, Title = "Subtask 1" } );
tasks.Add( new Task { Id = 1, ParentId = null, Title = "Top task" } );
tasks.Add( new Task { Id = 3, ParentId = 2, Title = "Subtask 2" } );
tasks.Add( new Task { Id = 4, ParentId = 1, Title = "Subtask 3" } );
tasks.Add( new Task { Id = 5, ParentId = 4, Title = "Subtask 4" } );
s.Append( "<ul>" );
foreach( var task in tasks )
{
if( task.ParentId == null )
{
WriteTaskList( tasks, task, s );
}
}
s.Append( "</ul>" );
return s.ToString( );
}
private static void WriteTaskList( List<Task> tasks, Task task, StringBuilder s )
{
s.Append( "<li>" + task.Title );
var subtasks = tasks.Where( p => p.ParentId == task.Id );
if( subtasks.Count( ) > 0 )
{
s.Append( "<ul>" );
foreach( Task p in subtasks )
{
if( tasks.Count( x => x.ParentId == p.Id ) > 0 )
WriteTaskList( tasks, p, s );
else
s.Append( string.Format( "<li>{0}</li>", p.Title ) );
}
s.Append( "</ul>" );
}
s.Append( "</li>" );
}