news and know-how about microsoft, technology, cloud and more.

Project Online / Project Server: Project Detail Pages - Enhancements (Part 1) - Show/Hide a field based on the value of an internal field on the same page

As an administrator, you may receive a requirement to add some logic to your Project Detail Pages (PDPs). There are some options how to do this. This is the first article of a series explaining ways to implement some logic using JavaScript/JQuery. All articles of this series apply to Project Online, Project Server 2013, Project Server 2016 and Project Server 2019.

There are three methods to get values of project fields:

Use only fields available on the page
  • Works in delegate sessions
  • Slower than other options, if you need to get values of more than one field
  • Evaluation field needs to be on page
  • Faster, if more than one field needs to be evaluated
  • Does not work in delegate sessions
  • Faster, if more than one field needs to be evaluated
  • Does not work in delegate sessions
  • Requires Access Project Server Reporting Service global permissions
  • Requires Project Premium license when using Project Online

Due to the disadvantages of OData, I will skip this method. Moreover, nearly everything available with OData can be achieved with REST.

Following topics will be discussed in this and future articles:

  1. Show/hide a field based on the value of an internal field on the same page
  2. Show/Hide a field based on the value of an Enterprise Custom field on the same page
  3. Show/Hide a field based on the value of an internal field using REST
  4. Show/Hide a field based on the value of an Enterprise Custom Field without Lookup Table using REST
  5. Remove Time from Enterprise Custom Fields on Project Detail Pages
  6. Remove Prefix from Enterprise Custom Fields on Project Detail Pages
  7. Hide Impact Ratings on Project Detail Page "Strategic Impact"
  8. Disable "Project Owner" Button on Project Detail Page

General Preparation

To get the sample scripts to work you will need to download the following jQuery library: jquery-2.1.1.min.js. Other versions of this library may work but this was the one I used / tested with. Upload this library to your PWA site collection. I created a document library named "Scripts" to hold all scripts including this library. Modify and upload samples of these articles to the same library.


To apply a script to a PDP, open the PDP either from PWA Settings - Project Detail Pages. Open PDP for page editing.


Add a Content Editor web part to your page.


Edit the Content Editor web part.


Enter full qualified or relative path to your script. Set Layout to Hidden, users do not want to see this web part. To avoid empty space at the top, set Zone Index to (#WebPartsOnPage - 1) - in this sample two webparts, so the value is 1. Click OK to apply your changes.


Stop editing of PDP.


Now your script will be active on this Project Detail Page.

Show/hide a field based on the value of a field on the same page

In this article, Enterprise Custom Field CostCenter will be hidden, if there are no cost for the project. Cost is an internal field, so GUID for this field is not known. Moreover, it is a field you cannot edit on an PDP. In one of the net articles you will see that it is easier to get a value of an Enterprise Custom fields if project is checked out. The code of this sample will work for a project, no difference if it is checked out or not. Using a field like cost, we need to look for the field name. If you look at the source of the page, you will see that all field information is provided in a table.
Skip details Unfortunately, this table has no table ID. In addition, the table rows holding the information have dynamic IDs. At least, the first part of the ID is dynamic and will be different in different sessions. Therefore, we will need to loop through all table rows to gather required data. Field names can be found in Header3 (<h3>).  A table row for a field looks like the following:

  •   <tr id="ctl00_ctl33_g_ea2bd6d2_a61d_42a5_b607_f8deb28f50b2_ctl00_pfp_Repeater_ctl02_pfp_ContainingElem_3732199b917243a591b8eafff9e28f88_0">
    Id of table row - will be used
  • <td nowrap="nowrap" valign="top" width="150px" class="ms-formlabel">
  • <h3 class="ms-accentText">Cost</h3>
    Field name in first column of table row, in tag h3
  • <div class="ms-textXSmall"><span style="white-space:normal;"></span></div>
  • </td>
  • <td valign="top" width="500px" class="ms-formbody">
  • <table width="100%" role="presentation">
    Nested table in second column of table row
  • <tr>
  • <td><div GUID="3732199b-9172-43a5-91b8-eafff9e28f88">$0.00</div></td>
    Value of field in first column in only row of nested table
  • </tr>
  • </table>
  • </td>
  • </tr>

Now take the information of the page and use it to hide field CostCenter.

<!-- Change path for jquery-2.1.1.min.js --> 
<script type = "text/javascript" src = "/sites/blog/Scripts/jquery-2.1.1.min.js"></script>
<script type = "text/javascript">

//Extend for required languages, use all translations of used fields 
//Sample: "Cost" in English, German and Dutch, Spanish (French "Coût"will only work with some editors 
var CostLanguages = ["Cost", "Kosten", "Costo"]
//Change to field to be hidden 
var FieldToHideOnCost = "CostCenter"
$(document).ready(ExecuteOrDelayUntilScriptLoaded(MainFunction, "sp.js"));
function MainFunction() {
    //Use all table rows 
    var TRows = $("tr");
    for (i = 0; i < TRows.length; i++) {
        //Field names in h3. No need to check other rows 
        if (TRows[i].getElementsByTagName('h3').length > 0) {
            if (jQuery.inArray(TRows[i].getElementsByTagName('h3')[0].innerText.replace('* ', ''), CostLanguages) > -1) {
                var CostFieldId = TRows[i].id
    if (CostFieldId) {
        var CostCellContent = document.getElementById(CostFieldId);
        var CostCellValue = CostCellContent.cells[1].innerText;
        //If Cost = 0, we do not need to show "CostCenter". Unformat number,Microsoft is using special formatting 
        if (LocalToNumber(CostCellValue, Sys.CultureInfo.CurrentCulture.numberFormat.CurrencyDecimalSeparator) == 0) {
    } else {
        console.log("Field not found")
//Hide a field 
function setFieldVisibility(field) {
    $(".ms-accentText").each(function(index) {
        if ($(this).text() == field) {
//Remove any number formatting by removing everything except decimalseparator and numbers 
function LocalToNumber(NumberString, DecimalSeparator) {
    var UnformattedNumber;
    if (DecimalSeparator == ',') {
        UnformattedNumber = parseFloat(NumberString.replace(/[^0-9-,]/g, ''));
    if (DecimalSeparator == '.') {
        UnformattedNumber = parseFloat(NumberString.replace(/[^0-9-.]/g, ''));
    return UnformattedNumber;

Copy above code into a text editor, modify at least the marked sections, save with file extension "js" or "html", and upload to your script library.

Pingbacks and trackbacks (1)+