Mass Action on Table Conditionally available


Hi Guys,

Is there a way to conditionally enable or to dynamically insert/remove a mass action into table? In our example we have a mass action “Send to DrawLoop” on a client list which does as described. It’s wonderful. The problem is that not all of our clients use DrawLoop, some use Conga, and some don’t do document generation.

For Conga clients we obviously want a different “Send to Conga” action, and for clients that don’t do document generation we don’t want anything.



Hi Dan,

One idea that comes to mind is to use an OnLoad script that keys on the “nx-actionselect-dropdown-item” class and removes the unwanted items.  This means that your script would have to know which doc gen software is available,

Irvin

I was hoping that all that was needed was to add the proper XML in the right place. No dice. Seems like an obvious place to put conditional rendering.

Agreed.

Hi Dan -

Unfortunately, there is no declaritive way to approach. There has been discussion in the community regarding adding conditional rendering to more areas (e.g. table columns, table row actions, etc.) and this would be another logical place for conditional rendering.

Here’s the options as I see them:

  1. Create separate tables and conditional render - Less than ideal for obvious reasons
  2. Wait for conditional rendering of mass actions - Skuid team is awesome at cranking out new features but I’m guessing you need something now
  3. Write your action as a snippet if possible - You could have the action text be “Create Document” (or try using merge syntax to get the proper name) and then your snippet could approach the document creation in another way based on which type (Conga, loop, etc.) it should use. The downside to this approach is that your use case indicates that in some situations there would be no “Create Document” option. This would leave an action in the mass actions list that you’d have deal with in your snippet and display a message like “Sorry, your installation doesn’t support this.” If every installation had doc creation, this would likely be viable approach but given your situation, this approach too is less than ideal.

The good news is that there is a way to do this although it does require some code and would be an unsupported approach from Skuid more than likely. If that doesn’t scare you, read on… :slight_smile:

Irvin is on the right path with the nx-actionselect-dropdown-item and manipulating the DOM. Unfortunately, this has a shortcoming and won’t work on document ready. The reason is that Skuid is “smart” about when it renders DOM elements - it won’t until they are needed. This means that the nx-actionselect-dropdown-item elements won’t appear until after the user selects a row and if even then, not until they click the arrow in the massaction button if you have more than one mass action will all items be rendered in the DOM. Once they are rendered the first time, they are just shown/hidden are needed. If they were there to begin with, in document ready you could do something like the following:

// find the table, then the header, then the mass actions, then the dropdown container and then
// each drop down item
// you could shorten this to just look in the entire DOM for .massactionconga
$(‘#docTable’).children(‘.nx-editor-header:first’).children(‘.nx-massactions:first’).children(‘.nx-actionselect-dropdown:first’).children(‘.nx-actionselect-dropdown-item’).find(‘.massactionconga’).remove()

A way around the “late rendering” of these would be to register a DOM mutation observer. You could listen for any element inserted to the DOM that has nx-actionselect-dropdown-item class and remove it if it doesn’t meet your criteria. There are two downsides to this:

  1. Depending on which browsers you support, DOM mutation observers are rather new and only supported in modern browsers. Older browsers implemented mutation events and let’s just say you don’t want to go there (e.g. terrible performance as they are synchronous).
  2. If you would end up with no available actions after removing some or if the one you want to remove is the default mass action, things would get rather difficult to manage properly in the UI.

Ok, enough of what you don’t want to do, let’s get back to a way you could do this. Again, this would be an unsupported solution but it should work for what you need.

In order to handle all scenarios, you need to modify the xmlConfiguration for your table at runtime and before the table itself gets rendered. When the table is rendered, the drop down items aren’t added to the DOM but the skootable object builds its internal data structures to “prepare” for everything. So what we need to do is remove the mass actions from the configuration so that the skootable doesn’t even know they were there in the first place.

Here’s how to do it:

  1. Create a custom component that manipulates the XML configuration of the table removing the ones you do not want
  2. Place the custom component on the page BEFORE the table - This is critical because we must manipulate the table configuration before the table starts to use it during it’s rendering process
  3. Each mass action in your table should have a special “uniqueid” This is accomplished via the “Action Icon” property.

The sample page below demonstrates all that you should need. This should handle situations where the mass action uses the first item as a default and when it doesn’t use the first. It should also handle situations where you end up with no actions left after removing the items.

Here’s the table definition from the builder - note two mass actions and the extra “Action Icon” for each of them.

Here’s the finished product - Note only Conga shows up

And here is the sample page

<skuidpage unsavedchangeswarning="yes" tabtooverride="Account" showsidebar="true" showheader="true">   <models>
      <model id="Account" limit="100" query="true" createrowifnonefound="false" sobject="Account">
         <fields>
            <field id="Name"/>
            <field id="CreatedDate"/>
         </fields>
         <conditions/>
         <actions/>
      </model>
   </models>
   <components>
      <pagetitle model="Account">
         <maintitle>
            <template>{{Model.labelPlural}}</template>
         </maintitle>
         <subtitle>
            <template>Home</template>
         </subtitle>
         <actions>
            <action type="savecancel"/>
         </actions>
      </pagetitle>
      <custom name="updateMassActions"/>
      <skootable uniqueid="docTable" model="Account" mode="read" createrecords="true" pagesize="10" showexportbuttons="false" searchbox="true" searchmethod="server" showsavecancel="false" showconditions="true" buttonposition="">
         <fields>
            <field id="Name" allowordering="true"/>
            <field id="CreatedDate" allowordering="true"/>
         </fields>
         <rowactions>
            <action type="edit"/>
            <action type="delete"/>
         </rowactions>
         <massactions usefirstitemasdefault="false">
            <action type="multi" icon="ui-silk-printer massactionconga" label="Create a Conga Document">
               <actions>
                  <action type="blockUI" message="Creating with Conga..." timeout="1000"/>
               </actions>
            </action>
            <action type="multi" icon="ui-silk-printer massactionloop" label="Create a Loop Document">
               <actions>
                  <action type="blockUI" message="Creating with Drawlooop..." timeout="1000"/>
               </actions>
            </action>
         </massactions>
         <views>
            <view type="standard"/>
         </views>
         <searchfields/>
      </skootable>
   </components>
   <resources>
      <labels/>
      <css/>
      <javascript>
         <jsitem name="updateMassActions" url="" cachelocation="false" location="inline">// jquery shortcut
var $ = skuid.$;
// helper to evaluate whether Conga is supported
var shouldShowConga = function() {
    // could lookup value in a model here or any other evaluation criteria
    return true;
};
// helper to evaluate whether Loop is supported
var shouldShowLoop = function() {
    // could lookup value in a model here or any other evaluation criteria
    return false;
};
// build an object with key/value pair for each of the classes that we put
// on the icon of the mass row action
// the value of the key will be true/false depending on whether or not it should display
var massactions = { 
        massactionconga: shouldShowConga()
        , massactionloop: shouldShowLoop()
    };
// register a skuid component called updateMassActions
skuid.componentType.register('updateMassActions', function(domElement, xmlConfig, component) {
    // locate the parent node of this component's configuration
    var parentElement = xmlConfig.context.parentNode;
    // locate any skootables that have uniqueid of docTable - there should only be one since it's a unique id
    // if you had multiple you could use the cssclass property instead of unqiueid adding the same cssclass to each table you want to evaluate
    $(parentElement).children('skootable[uniqueid="docTable"]').each(function(index, docTableComponent) {
        // for each mass action
        $.each(massactions, function(key, value) {
            // if false then remove the action from the configuration
            // note that we look for the attribute 'icon' where the value 'contains' our special icon class
            if (!value) {
                $(docTableComponent).children("massactions").children('[icon*="' + key + '"]').remove();       
            } 
        });
    });
    
    // hide ourself since we don't have a UI
    domElement.css('display', 'none');
});</jsitem>
      </javascript>
   </resources>
</skuidpage>

Brilliant solution and well documented. It works like a charm.

Thank you.

Glad it worked for you Dan!

Happy to announce that Conditional Rendering will be added to Table Mass and Global Actions in the next major release of Skuid!

That’ll be when’ish?

Summer.

Hey Zach - Great news, will save a lot of custom dev during page development.  Any chance the conditional rendering will be added to table columns or if not in summer release, is it on the roadmap?  Thanks!

Barry, unfortunately can’t give any updates on Table Column conditional rendering. Definitely on the roadmap, but can’t promise anything right now for summer release.

Understood Zach, appreciate the update and glad to hear its on the roadmap.

Hey Zach -  Ran in to a use case where be able to conditionally render table filters.  Any chance that this is on the docket along with mass/global actions?

The use case is as follows - Table built to generically support a list of records from an object and provide several filters.  In certain situations, the exact same table is needed but one or more fields should have a fixed filter value passed in querystring param.

Thanks!