Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Brian Hvarregaard 21 posts 61 karma points
    Jan 08, 2016 @ 16:53
    Brian Hvarregaard
    0

    Extending the backend with one section and multiple trees

    Hi, Im looking to make a extension of the Umbraco backend. I want to achieve something like the "Setting" section in the Umbraco 7.x. That means that i have a section with "multiple trees". I will have a number of elements in the backend tree and it should function like a menu. This means that if i click each of the nodes a different list of elements should be edited.

    As an example is a Libracy. I have a section named "Library" and when i click the "Library" section i create a new tree with three nodes. "Books", "Comics" and "Music". Under each of these i will be editing these different objects.

    How do I achieve this, im trying with angular, but it doesnt look as if i can make multiple edit.html, create.html etc files for books, comics and music.

    Any idea of how i can achieve this? I looked at the Settings section, but they seem to use webform and not Angular. Can this even be done using Angular (since Umbraco itself is not using it?).

    If not - can anyone please point me in the right direction for using either MVC or webforms for extending trees and to achieve the scenario mentioned above.

    Cheers

  • David Brendel 792 posts 2970 karma points MVP 3x c-trib
    Jan 09, 2016 @ 19:34
    David Brendel
    0

    Hi Brian,

    you need to Name the edit/create/delete files vor which ever you need differently for each object to edit. So editBook or similar.

    Or make your edit view generic so that it can handle each object by providing a different ui for every object type.

    Regards David

  • Nicholas Westby 2054 posts 7100 karma points c-trib
    Jan 09, 2016 @ 20:40
    Nicholas Westby
    1

    I'm doing something like that here:

    Formulate

    As you can see, I have one section (Formulate) with what appear to be multiple trees.

    In actuality, it's one tree with multiple "root" nodes (i.e., Forms, Layouts, Data Sources, Data Values, Validation Library).

    You can see the implementation for this tree here: https://github.com/rhythmagency/formulate/blob/e822c231a2cf953a033019d491721f98e8ad5934/src/formulate.app/Trees/FormulateTreeController.cs

    Here's the important bit:

    if (id.InvariantEquals(rootId))
    {
    
        // Get root nodes.
        var formatUrl = "/formulate/formulate/{0}/info";
        var hasRootForms = Persistence
            .RetrieveChildren(rootFormsId).Any();
        var formsNode = this.CreateTreeNode(FormsConstants.Id, id,
            queryStrings, FormsConstants.Title,
            FormsConstants.TreeIcon, hasRootForms,
            string.Format(formatUrl, "forms"));
        nodes.Add(formsNode);
        var hasRootLayouts = Persistence
            .RetrieveChildren(rootLayoutsId).Any();
        var layoutsNode = this.CreateTreeNode(LayoutsConstants.Id,
            id, queryStrings, LayoutsConstants.Title,
            LayoutsConstants.TreeIcon, hasRootLayouts,
            string.Format(formatUrl, "layouts"));
        nodes.Add(layoutsNode);
        var dataSourcesNode = this.CreateTreeNode(
            DataSourcesConstants.Id, id, queryStrings,
            DataSourcesConstants.Title, DataSourcesConstants.Icon,
            false, string.Format(formatUrl, "dataSources"));
        nodes.Add(dataSourcesNode);
        var dataValuesNode = this.CreateTreeNode(
            DataValuesConstants.Id, id, queryStrings,
            DataValuesConstants.Title, DataValuesConstants.Icon,
            false, string.Format(formatUrl, "dataValues"));
        nodes.Add(dataValuesNode);
        var hasRootValidations = Persistence
            .RetrieveChildren(rootValidationsId).Any();
        var validationsNode = this.CreateTreeNode(
            ValidationsConstants.Id, id, queryStrings,
            ValidationsConstants.Title, ValidationsConstants.TreeIcon,
            hasRootValidations,
            string.Format(formatUrl, "validationLibrary"));
        nodes.Add(validationsNode);
    
    }
    

    If it detects the master root ID of the tree (-1), it will add what I call the main root nodes under that virtual node. When it creates each of those nodes, it passes in the route for the HTML view to show when the node is clicked. As one example, when somebody clicks the "Forms" node, the route used will be "/formulate/formulate/forms/info". Due to Umbraco's/Angular's routing magic, that file resides at ~\App_Plugins\formulate\backoffice\formulate\forms.html (the "info" part of the route is interpreted as an ID, but that ID is ignored by my view). You can see that view here: https://github.com/rhythmagency/formulate/blob/e822c231a2cf953a033019d491721f98e8ad5934/src/formulate.app/App_Plugins/formulate/backoffice/formulate/forms.html

    Note that I'm not sure if this is the "right" way of doing things. However, this seemed to be the most flexible way I could figure out. I think there is another way to create multiple "trees" in the same section, but it had some unintended consequences in my case (I think it was nesting them all under a few "formulate" root nodes), but I could have just been doing that wrong.

  • Nicholas Westby 2054 posts 7100 karma points c-trib
    Jan 09, 2016 @ 20:44
    Nicholas Westby
    1

    I should also add that you can use the node ID's to add custom actions (aka, menu items) when each of those nodes are right clicked. Here's the part of my code that does that:

    if (id.InvariantEquals(rootId))
    {
    
        // Do nothing. The root requires no actions.
    
    }
    else if (id.InvariantEquals(FormsConstants.Id))
    {
    
        // Actions for forms.
        FormHelper.AddCreateFormAction(menu);
        FolderHelper.AddCreateFolderAction(menu);
    
    }
    else if (id.InvariantEquals(LayoutsConstants.Id))
    {
    
        // Actions for layouts.
        LayoutHelper.AddCreateLayoutAction(menu);
        FolderHelper.AddCreateFolderAction(menu);
    
    }
    else if (id.InvariantEquals(ValidationsConstants.Id))
    {
    
        // Actions for validations.
        ValidationHelper.AddCreateValidationAction(menu);
        FolderHelper.AddCreateFolderAction(menu);
    
    }
    

    That's at the same link as above: https://github.com/rhythmagency/formulate/blob/e822c231a2cf953a033019d491721f98e8ad5934/src/formulate.app/Trees/FormulateTreeController.cs

  • Nguyen Minh The 12 posts 99 karma points
    Jun 30, 2017 @ 09:33
    Nguyen Minh The
    1

    Hello, it's 2017 and I still find out that it's actually hard to extend umbraco backoffice, is it just me? it has few of document to learn

  • Streety 358 posts 568 karma points
    Jan 18, 2018 @ 16:23
    Streety
    0

    Actually I found bundling everything in ONE tree rather troublesome once the tree got bigger.

    I found applying multiple trees easier to handle with the benefit of sharing the core app but having different routing directories. enter image description here

    This means I don't have to write long logic methods trying to figure what data or view to return dependent on which id is selected.

  • Nicholas Westby 2054 posts 7100 karma points c-trib
    Jan 18, 2018 @ 16:41
    Nicholas Westby
    0

    Do you mind explaining a bit how you accomplished that? It might be useful for others to know.

  • Streety 358 posts 568 karma points
    Jan 19, 2018 @ 09:58
    Streety
    0

    Sure.

    I am assuming you have you new section available and the trees.config is all done.

    You will have a treecontroller class if you have followed the tutorials. The one that inherits from Umbraco.Web.Trees.Treecontroller.

    Within this class you need to override two methods:

     protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
    

    and

    protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings)
    

    Thing to note here is the id parameter. Its a string. This is important.

    The idea is that you open Umbraco, click on your section and your section is populated with some nodes.

    Have a look at the GetTreeNodes method

       TreeNodeCollection nodes = new TreeNodeCollection();
            TreeNode nodeToAdd = null;
    
            if (id == "-1")
            {
                foreach (var item in uCronosHelpers.TreeHelper.GetAllTreeSections(this.RootNodeDisplayName))
                {
                    var route = uCronosHelpers.TreeHelper.uCronosViewPath(queryStrings.Get("application"), this.TreeAlias) + item.route + "/" + item.id;
                    nodeToAdd = CreateTreeNode(item.id.ToString(), item.parentId, queryStrings, item.name, item.icon, item.hasChildren, route);
                    nodes.Add(nodeToAdd);
                }
            }
            else if (id != "-1")
            {
                foreach (var item in uCronosHelpers.TreeHelper.GetAllJobs(id))
                {
                    nodeToAdd = CreateTreeNode(item.id.ToString(), item.parentId.ToString(), queryStrings, item.jobName, item.jobIcon, false);
                    nodes.Add(nodeToAdd);
                }
            }
            return nodes;
    

    So when the block runs it checks the id parameter for a value. Well you don't have a value yet so it will be null ("-1") remember its a string.

    The first block will run and this is where you create your root tree nodes. Here I am getting my root nodes from a custom helper function but you could get them from an umbraco node, or perhaps Facebook posts. Its doesn't matter. The point is you get a Collection/List/Array or even manually add the nodes.

    New up an instance of TreeNodeCollection which exposes the CreateTreeNode method.

    nodeToAdd = CreateTreeNode(item.id.ToString(), item.parentId, queryStrings, item.name, item.icon, item.hasChildren, route);
    

    Once you have built your collection of TreeNode's add them to the TreeNodesCollection.

    Search google for the CreateTreeNode parameters. Compile and run it and hey presto you have treesnodes in your tree.

    OK.

    If you only want a single level hierarchy of trees then stop here. If not you need to tell your CreateTreeNode object that your treenode has children. This is a boolean applied as a parameter. In the example above my root nodes are configured to have children. The item.hasChildren is a bool field in my database.

    Setting the children parameter enables the "show children" triangle next to the root node in your tree. If you click it, it will run the GetTreeNodes method AGAIN and now the id parameter will be whatever you configured it to be in the preceding CreateTreeNode operation for the item you have just clicked.

    This means you can serve custom nodes using the id effectively as your WHERE clause.

    In my example I am just splitting out root nodes from child nodes. Hence the id == "-1" and id != "-1". But you can use as many as you like or I guess use a Switch statement. I have structured my "node data" Root and Child objects to store a "parentId", which allows the collection of child nodes to be selected easier and avoid lenghtly "If Elses".

    That's basically it.

    Hope it helps.

  • Dan Diplo 1554 posts 6205 karma points MVP 5x c-trib
    Jan 19, 2018 @ 13:29
    Dan Diplo
    0

    To add to all the useful info there's an example I use in my Audit Log Viewer that has one tree, but with nested nodes underneath it. Relevant code is here:

    https://github.com/DanDiplo/Umbraco.AuditLogViewer/blob/master/Diplo.AuditLogViewer/Controllers/AuditLogTreeController.cs

Please Sign in or register to post replies

Write your reply to:

Draft