1

In MS Project Server, on the Project Center page, I want to make it automatically show linked sub-projects in the main view.

You can get the sub-projects to show by clicking on the PROJECTS tab in the Ribbon and then checking the checkbox for show/hide sub-projects.

screen shot of ribbon

This setting is apparently persisted across sessions (maybe stored in a cookie?), but it is "personal" to each user, and I want the sub projects to be shown for any user without them having to go to the Ribbon and check the checkbox.

I know that you can issue Ribbon commands by doing

SP.Ribbon.PageManager.get_instance().get_commandDispatcher().executeCommand('CommandName', propertyBag);

and I even found out the correct command from the Project Server Ribbon to show/hide the sub-projects. However, in order for that command to be available to the command dispatcher, you have to call _ribbonStartInit with the...correct namespace?... not sure what to call it exactly, but it looks like a namespace.

Anyway, I have something that works, in a Script Editor web part on the Project Center page:

SP.SOD.executeOrDelayUntilScriptLoaded(function() {
     _ribbonStartInit('Ribbon.ContextualTabs.ProjectCenter.Home',true, event);
    setTimeout(function() {
        SP.Ribbon.PageManager.get_instance().get_commandDispatcher().executeCommand('InsertedProject', {On:true});
    }, 100);
},'sp.ribbon.js');

However, I'm not overly happy with having to use setTimeout to add a delay between the _ribbonStartInit and executing the Ribbon command. But you do need a delay - this:

SP.SOD.executeOrDelayUntilScriptLoaded(function() {
    _ribbonStartInit('Ribbon.ContextualTabs.ProjectCenter.Home',true, event);
    SP.Ribbon.PageManager.get_instance().get_commandDispatcher().executeCommand('InsertedProject', {On:true});
},'sp.ribbon.js');

does not work because the 'InsertedProject' command is not available until it's loaded, which is (apparently) not synchronous.

So my question is, is there an event that I can hook into that will tell me when the Ribbon.ContextualTabs.ProjectCenter.Home commands have loaded and are available, so I don't have to rely on setTimeout?

I found that there is a SP.Ribbon.PageManager.get_instance().add_ribbonInited() function that seems to allow for adding a callback to execute after the Ribbon has "Init"ed, but I tried that and it doesn't seem to work, I think that probably fires on an early "Init"ed, and not after my call to

_ribbonStartInit('Ribbon.ContextualTabs.ProjectCenter.Home',true, event)

which, TBH, I just took from inspecting what happens when you click on the PROJECTS tab, so I'm not even 100% sure what the event part of that is. I'm assuming it's the triggering event (i.e. the click on the tab), and not a callback function.

  • Were you ever able to find more about this? I've been digging through _ribbonStartInit and my Firefox dev console to determine if this is possible. – SomeShinyObject Jun 12 at 2:23
  • @SomeShinyObject no, I was never able to find out any more. Still using the timeout. – Dylan Cristy Jun 16 at 13:20
0

I finally got back to working on something for this and the following is what I came up with.

Caveats beforehand:

  1. I use jQuery. I'm in the middle of writing something where jQuery is just really convenient to use for it's selector system. You can modify it to use true Promises if you want.
  2. I assume a timeoutLimit to stop the code after 5 seconds but add a parameter to change it for those who wish to do so.
  3. I also check for the element every quarter of a second. Modify if you need to.

Basically change it how you see fit.

/**
 *  waitForElement waits for an element with a chainable jQuery deferred object
 *  @param {string} el - The name of the element as a sizzler selector
 *  @param {number} timeoutLimit - If the element isn't found in this timeout limit, it clears the interval and rejects the deferred
 */
var waitForElement = function(el, timeoutLimit) {
    var deferred = new $.Deferred(),
        interval = 0,
        timeout  = 0;
    
    if (!timeoutLimit) { timeoutLimit = 5000 }
        
    timeout = setTimeout(function() {
        clearInterval(interval);
        console.log("what what");
        deferred.reject("Element not found within alloted timeout limit");
    }, timeoutLimit);
    
    interval = setInterval(function() {
        var element = $(el);
        if (element.length) {
            clearTimeout(timeout);
            deferred.resolve(element);
        }
    }, 250)
    
    return deferred.promise();
}

In your case you could use it like so:

waitForElement("#NameOfCheckBoxId", 4000)
    .then(function() { 
        //code to check box 
    })
    .fail(function() {
        //couldn't find element
    });
| improve this answer | |

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.