Feb 242011
 

Often times we need to toggle the visiblity of an element based on the value of a field. This JScript file adds the methods to accomplish this by calling the setVisibility function. For example, in an onChange event for new_mypicklist I can call:

setVisibility('section','new_mypicklist','section_main',42);

This hides the section_main section if the value is not 42, which simplifies the process of hiding and showing relevant information.

I also like to use checkboxes to handle the visibility of elements, but checkbox values dont’ change until they lose focus. To work around the issue, I register an onClick event during the form load instead of using the onChange event. This unsupported method allows me to modify the value onClick and change the visibility immediately. To use this I just need to call it in the onload:

registerToggle('section', 'new_checkbox', 'section_main');

If you wanted to hide it when new_checkbox was false (or no), then you would need to specify the value, 0.

registerToggle('section', 'new_checkbox', 'section_main',0);

JScript: visibility.js

This is the main javascript file… visibility.js that you would need to add and reference as a web resource in CRM 2011, everything except for the registerToggle uses supported methods.

function registerToggle(t, attr, c, v) {
    if (typeof (v) === "undefined" || v === null) {
        var v = 1;
    }
    var ctrl = Xrm.Page.ui.controls.get(attr);
    var a = ctrl.getAttribute();
    var el = document.getElementById(attr);

    // Build Toggle Function
    var f = "var ef=function() { " +
              "var a = Xrm.Page.data.entity.attributes.get(attr); " +
              "a.setValue(!a.getValue()); " +
              "setVisibility('" + t + "','" + attr + "','" + c + "'," + v + ");" +
              " };";

    eval(f);

    // Attach to click event
    el.attachEvent('onclick', ef, false);

    // Set visibility
    setVisibility(t, attr, c, v);
}

function setVisibility(t, attr, c, v) {
    switch (t.toLowerCase().charAt(0)) {
        //tab
        case 't': setTabVisibility(attr, c, v);
            break;
        //section
        case 's': setSectionVisibility(attr, c, v);
            break;
        //control
        case 'c': setControlVisibility(attr, c, v);
            break;
        //navigation
        case 'n': setNavigationVisibility(attr, c, v);
            break;
    }
}

function setNavigationVisibility(attributename, navitemname, value) {
    var attribute = Xrm.Page.data.entity.attributes.get(attributename);
    var navitem = Xrm.Page.ui.navigation.items.get(navitemname);
    if (navitem === null)
    {
        return;
    }
    navitem.setVisible(attribute.getValue() == value);
}

function setTabVisibility(attributename, tabname, value) {
    var attribute = Xrm.Page.data.entity.attributes.get(attributename);
    var tab = Xrm.Page.ui.tabs.get(tabname);
    if (tab === null)
    {
        return;
    }
    tab.setVisible(attribute.getValue() == value);
}

function setSectionVisibility(attributename, sectionname, value) {
    var attribute = Xrm.Page.data.entity.attributes.get(attributename);
    var tabs = Xrm.Page.ui.tabs.get();
    for(var i in tabs) {
        var tab = tabs[i];
        var section = tab.sections.get(sectionname);
        if (section !== null) {
            section.setVisible(attribute.getValue() == value);
            return;
        }
    }
}

function setControlVisibility(attributename, controlname, value) {
    var attribute = Xrm.Page.data.entity.attributes.get(attributename);
    var control = Xrm.Page.ui.controls.get(controlname);
    if (control === null) 
    {
        return;
    }
    control.setVisible(attribute.getValue() == value);
}

  29 Responses to “CRM 2011: Toggle Visibility (Hide/Show) – Visibility.js”

Comments (26) Pingbacks (3)
  1. Hello

    any chance of publishing an RSS feed so I can subscribe to your blog

  2. I know this is a noob question but this new language in 2011 is kicking my butt. Can you give me an example of what you mena in this section (‘section’, ‘new_checkbox’, ‘section_main’);. If I was doing this for Tabs and my attribute was new_quoteproperty and I wanted to hide the Tab ‘Property_tab’ . I want to hide the Tab if new_quoteproperty is ‘No’ (It is a bit field). AM I right so far?? I am really confused by what you mean by ‘section’, am I supposed to put ‘Tab’ there? Any help would be appreciated. Thanks!!

    • I changed the code to handle no by adding the value to the registerToggle method. If you are using a checkbox, then you can call registerToggle in the onload and use the parameters:
      ‘tab’,'new_quoteproperty’,'Property_tab’,0

  3. Carlton
    This code is doing something strange to the radio buttons. It is requiring like three clicks to move the selection and my default values dont hold for some reason. This is the only code on this form right now. Any ideas?

    • You only use the registerToggle if you are changing the display to checkbox, not radio buttons – you can change the display to checkbox in the properties of the field – I think it is on the formatting tab. If you are using radio buttons, you should be able to use the onChange event and call the setVisibility method. There is an issue when you use a checkbox where it doesn’t change the value when you click on the checkbox, but instead when you lose focus. If you use the onChange event, then you also should call the setVisibility method in the onload as well; that way it will start up in the correct state. Hope that helps clear that up. If not, let me know and I’ll see what I can do to help.

  4. Thanks so much this worked perfectly. I have one more question. In 4.0 I had a lot of code that would hide/unhide sections of a tab based on a picklist value in that tab. An example would be a tab for Autos. I would create 20 sections in this tab to collect the info. We would hardly ever have 20 though. In order to not make my form out of control I would have the user pick the number of autos and then the form would unhide that number of sections. I am pasting a sample of the code below. Any idea how to write this with variables? I am struggling with this. It would be great to have since this scenario come into play about 20 other times in this form. If you have any ideas I would appreciate it.

    if (Xrm.Page.getAttribute("new_oflocations").getValue() == 1) { 
    crmForm.all.new_11addresscitystzip_c.parentElement.parentElement.style.display='';
    crmForm.all.new_12addresscitystzip_c.parentElement.parentElement.style.display='none'; 
    crmForm.all.new_21addresscitystzip_c.parentElement.parentElement.style.display='none'; 
    crmForm.all.new_22addresscitystzip_c.parentElement.parentElement.style.display='none';
    crmForm.all.new_addresscitystzip1_c.parentElement.parentElement.style.display='none'; 
    crmForm.all.new_addresscitystzip5_c.parentElement.parentElement.style.display='none';
    crmForm.all.new_addresscitystzip4_c.parentElement.parentElement.style.display='none';  
    crmForm.all.new_addresscitystzip3_c.parentElement.parentElement.style.display='none'; 
    crmForm.all.new_addresscitystzip6_c.parentElement.parentElement.style.display='none'; 
    crmForm.all.new_addresscitystzip2_c.parentElement.parentElement.style.display='none';
    } 
    else if (Xrm.Page.getAttribute("new_oflocations").getValue() == 2) { 
    crmForm.all.new_11addresscitystzip_c.parentElement.parentElement.style.display='';
    crmForm.all.new_12addresscitystzip_c.parentElement.parentElement.style.display=''; 
    crmForm.all.new_21addresscitystzip_c.parentElement.parentElement.style.display='none'; 
    crmForm.all.new_22addresscitystzip_c.parentElement.parentElement.style.display='none';
    crmForm.all.new_addresscitystzip1_c.parentElement.parentElement.style.display='none'; 
    crmForm.all.new_addresscitystzip5_c.parentElement.parentElement.style.display='none';
    crmForm.all.new_addresscitystzip4_c.parentElement.parentElement.style.display='none';  
    crmForm.all.new_addresscitystzip3_c.parentElement.parentElement.style.display='none'; 
    crmForm.all.new_addresscitystzip6_c.parentElement.parentElement.style.display='none'; 
    crmForm.all.new_addresscitystzip2_c.parentElement.parentElement.style.display='none';
    }
    
    • With CRM 2011 you can leverage the new API, and use it to get the value, the controls, and then hide/show them accordingly using the following technique.

      // Syntax: setVisibilityForMultipleControls(picklist_attribute_name, field1, field2, ...);
      function setVisibilityForMultipleControls()
      {
          // Get the picklist and use it's text instead of the value.
          var picklist = Xrm.Page.data.entity.attributes.get(setVisibilityForMultipleControls.arguments[0]); 
          var number = parseInt(picklist.getText());
          
          var options = picklist.getOptions();
          var i=0;
          for (i=0;i<options .length;i++)
          {
              var optionnumber = parseInt(options[i].text);
              if (isNaN(optionnumber)) continue;
              var j=1;
              for (j=1;j<setVisibilityForMultipleControls.arguments.length;j++)
              {
                  var controlname = setVisibilityForMultipleControls.arguments[j].replace('@',j);
                  var control = Xrm.Page.ui.controls.get(controlname);   
                  control.setVisible(optionnumber<=number);
              }
          }
      }
      

      Then you could add setVisibilityForMultipleControls to the onLoad and onChange with the parameters ‘new_oflocations’, ‘new_addresscitystzip@’, ‘new_stateorprovince@’. Using the @ symbol, it allows the number to be placed anywhere in the field, not just at the end.

      If you were going to do this with sections instead of controls, just replace the var controlname… to (optionnumber<=number); with the following code, using my previous post about visibility.

      var sectionname = setVisibilityForMultipleControls.arguments[j].replace('@',j);
      setSectionVisibility(setVisibilityForMultipleControls.arguments[0],sectionname,(optionnumber<=number)?picklist.getValue():'a');
      

      I think this is a great method of hiding and showing items programatically, and it could easily be modified to show sections, etc., but I can’t help but wonder, why not use a separate entity in this scenario? With CRM 2011 you could use a dialog to walk them through adding all of the information. You could even display the list of addresses, etc. in a sub-grid.

  5. We are trying to replicate a paper form we used and make it dynamic. It may not be all complete on the first time. Would dialogue still work? Also I am not sure what variable I am supposed to define above. Do I tell the function that in this ‘picklist’ if the value is ’1′ hide section1, section2, section3. Sorry just a little confused.

  6. Carlton

    I thought about it over night. Your example above is for multiple controls. I have one control that needs to hide/show multiple tabs based on its value for instance if xrm.page.getAttribute(sectionhide_control) == 1 { Xrm.Page.ui.section.get(section1).SetVisible(true); Xrm.Page.ui.section.get(section2).SetVisible(false); Xrm.Page.ui.section.get(section3).SetVisible(false); }

    then I want to say ….

    if xrm.page.getAttribute(sectionhide_control) == 2 { Xrm.Page.ui.section.get(section1).SetVisible(true); Xrm.Page.ui.section.get(section2).SetVisible(true); Xrm.Page.ui.section.get(section3).SetVisible(false); }

    then

    if xrm.page.getAttribute(sectionhide_control) == 3 { Xrm.Page.ui.section.get(section1).SetVisible(true); Xrm.Page.ui.section.get(section2).SetVisible(true); Xrm.Page.ui.section.get(section3).SetVisible(true); }

    }

    Is this the correct way to do this or will your script do this?

    • To do that you might as well just create a JScript to work that way, instead of linking it to a specific value of a field. I would modify the setSectionVisibility to be more like the code below, then create a script to run the onload conditions for each of the data fields.

      function setSectionVisibility(section, value) {
          var sections = {};
          if (section instanceof Array) {
              sections = section;
          } else {
              sections[0] = section;
          }
          var tabs = Xrm.Page.ui.tabs.get();   
          for(var i in tabs) {   
              var tab = tabs[i];   
              for(var j in sections)
              {
                  var sectionObj = tab.sections.get(sections[j]);   
                  if (sectionObj !== null) {   
                      section.setVisible(value);   
                      if (j==0) return;
                  }   
              }
          }
      }
      
  7. Hi Carlton, great work on the code. I have a few questions pertaining to trying to hide a section:
    A. How do I get the name of the section? Do I just click on the section and grab it from the Section Properties? Vision is the name of the section I want to hide, but just putting Vision in is not seeming to work…
    B. If the checkbox field I am using is zy_vision and I am trying to hide a section when that is not clicked, do I add the function to the onChange (after adding the function to OnLoad) and then from the Event Handler, do I put setTabVisibility as the Function?
    C. And then at this point, do I add the line ‘zy_vision’,'Vision’,0 as the comma seperated list of perameters, where zy_vision is the attribute name, Vision is the display and name of my section and 0 is when zy_vision is not clicked to hide the section?

    • Mike,

      A. You can grab the name of the section from the properties. You need to pass the name in quotes.
      B. The function gets added to an onload if you have changed the field to show up as a checkbox. Such as:
      registerToggle with parameters ‘section’, ‘zy_vision’, ‘Vision’,0
      C. see above.

      Just make sure to retype the quotes incase it does not render properly in your browser.

  8. I love this script, and have started using it frequently. I do have one question about the picklist hiding.
    I have a picklist with 3 options, and a section that needs to be visible for 2 options. Can your code be altered to support more numbers?

    I.E “setVisibility(‘section’,'wwl_accounttype’,'Cost’,2,3);”

    It fails when i do:
    setVisibility(‘section’,'wwl_accounttype’,'Cost’,2);
    setVisibility(‘section’,'wwl_accounttype’,'Cost’,3);

    Here it naturaly only remembers the nr 3:)

    • Ok… You could make it support arrays for the true value. You need to make arrays support contains:

      Here is where the following two methods for arrays were taken from. And below is the code:

      if(!Array.prototype.indexOf) {
          Array.prototype.indexOf = function(needle) {
              for(var i = 0; i < this.length; i++) {
                  if(this[i] === needle) {
                      return i;
                  }
              }        
              return -1;    
          };
      }
      
      Array.prototype.contains = function(obj) {
          var i = this.length;
          while (i--) {
              if (this[i] === obj) {
                  return true;
              }
          }
          return false;
      }
      

      Then you can change the setVisible statements to be more like this:

      section.setVisible(attribute.getValue() == value || (value instanceof Array && value.contains(attribute.getValue())));
      

      Then you could pass it:

      setvisibility('section','wwl_accounttype',[2,3]);
      

      And it will be visible if it is 2 or 3.

  9. Not sure why the registerToggle is unsupported. I thought manipulation of the DOM via JavaScript was allowed?

    • John, it is allowed, but it is not supported for upgradability. The SDK states the following in regards to Form Scripting:

      Microsoft JScript functions that are associated through the customization tools to the available events in the form are supported. Interaction with data in the form is supported when performed using documented objects and methods available within the Xrm.Page.data object. Interaction with the form appearance and behavior is supported when performed using documented objects and methods available within the Xrm.Page.ui object. However, any direct interaction with the HTML Document Object Model (DOM) will probably not be upgradable. The structure of forms and HTML elements used in the forms could change in future releases. For more information, see Write Code for Microsoft Dynamics CRM Forms.

  10. Handy code.

    Can the same not be achieved with CRM 2011′s multiple forms – and then simply select a form that already has the relevant fields.

    Don’t want to wander off-topic too far… but have you got some code to switch forms based on a record type dynamically in OnLoad?

    Don

    • Yes, you can switch forms based on a value: http://social.microsoft.com/Forums/en-US/crmdevelopment/thread/5ba919f7-9f7c-4abf-ba88-224951bb7c11

      var setform = function()
      {
       var currentForm= Xrm.Page.ui.formSelector.getCurrentItem().getId();
       var Information;
       var cType = Xrm.Page.data.entity.attributes.get('my_contacttype').getText().toLowerCase();
       var forms = Xrm.Page.ui.formSelector.items.get();
       var i = 0;
       for (i=0;i<forms.length;i++)
       {
        if (forms[i].getLabel().toLowerCase()==cType) {
         if (currentForm!=forms[i].getId()) {
          forms[i].navigate();
         }
         return;
        }
        if (forms[i].getLabel().toLowerCase()=='information') {
         Information=forms[i];
        }
       }
       if (currentForm!=Information.getId())
       {
        Information.navigate();
       }
      }
      
  11. Carlton,

    Thanks for this. I’m a long time CRM guy, but relatively new to MSFT and definitely a JS newbie. Wondering if you might expand a little on the setNavigationVisibility option.

    I tried to execute this based on a field value, where the field value determines if the nav item should appear or disappear. Unfortunately, I can’t get it to work.

    I am loading the script event twice – once to expose a tab (works perfectly, BTW) and once to check on the nav item. CRM isn’t throwing an error, but it won’t make the nav item appear/disappear as desired.

    Thanks again – I truly appreciate your blog!
    Rick

  12. Hi,

    I’m trying to add java script to hide or show a section within one of my tabs based on a field value from an option set in a different section withing the same tab. (Hope you still follow)

    1x Tab
    2 x Sections

    Option set field in first section dictates if second section appears.

    I tried writing some script but feel i got lost along the way:

    function showSection(sectionName, optionField, optionValue) {
    if (Xrm.Page.getAttribute(optionField).getValue() == optionValue) {
    Xrm.Page.ui.tab.sections.get(sectionName).setVisible(true);
    }
    else {
    Xrm.Page.ui.tab.sections.get(sectionName).setVisible(false);
    }
    }

    Passing the following parameters on my field new_incidenttype :

    Test, “new_incidenttype”, ’100,000,001′

    Test = Section Name
    “new_incidenttype” = Field Name
    ’100,000’001′ option set number.

    Can anyone help and point me to where i am going wrong?

 Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>