2

I'm trying to find a way to do this: In a webpart on a page, create a tree view of all items in the "Documents" library, with folders, subfolders, and items (links to items).

So my idea was to add a Documents webpart on the page, and, using JSLink, output a html ul/li list that can be easily tranformed into a tree view using 3rd party JS library. (e.g. jsTree)

Example: For a Documents library created as this :

  • Folder 1
    • Folder 1.1
      • item A (itemA.ext)
      • item B (itemB.ext)
    • Folder 1.2
      • item C (itemC.ext)
      • item D (itemD.ext)
  • Folder 2
    • ...

The ul/li would look like this

<ul>
    <li class="folder">Folder 1
        <ul>
            <li class="folder">Folder 1.1
                <ul>
                    <li class="item"><a href="xxx/itemA.ext">item A</li>
                    <li class="item"><a href="xxx/itemB.ext">item B</li>
                </ul>
            </li>
            <li class="folder">Folder 1.2
                <ul>
                    <li class="item"><a href="xxx/itemC.ext">item D</li>
                    <li class="item"><a href="xxx/itemC.ext">item D</li>
                </ul>
            </li>
        </ul>
    </li>
    <li class="folder">Folder 2
        ....
    </li>
</ul>

And the tree result would be like:

jsTree

(of course, more than 2 levels might be used) So i've added my Documents webpart, and added this JSLink:

var DocView = DocView || {};

DocView.itemHtml = function (ctx) {
    var title = ctx.CurrentItem.Title; 
    var fileRef = ctx.CurrentItem.FileRef;
    var fileLeafRef = ctx.CurrentItem.FileLeafRef;
    if (title) {
        return "<li><a href='"+ fileRef + "'>"+ title + "</a></li>"; 
    }
    else {
        return "<li>"+ fileLeafRef + "</li>"; 
    }
};

(function () {
    var DocuCtx = {};
    DocuCtx.Templates = {};
    DocuCtx.Templates.Header = "<ul class='allDocs'>";
    DocuCtx.Templates.Item = DocView.itemHtml;
    DocuCtx.Templates.Footer = "</ul>";

    DocuCtx.ListTemplateType = 101;
    //DocuCtx.BaseViewID = 99;

    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(DocuCtx);
})();

This results as a list of items located at first level of my Documents library. I then tried to modify the default view of the library to display all files flat, without folders. There, it displays all items flat, without folders. and I don't have ctx.currentItem.Path value to add a manual logic to recreate the library hierarchy.

So questions: Is this way of doing a good approach? (I mean with JSLink) Any way to get the actual hierarchy structure of the library? Any performance issues to expect if that library is quite huge? (~3-4 levels + a total of 300+ items inside)

Note: As simple owner of the site collections, I can't do much, other that use JS API, no server-side scripting possible...

Thanks for your help !

3

I found a solution.

Here it is:

I modified the view of my documents Library to display all elements flat, without folders. Then I created this JSLink:

var DocuView = DocuView || {};

DocuView.itemHtml = function (ctx) {
    var title = ctx.CurrentItem.Title; 
    var fileRef = ctx.CurrentItem.FileRef;
    var fileLeafRef = ctx.CurrentItem.FileLeafRef;
    //if title defined, display it, otherwise display fileLeafRef, without aspx extension in case of link to document
    var displayTitle=(title)?title:(/\.aspx$/.test(fileLeafRef)?fileLeafRef.replace('.aspx',''):fileLeafRef);
    //split path to array to get different levels of hierarchy
    var path=fileRef.slice(fileRef.indexOf('Documents/')+10,fileRef.lastIndexOf('/')).split('/');
    //create a container outside the default container, because the JSLink will overwrite all content inside the default <td>
    //and load js+css files by adding to DOM
    if($('#docsTree').length==0) $('#script'+ctx.wpq).closest('tr').after('<tr><td><link rel="stylesheet" href="/sites/testSite/Tree/SiteAssets/style.min.css"/><script src="/sites/testSite/Tree/SiteAssets/jquery-1.12.0.min.js"></script><script src="/sites/testSite/Tree/SiteAssets/jstree.min.js"></script><script src="/sites/testSite/Tree/SiteAssets/jstree.search.js"></script><script src="/sites/testSite/Tree/SiteAssets/jstree.wholerow.js"></script><div id="docsTree"></div></td></tr>');
    if($('#docsTree>ul').length==0) $(dom).append('<ul>');
    //Clear path for root elements
    if(path.length==1 && path[0]=="") path=[];
    var dom='#docsTree';
    var domTarg;
    //for each level (folder), add it to the html list
    $(path).each(function(j,p){
        var domAdd=' li[data-path="'+p+'"]'
        dom+=domAdd;
        if($(dom).length==0){
            if($(dom.replace(domAdd,'')+'>ul').length==0) $(dom.replace(domAdd,'')).append('<ul>');
            $(dom.replace(domAdd,'')+'>ul').append('<li class="folder" data-jstree=\'{"icon":"'+ctx.imagesPath+'folder.gif"}\' data-path="'+p+'">'+p+'<ul><ul></li>')
        }
    });
    $(dom+'>ul').append('<li class="leaf" data-jstree=\'{"icon":"'+ctx.imagesPath+ctx.CurrentItem["HTML_x0020_File_x0020_Type.File_x0020_Type.mapico"]+'"}\'><a href="'+fileRef+'">'+displayTitle+'</a></li>')
    return ""
};

(function () {
    var DocuCtx = {};
    DocuCtx.Templates = {};
    DocuCtx.Templates.Header = '<div class="treeSearch"><input type="text" id="searchInput"/><a id="clearResults">Clear</a><div id="SearchMessage"></div></div>';
    DocuCtx.Templates.Item = DocuView.itemHtml;
    DocuCtx.Templates.Footer = '<script type="text/javascript">$(\'#docsTree\').jstree();</script>';

    DocuCtx.ListTemplateType = 101;
    //DocuCtx.BaseViewID = 99;

    DocuCtx.OnPostRender = postRenderHandler;   

    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(DocuCtx);
})();
function postRenderHandler(ctx) {
    $('#docsTree').jstree({
        plugins:["wholerow","search"]
    })
}

Remains the question of performance, I have to test with a huge library...

  • I'm trying to test this but couldn't get the Treeview to display. I tried loading jstree.js in a script src cewp above the documents web part but nothing is rendered. – Brett Apr 3 at 2:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.