0

Ok I've already opened a subject like this, but this time I have no hairs left so I'm gonna summarize my knowledge on this issue, clearly, and hope that someone could help me.

Goal

I try to hide a node of the left navigation menu if the user is not part of the SP admin group.

Facts

To do this, I use jQuery on a custom .js file. I succeed to get if the user is admin or not, the problem is not here. But when I try to select the particular node to hide it, is works, on some pages. On others, it won't work.

I'm using SharePoint Foundation 2013.

Code

Here is my function to be called for every page loads :

function checkAdminRights() {

    var userId = _spPageContextInfo.userId;
    var requestHeaders = { "accept" : "application/json; odata=verbose" };

    $.ajax({
        url : _spPageContextInfo.webAbsoluteUrl + "/_api/web/sitegroups(7)/users/getbyid(" + userId + ")",
        contentType : "application/json;odata=verbose",
        headers : requestHeaders,
        success : userAdmin,
        error : userNotAdmin
    });
    function userAdmin(data, request) {
        console.log("user admin");
        var groupName = data.d.LoginName;
    }
    function userNotAdmin(error) {
        console.log("user not admin");
        $("ul.ms-core-listMenu-root li.static").each(function() {
            console.log("found !");
            if($(this).find("span.menu-item-text").text().indexOf("Administration") >= 0) { 
                $(this).hide();
            } 
        });
    }
}

I tried to launch this function with every single damn ways :

$.getScript("/_layouts/15/SP.UserProfiles.js");
SP.SOD.executeOrDelayUntilScriptLoaded(checkAdminRights, 'SP.UserProfiles.js');
// or
$.getScript("/_layouts/15/SP.UserProfiles.js");
_spBodyOnLoadFunctionNames.push('checkAdminRights');

In or out the following calls :

$(window).load(function () {}
// or
$(document).ready(function() {}

I can add that :

  • sp.js is already included in my pages, I can see it from the web developper toolbox of my browser (Firefox)
  • I cleared the cache between tries
  • I tried the conflict avoidance, by changing the aliases of jQuery "$" to "$jq", not changed anything.

Logs

In the console logs I can see that my function checkAdminRights is called properly and always execute the right callback. So if the user isn't admin, at each page load is see "user not admin". BUT, my .each(... loop is never accessed on some pages, in spite of that the HTML tag is existing !

Question

Why the hell, I can hide the node when loading for example the homepage ? But not for my Wiki pages, or a lot of others ?

I suspect the sp.js not to be included in the content of the page but into the master page. So it don't have the scope to reach my menu elements. I'm saying this because I've noticed that every pages where I put a Custom Script WebPart and I reference sp.js into, my code works for these pages.

Any help is appreciated, this thing is driving me crazy.

3

Since your ultimate goal is to manage visibility of navigation nodes based on user permissions, let me demonstrate another approach (no code solution).

How to configure Audience for Navigation nodes:

  • Go to Site Settings -> Navigation
  • select Navigation Heading or Link and click Edit link
  • specify Audience property. The figure below demonstrates how to configure Navigation Link in order to display Requests link only for SharePoint Group named Site Admins

enter image description here

Result

enter image description here


Option 2.

Solution consists of:

  • Determine whether user belongs to SP Group or not
  • Hide navigation node

JavaScript example:

function isUserInGroup(webUrl,userId,groupId)
{
    var url = webUrl + "/_api/web/sitegroups(" + groupId + ")/users?$filter=Id eq " + userId;
    return $.getJSON(url).then(function(data) {
           return (data.value.length > 0); 
    });
}

function hideNavigationLink(title) {
   var nodes = $('span.menu-item-text').filter(function(){ return $(this).text() == title; }); 
   if(nodes.length == 1) {
       $(nodes[0]).closest('li').hide();
   }    
}  


function initQuickLaunch()
{
   var webUrl = _spPageContextInfo.webAbsoluteUrl;  
   var currentUserId = _spPageContextInfo.userId; 
   var groupId = 26;  //specify your SP Group Id here
   var nodeTitle = 'Requests'; //specify your Node Title

   isUserInGroup(webUrl,currentUserId,groupId)
   .done(function(found){
       if(!found) hideNavigationLink(nodeTitle);    
   })
   .fail(function(error){
       console.log(JSON.stringify(error));
   });
}


_spBodyOnLoadFunctionNames.push('initQuickLaunch');
  • 1
    I'm so sorry, I forgot to write that I'm using SP Foundation 2013. I added the handmade Publishing Infrastructure recently, but still, my menu navigation isn't as elaborated as this one. – Alex Nov 21 '14 at 13:11
  • I see, the answer has been updated with custom solution that works for me – Vadim Gremyachev Nov 21 '14 at 15:46
  • Sorry for the late, reply Vadim. I'm doing pretty well the same thing in my script to hide my navigation node, but the matter is there : the selector $('span.menu-item-text') that we both use, can't find any DOM element. I do have these elements in my page, but do I have the scope to reach it from my script ? – Alex Nov 27 '14 at 13:11
  • Alex, i also noticed we use similar selector. One idea why it can't find DOM element is maybe your function is not called at all in some cases. Try to replace SP.SOD.executeOrDelayUntilScriptLoaded with SP.SOD.executeFunc function – Vadim Gremyachev Nov 27 '14 at 15:57
  • 1
    Alex, you are not bothering at all, your last comment sounds very reasonable, i'll check myself and get back to you.. – Vadim Gremyachev Dec 22 '14 at 8:30
1

It's not a complete answer yet, but I got a piece of the answer, hence my post.

I spotted that the MDS (Minimal Download Strategy)*(1) is altering the behaviour my custom script. For some page loads, the MDS is used, generating URLs like start.aspx#/Lists/link/to/my/element.

When the page is dynamically created with the asyncDeltaManager like this, my script is executed, but can't find the DOM elements of my Quick Launch left menu, because these elements are not retrieved again from the server, and somehow kept in cache. Besides, when the URL is normal and the content is completly retrieved from the server (not only the delta), my function to hide a node from the left menu works.

I tried to disable the MDS, and my script then works everywhere !

If I want to keep this feature activated, but exclude from the MDS my function I have to use the function RegisterModuleInit( file.js, functionName); *(2). I enabled again the MDS on my SP site, tryed this, but nothing changed ...

I'm still digging, but I think even if I disable MDS for this specific function, it won't work anyway until it needs to access some DOM elements which will not be rendered again (?)

*(1) The MDS is well explained here http://www.wictorwilen.se/sharepoint-2013---introduction-to-the-minimal-download-strategy-mds

*(2) I took informations from this post on MSDN blogs : http://blogs.msdn.com/b/sridhara/archive/2013/02/08/register-csr-override-on-mds-enabled-sharepoint-2013-site.aspx

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.