This project is read-only.

TreeViewFor not showing child nodes

Jul 16, 2012 at 5:23 PM
Edited Jul 16, 2012 at 5:32 PM

I have a class: 

    public class OrganisationElement : Entity
    {
        public virtual string Name { get; set; }

        public virtual string Description { get; set; }

        public virtual IList<OrganisationElement> Children { get; set; }

        public virtual OrganisationElement Parent { get; set; }

        public OrganisationElement()
        {
            Children = new List<OrganisationElement>();
        }
I'm having problems getting the tree view to populate any child nodes. I have checked the validity of the entity using the Menu which displays the children:
@Html.Menu("Org",Model.OrganisationElements.Where(x=>x.Parent==null),
new{@class="navigationMenu"},
x=>x.Children,
_S.L<OrganisationElement>(h => "<span class='folder'>"+h.DisplayFor(m => m.Name).ToString()+"</span>"),null)
I cannot work out what I'm doing wrong with the TreeViewFor that it will not work:
@Html.TreeViewFor(model => model.OrganisationElements.Where(x=>x.Parent==null),
i=> "Children",
ExternalContainerType.span, 
"filetree treeview-red",
new object[]
    {
        _S.L<OrganisationElement>(h => "<span class='folder'>"+h.DisplayFor(m => m.Name).ToString()+"</span>")
    },
(x,y)=>0,
null,
null,
null,
TreeViewMode.InitializeDisplay,
(x)=>"allnodes",
(x,y) =>TreeViewItemStatus.initializeShow)
Cheers,
Rowan
Jul 16, 2012 at 5:32 PM

I thought I should also mention that the view model is using:

public IList<OrganisationElement> OrganisationElements { get; set; }

Coordinator
Jul 16, 2012 at 10:49 PM
model => model.OrganisationElements.Where(x=>x.Parent==null)

 

Is wrong! the m => m.... notation CANNOT ACCEPT METHOD CALLS(this is true for all helpers) but just property access m => m.property.subpreperty1.subproperty2 and so on ...So you have to extract x => x.Parent == null BEFORE, in the controller and put them in OrganizationElement. Then in the view you write simply mpdel => model.OrganisationElement

Jul 17, 2012 at 8:55 AM

Showing my 3 week MVC newbie-ness here ;-)

OK so I have created another list that contains only the root element

public List<OrganisationElement> RootOrganisationElements { get; set; }

This still doesn't show the children when passed to the helper.

If I try and pass a single OrganisationElement:

@Html.TreeViewFor(model => model.RootOrganisationElement,
i=> "Children",
ExternalContainerType.span, 
"filetree treeview-red",
new object[]
    {
        _S.L<OrganisationElement>(h => "<span class='folder'>"+h.DisplayFor(m => m.Name).ToString()+"</span>")
    },
(x,y)=>0,
null,
null,
null,
TreeViewMode.InitializeDisplay,
(x)=>"allnodes",
(x,y) =>TreeViewItemStatus.initializeShow)

I get an error:

The type arguments for method 'MVCControlsToolkit.Controls.TreeViewHelpers.TreeViewFor(System.Web.Mvc.HtmlHelper, MVCControlsToolkit.Core.RenderInfo>, System.Func, MVCControlsToolkit.Controls.ExternalContainerType, string, object[], System.Func, string, object[], System.Func, MVCControlsToolkit.Controls.TreeViewMode, System.Func, System.Func, MVCControlsToolkit.Controls.TreeViewOptions)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

Coordinator
Jul 17, 2012 at 9:22 AM

you passeed some argument with the wrong data type.  Does RootOrganizationElement is the same (with a spelling error) of  RootOrganizationElements or it si a single element? The treeview must be passed a list of root nodes not a single root node (obviously the list may contain also a single node)

Jul 17, 2012 at 10:15 AM

RootOrganisationElement = single OrganisationElement  -  I wasn't quite sure from your previous reply what I should be passing. I had read on another post it should be a list of root elements. That's now confirmed thanks.

So back to the child problems. Using my list RootOrganisationElements which extracts the parents (only one it this case) in the controller I still do not have any children displayed.

Controller:

            model.RootOrganisationElements = new List<OrganisationElement>()
                { model.OrganisationElements.FirstOrDefault(x => x.Parent == null) };

ViewModel:



        public IList<OrganisationElement> RootOrganisationElements { get; set; }

View:



@Html.TreeViewFor(model => model.RootOrganisationElements,
i=> "Children",
ExternalContainerType.span, 
"filetree treeview-red",
new object[]
    {
        _S.L<OrganisationElement>(h => "<span class='folder'>"+h.DisplayFor(m => m.Name).ToString()+"</span>")
    },
(x,y)=>0,
null,
null,
null,
TreeViewMode.InitializeDisplay,
(x)=>"allnodes",
(x,y) =>TreeViewItemStatus.initializeShow)

 

Again I have tested using the Menu helper:

@Html.Menu("Org",Model.RootOrganisationElements,
new{@class="navigationMenu"},
x=>x.Children,
_S.L<OrganisationElement>(h => "<span class='folder'>"+h.DisplayFor(m => m.Name).ToString()+"</span>"),null)

And can confirm the child elements are displayed in the Menu but not the TreeView.



Coordinator
Jul 17, 2012 at 10:41 AM

While you vcan put the Root elements in any IEnumerable property, the Children property of each node must be of type List<T>. At moment we still habe this limitation. In the next release (2.3) we will remove it.

In any case I advice avoiding to use Data Layer classes in the presentation layer. It is better to define presentation layer variants of them in the controllers, so you can adapt them to what you have to pass to the View, you can add metadata and validation attributes that are specific for the presentation layer.

You can do this directly with a Linq select clause that fill the variant of the original class. Another possibility is the use of AutoMapper to copy one object in the other (for big classes with a lot of properties)

 

You can apply validation attributes to all variant of the same class by using aa MetaDataType when needed, to avoid code duplications.

Jul 17, 2012 at 10:57 AM

OK thanks - I'm using fluent nhibernate so I'm stuck using IList rather than List. I'll have a look at whether automapper is practical for this.

Do you have an ETA on 2.3?

Jul 17, 2012 at 11:32 AM

That's working now using AutoMapper and using an OrganisationElementViewModel, thanks a lot for your help.