Image 1: List view webpart with folder-navigation breadcrumb
I’ll explain in the post how you can achieve this kind of folder navigation with minimum changes/customisation.
Deployment
Download the FolderNavigation.js file from MSDN Code Gallery. You can deploy the script either in Layouts folder (in case of full trust solutions) or in Master Page gallery (in case of SharePoint Online or full trust). I would recommend to deploy in Master Page Gallery so that even if you move to cloud, it works without modification. If you deploy in Master page gallery, you don’t need to make any changes, but if you deploy in layouts folder, you need to make small changes in the script which is described in section ‘Deploy JS Link file in Layouts folder’.Option 1: Deploy in Master Page Gallery (Suggested)
If you are dealing with SharePoint Online, you don’t have the option to deploy in Layouts folder. In that case you need to deploy it in Master page gallery. Note, deploying the script in other libraries (like site assets, site library) will not work, you need to deploy in master page gallery. To deploy in master page gallery manually, please follow the steps:- Download the js file from MSDN Code Gallery.
- Navigate to Root web => site settings => Master Pages (under group ‘Web Designer Galleries’).
- From the ‘New Document’ ribbon try adding ’JavaScript Display Template’ and then upload the FolderNavigation.js file and set properties as shown below:
Image 2: Upload JS file to Master Page Gallery
Option 2: Deploy JS Link file in Layouts Folder
If you are deploying the FolderNavigation.js file in Layouts folder, you need to make small changes in the downloaded script’s RegisterModuleInti method as shown below:RegisterModuleInit('FolderNavigation.js', folderNavigation);
In this case the ‘RegisterModuleInit’ first parameter will be the path relative to Layouts folder. If you deploy your file in path ‘/_Layouts/folder1’, the then you need to modify code as shown below:
RegisterModuleInit('Folder1/FolderNavigation.js', folderNavigation);
If you are deploying in other subfolders in Layouts folder, you need to update the path accordingly. What I’ve found till now, you can only deploy in Layouts and Master page gallery. But if you find deploying in other folders works, please share.
Use The JS File in List View WebPart
Once you deploy the FolderNavigation.js file, you can start using it in list view webpart. Edit the list view web part properties and then under ‘Miscellaneous’ section put the file url for JS Link as shown below:Image 3: JS Link for list view webpart
Few points to note for this JS Link:
- if you have deployed the js file in Master Page Gallery, You can use ~site or ~SiteCollection token, which means current site or current site collection respectively.
- If you have deployed in Layouts folder, you need to use corresponding path in the JS Link properties. For example if you are deploying the file in Layouts folder, then use ‘/_layouts/15/FolderNavigation.js’, if you are deploying in ‘Layouts/Folder1’ then, use ‘/_layouts/15/Folder1/FolderNavigation.js’.
How it works?
If you are interested how it works, you can carry on reading, either move to deployment section. Basically I’ve utilized the SharePoint 2013 Client Side Rendering (CSR) concept. If you are not familiar with this CSR, you can get the basic idea by Googling. Simply, CSR allows us to customize the rendering of SharePoint fields using JavaScript. I’ve developed a client side rendering JavaScript file which is shown below:
///Author: Sohel Rana //Version 1.2 //Last Modified on 27-Oct-2013 //Version History: // 1. Added // 2. Fixed the bug 'Filtering by clicking on field title would result duplicate navigation link' // 3. Fixed the bug 'breadcrumb title always lowercase'. Now breadcrumb title is as like the folder name in the library even with case (lower/upper) //replace query string key with value function replaceQueryStringAndGet(url, key, value) { var re = new RegExp("([?|&])" + key + "=.*?(&|$)", "i"); separator = url.indexOf('?') !== -1 ? "&" : "?"; if (url.match(re)) { return url.replace(re, '$1' + key + "=" + value + '$2'); } else { return url + separator + key + "=" + value; } } function folderNavigation() { function onPostRender(renderCtx) { if (renderCtx.rootFolder) { var listUrl = decodeURIComponent(renderCtx.listUrlDir); var rootFolder = decodeURIComponent(renderCtx.rootFolder); if (renderCtx.rootFolder == '' || rootFolder.toLowerCase() == listUrl.toLowerCase()) return; //get the folder path excluding list url. removing list url will give us path relative to current list url var folderPath = rootFolder.toLowerCase().indexOf(listUrl.toLowerCase()) == 0 ? rootFolder.substr(listUrl.length) : rootFolder; var pathArray = folderPath.split('/'); var navigationItems = new Array(); var currentFolderUrl = listUrl; var rootNavItem = { title: 'Root', url: replaceQueryStringAndGet(document.location.href, 'RootFolder', listUrl) }; navigationItems.push(rootNavItem); for (var index = 0; index < pathArray.length; index++) { if (pathArray[index] == '') continue; var lastItem = index == pathArray.length - 1; currentFolderUrl += '/' + pathArray[index]; var item = { title: pathArray[index], url: lastItem ? '' : replaceQueryStringAndGet(document.location.href, 'RootFolder', encodeURIComponent(currentFolderUrl)) }; navigationItems.push(item); } RenderItems(renderCtx, navigationItems); } } //Add a div and then render navigation items inside span function RenderItems(renderCtx, navigationItems) { if (navigationItems.length == 0) return; var folderNavDivId = 'foldernav_' + renderCtx.wpq; var webpartDivId = 'WebPart' + renderCtx.wpq; //a div is added beneth the header to show folder navigation var folderNavDiv = document.getElementById(folderNavDivId); var webpartDiv = document.getElementById(webpartDivId); if(folderNavDiv!=null){ folderNavDiv.parentNode.removeChild(folderNavDiv); folderNavDiv =null; } if (folderNavDiv == null) { var folderNavDiv = document.createElement('div'); folderNavDiv.setAttribute('id', folderNavDivId) webpartDiv.parentNode.insertBefore(folderNavDiv, webpartDiv); folderNavDiv = document.getElementById(folderNavDivId); } for (var index = 0; index < navigationItems.length; index++) { if (navigationItems[index].url == '') { var span = document.createElement('span'); span.innerHTML = navigationItems[index].title; folderNavDiv.appendChild(span); } else { var span = document.createElement('span'); var anchor = document.createElement('a'); anchor.setAttribute('href', navigationItems[index].url); anchor.innerHTML = navigationItems[index].title; span.appendChild(anchor); folderNavDiv.appendChild(span); } //add arrow (>) to separate navigation items, except the last one if (index != navigationItems.length - 1) { var span = document.createElement('span'); span.innerHTML = ' > '; folderNavDiv.appendChild(span); } } } function _registerTemplate() { var viewContext = {}; viewContext.Templates = {}; viewContext.OnPostRender = onPostRender; SPClientTemplates.TemplateManager.RegisterTemplateOverrides(viewContext); } //delay the execution of the script until clienttempltes.js gets loaded ExecuteOrDelayUntilScriptLoaded(_registerTemplate, 'clienttemplates.js'); }; //RegisterModuleInit ensure folderNavigation() function get executed when Minimum Download Strategy is enabled. //if you deploy the FolderNavigation.js file in '_layouts' folder use 'FolderNavigation.js' as first paramter. //if you deploy the FolderNavigation.js file in '_layouts/folder/subfolder' folder, use 'folder/subfolder/FolderNavigation.js as first parameter' //if you are deploying in master page gallery, use '/_catalogs/masterpage/FolderNavigation.js' as first parameter RegisterModuleInit('/_catalogs/masterpage/FolderNavigation.js', folderNavigation); //this function get executed in case when Minimum Download Strategy not enabled. folderNavigation();
Code Snippet 1: Folder Navigation JavaScript
Let me explain the code briefly.
- The method ‘replaceQueryStringAndGet’ is used to replace query string parameter with new value. For example if you have url ‘http://abc.com?key=value&name=sohel’ and you would like to replace the query string ‘key’ with value ‘New Value’, you can use the method like
replaceQueryStringAndGet("http://abc.com?key=value&name=sohel","key","New Value")
- The function folderNavigation has three methods. Function ‘onPostRender’ is bound to rendering context’s OnPostRender event. The method first checks if the list view’s root folder is not null and root folder url is not list url (which means user is browsing list’s/library’s root). Then the method split the render context’s folder path and creates navigation items as shown below:
var item = { title: title, url: lastItem ? '' : replaceQueryStringAndGet(document.location.href, 'RootFolder', encodeURIComponent(rootFolderUrl)) };
As shown above, in case of last item (which means current folder user browsing), the url is empty as we’ll show a text instead of link for current folder.
- Function ‘RenderItems’ renders the items in the page. I think this is the place of customisation you might be interested. Having all navigation items passed to this function, you can render your navigation items in your own way. renderContext.wpq is unique webpart id in the page. As shown below with the wpq value of ‘WPQ2’ the webpart is rendered in a div with id ‘WebPartWPQ2’.
Image 4: How list view webpart is rendered
In ‘RenderItems’ function I’ve added a div just before the webpart div ‘WebPartWPQ2’ to put the folder navigation as shown in the image 1.
- In the method ‘_registerTemplate’, I’ve registered the template and bound the OnPostRender event.
- The final piece is RegisterModuleInit. In some example you will find the function folderNavigation is executed immediately along with the declaration. However, there’s a problem with Client Side Rendering and Minimal Download Strategy (MDS) working together as described in here. To avoid this problem, we need to Register foldernavigation function with RegisterModuleInit to ensure the script get executed in case of MDS-enabled site. The last line ‘folderNavigation()’ will execute normally in case of MDS-disabled site.
If I create a new View in the Documents list and use the default (which I just added a JSLink definition to) to start with, it does not inherit the JSLink definition.
ReplyDeleteHow will this then work for Personal Views users create??
@Danny, Yes I've noticed the same problem now. The only solution I find (maybe not the best one) is to add the JS link in the personal view also.
ReplyDeleteThanks a lot for this great guide! Just yesterday my GM asked me to figure out how to enable breadcrumbs for Document Libraries, so your timing was perfect.
ReplyDeletePerfect! Thank you!
ReplyDeleteOnly the procedure and screenshots are slightly different (updated?) in SharePoint online (e.g. it was called Display Template Code instead of JavaScript Display Template’)
Hi All, a bug was reported - "Filtering by clicking on field title would result duplicate navigation link". I've fixed the issue and uploaded the latest js file in code gallery. Please take update..
ReplyDeleteI tried this in an O365 site but doesnt work, any ideas?
ReplyDeleteRather to be more specific, the breadcrumb is not showing full path when i navigate to subfolders
DeleteHi, Where have you deployed the script? Master Page gallery or Layouts folder? Can you please provide more specific details - like your folder structure or possibly a screenshot to my personal email ranaictiu at hotmail dot com? If there's any bug I'll fix it.
DeleteSorry for the late reply Sohel, but i found that the issue was occurring if i was visiting the document library folder from a web part in the home page of the site. If i went to the documents library it was working fine. So basically your code is perfect, thanks a lot :)
DeleteIt works fine for me.
ReplyDeleteThank you a lot for this !
Hi Sohel
ReplyDeleteThank you very much for this script. It worked like a charm. Just one thing, Is it possible to make first letter of the Folder name to be uppercase? Instead of "folder 1", can it be "Folder 1"?
Thanks
Hi, the script were showing folder name in lower case always as reported by Dipal Patel. I've fixed the bug, now the folder name appears as it is in the list. I've uploaded the updated script in the MSDN code gallery. Thanks for your feedback.
ReplyDeleteHi Sohel
ReplyDeleteThank you very much for making this change. It really helps a lot.
Hi Sohel, I've tried your step by step procedure but it doesn't show up :( I am using sharepoint online, but i dont think that should be the problem?
ReplyDeleteI have uploaded it in masterpage gallery (_catalogs/masterpage) as Javascript Display Template content type. Then edited the webpart of my document library to add the link of js script. I don't get that breadcrumb below the webpart title. Do I need to activate a feature of something? Or edit something on the script? Thanks for all your help!
@Karen, How have you referenced the file in js link? You need to use ~site or ~siteCollection token.
ReplyDeleteSohel, this is excellent and works great. Thanks so much. Is there any where in your js that I could add a line break after the navigation? If "Display search box" is selected in the web part properties and the toolbar with "new document" is set to show, the folder navigation is positioned very tightly above "new document" and looks cluttered. Perhaps there is a better way to get a line break there. Any suggestions?
ReplyDelete@Neil G, Currently it doesn't support styling, but I'll include some stying option later...
ReplyDeleteI created a similiar feature, but I did it using front end jQuery code and the "Navigate Up" breadcrumb snippet. Hopefully it's useful to someone else. Your solution worked for list views, but for some reason wouldn't work on document library pages. You can view my solution here:
ReplyDeletehttps://hardwiredmedia.com/creating-breadcrumbs-sharepoint-2013-document-library-pages/
It's a bit of a hack, but it works!
also, this solution works for list views and doc libraries!
DeleteThanks for your code.
ReplyDeleteIf I'm understanding this correctly, every list, library, view needs to have this added. Any new document libraries and lists as well.
Stephan Onisick
@Stephano, Yes if you need to use in in a single library, but one of my colleagues has put it in master page and the breadcrumb appeared globally, I've not tested though.
ReplyDeleteUsing the exact instructions from the first method doesn't work for our 2013 on site installation :S. Do i need to use the list template ID? If so what list template to I gain the ID of and how???
ReplyDeleteThanks in advance
Lawrence
I've since solved this :) my mistake. Fat fingers :P
DeleteHi, at first thanks for this nice feature! Secondly, we are facing issue with SP Online. Users with read permission don't see breadcrumb. Only people having at least Contribute permissions for JavaScript file. Any ideas how to overcome this issue, so that we can set JS file as Read?
ReplyDeleteThanks for advance!
@Aivovaurio, Please check the js file permission, if everyone has read permission. I think if you upload in the 'masterpage gallery', everyone will have read permission by default.
ReplyDeleteThank you for response. That is part of the problem, when file has read only permissions, some users who has only read permission on site itself, cannot see breadcrumb. Only if they are promoted as Contribute for that js file. Which is very bad approach. I should come over this and keel the file read only for all, and also make this visible for people only read right for the site.
DeleteOk, now it is solved. It is good idea to publish js file when uploaded! If it is in draft mode, sure it won't appear to read only people :)
DeleteWhen I press the "New Document" button all that I get is a "Add a master page" dialog not matter what document type I select. Has anyone else ran into this issue? This is what happens on the root site but on all subsites the "New Document" button is grayed out completely.
ReplyDelete@skeletank, Do you have right permission (site collection administrator, most probably)? Also if you are using any custom branding, that might break the functionality sometimes.
ReplyDeleteI am a site collection administrator. I realize now that on the root site the 'Add a master page' dialog is normal and that I select a content type afterwards. However, I still don't understand why the "New Document" option is grayed out on subsites.
DeleteI can confirm that calling the FolderNavigation.js file in the master page DOES make the breadcrumb appear globally. It automatically shows up in the header of any document libraries I go to, but only once I go down into a folder. I used CSS to move the breadcrumb up under the global breadcrumb in the site title, and it looks great.
ReplyDeleteAwesome work! Thank you for this script!
Thanks for the script. Awesome work, was exactly what I needed!
ReplyDeleteThanks for your scripts. it is working well.
ReplyDeleteThanks for the script! Sometimes, the navigation bar is visible, sometimes not. If I start navigating in edit mode, then the navigation bar is visible. Otherwise, it is hidden all the time. Not sure how to make it visible by default. I have installed the script under Master Pages. Any suggestions?
ReplyDelete@Srinath, please make sure the script is published. Also if you are using custom branding/master page, check if the custom styling is hiding the nav - one way to check this is to use SharePoint default master page and check if the nav is visible
ReplyDeleteSohel,
ReplyDeleteHow can we get it to work if we have multiple document libraries on the same page? Looks like it does not work in this scenario.
Thank you.
@Ajay, It doesn't work with multiple document libraries in a page... I'll look into the issue and once I fix, I'll update in here..
ReplyDeleteGreat script..! Thanks for this.. but how do I change the display name for the root node to show the name of the document library instead of the default 'Root'?
ReplyDelete@Jatin, current version only support 'Root' but I'm working on next version with css styles support as well as few more options... I'll look into your suggestion also.
ReplyDeleteI've uploaded new version of the script with the following additions:
ReplyDelete1) css class support - the default css class is 'folder-nav-container'
2) Added option whether to show 'Root' or list/library title through a javascript variable 'useDocLibTitleAsRootFolderName'. By default it's false means will show 'Root'
However supporting multiple document libraries in the same page will be quite difficult and not supporting at this time..
Hi Sohel,
ReplyDeleteI'm using SharePoint 2013 (on-prem) and my purpose for using your script is so I can show the breadcrumb in modal windows because OOTB SharePoint removes the page title breadcrumb in modal windows.
When I click on the navigation links created by your script it actually opens a new IE tab inside of navigating inside the modal window. Is there any way to fix this?
1. Create two document library webparts on the same page, say we name them A and B.
ReplyDelete2. Create one sub-folder for each library respectively. say foo for A, and bar for B.
3. On the same page, click open folder foo for library A, AND at same time click open folder bar for library B.
4. Click "Root" for folder foo of library A.
5. Page Refreshes and folder foo closed. Folder Bar also closes in library B, but incorrectly, the breadcrumb is still showing, and has a structure of "Root > SiteName > A"
6. When click on the SiteNmae part of the breadcrumb, some times webpart crashes.
Please advise.
Thanks
Hi Micky,
ReplyDeleteMultiple webparts in a page is not supported yet.
I see, looking forward to seeing more updates. Thanks for everything you've already done.
DeletePerfect.......Thank you!
ReplyDeleteworked perfectly first time, thank you!
ReplyDeleteGood Day.
ReplyDeleteThanks for the script.
But I have several questions.
1. When I try this script in Chrome and IE it's not working. And I see error in javascript console telling that it refused to execute script because its mime type is not executable, and strict MIME type checking is enabled.
2. I changed useDocLibTitleAsRootFolderName parameter to true. But if I go to doc library and open some folder it still shows me "root" at the start of the full path and the title of the library. Only if I do refresh it shows correct path.
@peanucm, sorry for late reply - was on holiday. The most probable reason might be you have not not selected 'javascript teamplate' when you had uploaded in master page gallery??
ReplyDeleteNo, I selected 'javascript teamplate'.
ReplyDeleteI found that this problem happened only for users who have only read permissions on the root site, so they are in SharePoint Visitors group.
Sohel, nice script. I am having and issue with styles though. When we deploy the script it seems as though it some how overrides the styles of the list (specifically the alternate row shading disappears). Have you run into this before and if so is there a fix? Thanks in advance.
ReplyDeleteHi Sohel,
ReplyDeleteI can't start complimenting you enough for this great addition!
One question though.
I'm trying to get this to work for ALL libraries farm-wide.
So I've added this in the _layouts folder and added it to the master page (at the bottom) to always load.
It works perfectly for direct links (/sitename/Libname?RootFolder=...) but not for MDS links (/sitename/_layouts/15/start.aspx#libname?RootFolder=...).
Any clue as to why this could be?
I have several tens of sites I want this to apply to.
SabbeRubbish
My bad, shouldn't have included the .js file in the master page using a < script > tag, had to use the < SharePoint:ScriptLink > tag. Seems < script > is not supported by MDS.
Delete@Martin,The option is whether to show root folder as 'Root' or Document Library title. If doesn't display properly can you please try changing the document library title to simple text or try in different document library?
ReplyDeleteGreat Script! but when I change view setting( style>default to preview) , it doesn't work.
ReplyDeleteCan't use this script in preview style ?
Hi
ReplyDeleteAny update on multiple views on the same page - was really exciting to see on first webpart and was gutted not to work on the others - by far the nicest solution out there, please update for us :)
Hi Unknown,
ReplyDeleteI've actually managed to get it to work on a page with multiple listview webparts using the default code.
any idea how? SPonline?
ReplyDeleteJust include the code in your master page (the .html, not the .master) and you're set to go. Make sure you also add the JS file in your Asset library.
ReplyDeleteThis should work in SP Online just as well, no magic happening anywhere on server side.
I think I have it working now, whole page reload is a bit painful on folder select through!
ReplyDeleteThen make sure Minimal Download Strategy is enabled and use the latest version of the script that supports MDS.
ReplyDeleteMany thanks brother, just used your functionality today, definitely saved me couple of hours.. I think NEC should bill Ignia for 2 hours, hahaha... Cheers
ReplyDeleteHi
ReplyDeleteIts not working for me if the browser in compatible mode. any ideas?
Thanks in Advance!
Shouldn't have any issues with Browser compatibility mode. Please try with SharePoint default master page as custom branding/scripting may cause issues.
ReplyDeleteHi Sohel,
ReplyDeleteThanks for the script it works fine. Perfect.
Hi Sohel
ReplyDeleteI added an improved version of your script to the free and easy deployment tool Plain 365 (https://fiechter.eu/p365/). This is intended for users which don't really want to play around with java script, SharePoint Designer and other things.
Also the blog post announcing the feature is referencing your blog
https://fiechter.eu/2016/01/31/breadcrumb-for-sharepoint-document-libraries/
Hi Sohel,
ReplyDeleteI was able to add the Breadcrumb on a document library web part. However when I apply style on the library view (e.g. shaded view in web part setting) the style is not applied on the web part. Can you please me help sort out this issue?
Any update about same
DeletePlease use browser developer toolbar (or take help from any web developer) on applying css style to the breadcrumb.
DeleteThanks. I managed to add Shaded look to the document library web part by adding below code on a script editor Web Part on the page where the Document Library Web part is created.
Deletestyle type="text/css">
tr:nth-child(even){background:#f1f1f1}
/style>
(Open and close the style tags< blog does not allow me to save the comment if I use Style tags)
@Adrian, thanks for sharing.
ReplyDeletehi - great solution, except I am having the same problem as the posters above. it breaks my style I have set on my webpart view... how do I get around that?
ReplyDeleteThanx man
ReplyDeleteFirst off – love this script. One thing noticed in practice… if you have a long list in which you have to scroll to select your folders – if then the selected folder also has a long list of files/folders, that the script will lands you in the middle of the page – Not at the top as expected. You have to scroll up to get to the top of the list.
ReplyDeleteThank you so much
ReplyDeleteFor multiple web parts on the page, I've added the following code in folderNavigation() after checking renderCtx.rootFolder. Since clicking on a folder in one web part causes the other web part(s) to render displaying the root, I am just not doing anything if the root folder in the URL and the list URL of the web part being rendered do not match. This means I am only seeing the crumbing for the web part that corresponds to the one in which I clicked on a folder. Not heavily tested but seems to work for my purposes.
ReplyDeletevar listUrl = encodeURIComponent(renderCtx.listUrlDir.replace("%20", " "));
if (renderCtx.rootFolder.indexOf(listUrl) === -1) {
return;
}
I'm having trouble making these breadcrumbs work in IE 11 and Firefox. The folder navigation works just fine in Chrome and Edge. It's an https:// site, would this be a reason for it not working in IE? Any other ideas?
ReplyDeleteThis comment has been removed by the author.
ReplyDeletehi. i like your custom JS. but i would like to check how do i edit the js such that when the user first enter the page with the web part, the bread crumb will show the root folder. currently now it is not showing anything. i need to click on a folder then click on the root folder link before it will be shown.
ReplyDeleteweb part initial view
Click on folder
Navigate back