Skip navigation
All Places > Getting Started > Blog
1 2 3 Previous Next

Getting Started

459 posts

For a long time, we have been plagued by times in InfoPath forms jumping forward by an hour during daylight saving time after amending the metadata fields.

Investigation shows that the datetime value written back to the form contains a modifier telling SharePoint that the time is recorded as being GMT (and thus an hour needs to be added to make it ‘correct’ again).

Date field in InfoPath form

<my:StartDate>2018-05-23T00:00:00Z</my:StartDate>

The solution was to use Nintex to create a workflow that rewrites the date fields after change to remove the ‘Z’ character.

The workflow could either run on any change – or fine tune it to run only when one of the affected fields change value

The action is to

  • Retrieve the field value from the xml document
  • Test if it contains a ‘Z’
    • If it does, write it back without the ‘Z’

As it runs immediately after a change, it is worth starting the workflow with a ‘Commit pending changes’

The first step is to read the xml document associated with the current item, so insert a Query XML task – ensure the source is the Current Item; return the result as Text, to a temporary string variable

In the Output, set ‘Process using’ to XPath and click the XPath Builder button and navigate through your form’s xml to the field

When you reach it, select it and click the Apply button and something like this will be returned

 

Now test strTest in a Run If

Within the Run If, add an Update XML task

You can copy/paste the field reference from the Query XML task

You then replace the node content with the item value for the field, replacing the ‘Z’ with a blank

Note that the FormatDate function returns the date/time in the same format as that stored within the xml.

Now repeat this for each affected field.

I have been assigned to do Sharepoint, already set up all the needed things. WF. But have query if Auto-ID can be a link to item. I need to have the ID to be clickable like Context ID Display Name. 

 

Any help is much appreciated.

 

Thank you

graham

Nintex Workflow – Fast Loops

Posted by graham Jun 12, 2018

Recently I needed to create a schedule of dates, one week apart. I created a loop and added 7 days in each iteration. I noticed it took a very long time, so I added a Log in History task in the loop and saw that each iteration was taking 5 minutes. I realized that this was down to ‘Safe Looping’.

This protective feature places some safety measures against the hazards of an infinite loop by adding a hidden delay..

I didn’t want to disable this option, mainly because of the maintenance overhead involved, so I looked for another option.

I realised that the Collection iteration (For Each) didn’t have any such restriction, so all I needed was to create a collection with the number of entries that I wanted to loop for.

The Regular Expression task with the Split operator is the easiest way to create a collection; it simply splits text based on a character. All I had to do was to create a string with the right number of delimiters.

This is where I got the idea for this article https://community.nintex.com/community/build-your-own/blog/2018/06/08/nintex-string-repeat.

Now, as n delimiters will create n+ 1 entries, we need to reduce the number of delimiters by 1

Initialising the string to a non-delimiter will ensure that the string is padded to length ‘Iterations’ containing n-1 delimiters.

Regular Expression

For each

 

We place the retrieved value in TempStr variable and ignore it.

Calculate date:

Here’s where we add the recurrent +7 days added on each loop

The final workflow

 

 

I set the Iterations variable to be a startup parameter and set it to 10

Here are the results from the history - as you can see, it all executed immediately

 

Time

Event

Message

11/05/2018 10:49

Workflow Comment

MyDate=18/05/2018 10:49

11/05/2018 10:49

Workflow Comment

MyDate=25/05/2018 10:49

11/05/2018 10:49

Workflow Comment

MyDate=01/06/2018 10:49

11/05/2018 10:49

Workflow Comment

MyDate=08/06/2018 10:49

11/05/2018 10:49

Workflow Comment

MyDate=15/06/2018 10:49

11/05/2018 10:49

Workflow Comment

MyDate=22/06/2018 10:49

11/05/2018 10:49

Workflow Comment

MyDate=29/06/2018 10:49

11/05/2018 10:49

Workflow Comment

MyDate=06/07/2018 10:49

11/05/2018 10:49

Workflow Comment

MyDate=13/07/2018 10:49

11/05/2018 10:49

Workflow Comment

MyDate=20/07/2018 10:49

 

 

graham

Nintex String-Repeat

Posted by graham Jun 8, 2018

I recently needed a String-Repeat function in a workflow. But it doesn’t exist.

Or does it?

Looking at the inline function specifications, I saw that the PadLeft function (and PadRight) adds a number of characters to a string, until the string length is the desired number of characters long.

If you needed just a specific number of characters (lets say ‘-‘ chars), then the following

fn-PadLeft(-,15,-)

 

Will result in a string of 15 ‘-‘ characters

Now, you cannot tell it to pad out with a string of more than 1 character (it actually returns the text of the function definition when you try), so you need to be a little more clever to give a string of 15 repetitions of ‘Graham’ for example

We create a string of 15 ‘-‘ characters then replace each ‘-‘ with the longer text that we want to repeat in a RegEx task.

Hi All

 

How to Update Multiple Values Select Lookup ?

    We can Update Multiple Values Select Lookup column using REST API in Nintex Workflow

Why Rest ?

   When you are using SharePoint Default Update  Action to update, you will get below error, to avoid this we have use REST API 

 

Error Detail  When use Update List Item Action

 

{"error":{"code":"-1, Microsoft.SharePoint.Client.InvalidClientQueryException","message":{"lang":"en-US","value":"A 'PrimitiveValue' node with non-null value was found when trying to read the value of a navigation property; however, a 'StartArray' node, a 'StartObject' node, or a 'PrimitiveValue' node with null value was expected."}}} Bad Request

 

about  this error you may heard, like Microsoft bug or Nintex  bug we cannot update multi select lookup column in SharePoint online Etc

but  We Can Update 

here you can get the solution for that,

using REST API we can update the Multi select lookup column.

 

 Key Point are 

1)Pass value in array  =  [21,42]

2)Column name id      =  ColumnNameId

 

Step by Step 

 

1) Build metadata with you List/Library  SP.Data.AssetsLibraryItem ( for Library) or SP.Data.AssetsLibraryListItem   ( for List)

 

 

2) Pass your Multi Select Value ID in to the Text Variable

 

3)Get Value in Dictionary Variable "here the out put Result is a dictionary Variable"

 

 

4) Pass the Value in to you column name ID   Ex "ColumnnameId" the Key value should be  "Columnname+Id "

 

 

5) usual Update Merge Method , get this in to Request Header 

 

6 Finally {Workflow Context:Current site URL}_api/web/lists/GetByTitle('Listname')/items({Variable:GetID}) with Post Method 

 

That is it, all good,  Enjoy.......

graham

Workflow Approvals Dashboard

Posted by graham Jun 5, 2018

This article is not strictly Nintex, as it could apply to any workflow engine.

We manage our Change Control process using InfoPath forms and Nintex workflow.

For a management overview and reminder for when approval request emails are missed, we needed a dashboard page that would show all outstanding approvals and those assigned to the current user.

Two methods were identified to provide this functionality – the Nintex webparts and custom list views of the WorkflowTasks list.

This is a summary of our requirements

Requirement

Nintex Webpart

Custom Listview

Display the ID of the item being approved

N

N

Link the item being approved to open in the browser

Y

N

Group all approvals for each item

N

Y

Ability to Approve from the page

Y

Y

Ability to Delegate from the page

N

Y

 

Whilst the Nintex webpart allows the current user to respond to a task if s/he is the one to whom the task was assigned, the Terminate Workflow option is visible and could cause problems - and the Delegate user was not available at al.

Our first attempt to solve this was to add a column to the WorkflowTask list and have a workflow paste in the relevant information each time a task was created. Big mistake – we had no end of ‘Task is locked by a workflow’ errors and resulted in delays of hours before an approval could be given.

Returning to the List Views, because the views are grouped, we did not want the name of the grouping field to be repeated in each group, so we used the JScript found here -> http://bistesh.blogspot.co.uk/2014/04/sharepoint-20132010-remove-columns-name.html and added it to a CEWP. We used this code as a basis to edit the url of the Related Content to use the InfoPath form server.

It also amends the standard message:

'There are no items to show in this view of the "Workflow Tasks" list. To add a new item, click "New".'

To show

'You have no outstanding approvals'

 

We wanted to be able to show the ID of the related content.

Research indicated that SP 2013 held a field called WorkflowItemId – a Content Query webpart (CQWP) was created using the debugging style to retrieve a field of this name and found it existed in SharePoint 2010 and was populated with the ID value.

Debugging XSLT

<xsl:template name="debugCustomStyle" match="Row[@Style='dCustomStyle']" mode="itemstyle">

<!-- shows all the fields supplied and their names  -->

<xsl:for-each select="@*">

F:

<xsl:value-of select="name()" />

=

<xsl:value-of select="." />

+

<br />

</xsl:for-each>

<xsl:call-template name="repeatstr">

<xsl:with-param name="num" select="20" />

<xsl:with-param name="str" select="'-'" />

</xsl:call-template>

<br />

<!-- shows all the nodes supplied and their names  -->

<xsl:for-each select="//*">

F:

<xsl:value-of select="name()" />

=

<xsl:value-of select="." />

+

<br />

</xsl:for-each>

<xsl:call-template name="repeatstr">

<xsl:with-param name="num" select="50" />

<xsl:with-param name="str" select="'='" />

</xsl:call-template>

<br />

</xsl:template>

 

The Property CommonViewFields of the webpart source was set to include all the wanted fields (it is imperative that the case matches the definition, otherwise it will not be recognised).

<property name="CommonViewFields" type="string">Title;WorkflowName;WorkflowLink;AssignedTo;Related Content;WorkflowListId;WorkflowItemId</property>

The next thing was to show it in the view – this field is not selectable as it is hidden. The answer was to export the ListView webpart (see Export a List Webpart at the end) and edit the embedded view

<property name="XmlDefinition" type="string">&lt;View Name="{CE1736B1-205B-42D4-99B6-AE5D5F723D18}" MobileView="TRUE" Type="HTML" Hidden="TRUE" TabularView="FALSE" DisplayName="" Url="[redacted]" Level="255" BaseViewID="1" ContentTypeID="0x" ImageUrl="/_layouts/images/issues.png"&gt;&lt;Query&gt;&lt;GroupBy Collapse="FALSE" GroupLimit="30"&gt;&lt;FieldRef Name="WorkflowItemId"/&gt;&lt;/GroupBy&gt;&lt;OrderBy&gt;&lt;FieldRef Name="WorkflowItemId" Ascending="FALSE"/&gt;&lt;FieldRef Name="AssignedTo"/&gt;&lt;/OrderBy&gt;&lt;Where&gt;&lt;Eq&gt;&lt;FieldRef Name="WorkflowOutcome"/&gt;&lt;Value Type="Text"&gt;Pending&lt;/Value&gt;&lt;/Eq&gt;&lt;/Where&gt;&lt;/Query&gt;&lt;ViewFields&gt;&lt;FieldRef Name="WorkflowItemId"/&gt;&lt;FieldRef Name="WorkflowLink"/&gt;&lt;FieldRef Name="WorkflowName"/&gt;&lt;FieldRef Name="Created"/&gt;&lt;FieldRef Name="AssignedTo"/&gt;&lt;FieldRef Name="LinkTitle"/&gt;&lt;/ViewFields&gt;&lt;RowLimit Paged="TRUE"&gt;30&lt;/RowLimit&gt;&lt;Aggregations Value="Off"/&gt;&lt;ViewStyle ID="17"/&gt;&lt;Toolbar Type="None"/&gt;&lt;/View&gt;</property>

 

When html un-encoded and reformatted, it looks like this

<View Name="{CE1736B1-205B-42D4-99B6-AE5D5F723D18}" MobileView="TRUE" Type="HTML" Hidden="TRUE" TabularView="FALSE" DisplayName="" Url="[redacted]" Level="255" BaseViewID="1" ContentTypeID="0x" ImageUrl="/_layouts/images/issues.png">

   <Query>

     <GroupBy Collapse="FALSE" GroupLimit="30">

         <FieldRef Name="WorkflowItemId" />

     </GroupBy>

     <OrderBy>

         <FieldRef Name="WorkflowItemId" Ascending="FALSE" />

         <FieldRef Name="AssignedTo" />

     </OrderBy>

     <Where>

         <Eq>

           <FieldRef Name="WorkflowOutcome" />

           <Value Type="Text">Pending</Value>

         </Eq>

     </Where>

   </Query>

   <ViewFields>

     <FieldRef Name="WorkflowItemId" />

     <FieldRef Name="WorkflowLink" />

     <FieldRef Name="WorkflowName" />

     <FieldRef Name="Created" />

     <FieldRef Name="AssignedTo" />

     <FieldRef Name="LinkTitle" />

   </ViewFields>

   <RowLimit Paged="TRUE">30</RowLimit>

   <Aggregations Value="Off" />

   <ViewStyle ID="17" />

   <Toolbar Type="None" />

</View>

 

This makes it a lot easier to read, understand and amend – this will need to be re-edited to remove unnecessary whitespace and carriage returns, then html encoded (or the tag can be set up to be a CDATA entry).

I recommend that you use the field Status as a substitute field, then find/replace it with WorkflowItemId – this should prevent errors when editing the encoded xml.

So the new field WorkflowItemId is added to the view fields and used as the Group By value.

After the webpart(s) have been re-uploaded, if you Edit Webpart and Edit current view, the fields will appear in their correct locations.

The My Approvals – with no assigned approvals

All Approvals

The full jscript is shown here

_spBodyOnLoadFunctionNames.push("HideHeaders");

 function HideHeaders() {   

    var elem;   

    var elements = getElementsByClassName(document, "td", "ms-gb");

    for (var i = 0; i &lt; elements.length; i++) {

        elem = elements[i];

        elem.childNodes[0].childNodes[1].nodeValue = "";

        elem.childNodes[1].nodeValue = elem.childNodes[1].nodeValue.replace(':', '');

        elem.childNodes[2].href="/_layouts/formserver.aspx?xmllocation=" + elem.childNodes[2].href + "&openin=browser";

        elem.childNodes[2].target="_blank";

   }

   

    elements = getElementsByClassName(document, "td", "ms-vb2");

    for (var i = 0; i &lt; elements.length; i++) {

        elem = elements[i];

        if (elem.childNodes[0].nodeName == 'A') {

            elem.childNodes[0].href="/_layouts/formserver.aspx?xmllocation=" + elem.childNodes[0].href + "&openin=browser";

            elem.childNodes[0].target="_blank";

       }

   }

   

    elements = getElementsByClassName(document, "td", "ms-vb");

    for (var i = 0; i &lt; elements.length; i++) {

        elem = elements[i];

         if (elem.childNodes[0].nodeValue == 'There are no items to show in this view of the "Workflow Tasks" list. To add a new item, click "New".') {

            elem.childNodes[0].nodeValue='You have no outstanding approvals';

       }

   }

}

 

/*

Written by Jonathan Snook, http://www.snook.ca/jonathan

Add-ons by Robert Nyman, http://www.robertnyman.com

*/

function getElementsByClassName(oElm, strTagName, strClassName) {

    var arrElements = (strTagName == "*" && oElm.all) ? oElm.all : oElm.getElementsByTagName(strTagName);

    var arrReturnElements = new Array();

    strClassName = strClassName.replace(/\-/g, "\\-");

    var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");

    var oElement;

    for (var i = 0; i &lt; arrElements.length; i++) {

        oElement = arrElements[i];

        if (oRegExp.test(oElement.className)) {

            arrReturnElements.push(oElement);

       }

   }

    return (arrReturnElements)

}

 

 

Export a List Webpart

You want to export the list webpart to your pc, to upload on a different site/page or edit it, but the export webpart option is not available.

 

This is where we get funky …. Still in edit page mode, in the browser toolbar, click Tools | F12 Developer tools. Now select the area on the page holding the webpart

 

Search for the text allowExport within the html

See the =false after it, double-click on it and change that to true

Now the Export option is available on the webpart

 

Save it to the pc, then you can edit it and Add webpart and upload the saved one

Applies to: Nintex for SharePoint 2016 and 2013

 

For the farm administrator:

  • Transport Layer Security (TLS) protocol 1.0 and 1.1, which is supported by default in Nintex Workflow for SharePoint 2016 (and 2013), is no longer compatible with the Start workflows with Nintex Workflow Cloud action.
  • TLS1.2 is now required to start workflows with this action. You can opt in for TLS 1.2 even if your application framework doesn't support it.


To use TLS 1.2, follow these steps (all servers):

  1. Create a text file with a .reg extension and the following contents:
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319]
    "SchUseStrongCrypto"=dword:00000001
    [HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319]
    "SchUseStrongCrypto"=dword:00000001
  2. Double-click the .reg file install, then restart the SharePoint Timer Service and IIS.

 

For more information, see Microsoft articles:

How to add Save as Draft button functionality and users can modify their own items? 

  1. Please follow this post for Save as Draft button functionality, thanks Dan Stoll for wonderful post.
  2. Under Version settings, set "Content Approval" to Yes and set "Draft Item Security" to "Only users who can approve items (and the author of the item) ". This would help us to hide own draft item from others.  
  3. Under Advanced Settings Set Item Level permissions to "Create items and edit items that were created by the user".
  4. Now Build you Nintex Form by adding two Calculated fields and Save as Draft button.
  5. Set 1st Calculated field Value 
  6. Set 2nd Calculated field Value to  [if IE 9]  [endif] 
    userProfileLookup(Current User, "PreferredName") 
  7. You many hide both these fields under banner by using "bring to front" functionality.
  8. Add Set as Draft button
  9. Add rule and set on 'Save as Draft' and 'Save and Submit' buttons and set following condition - 
  10. Save these changes and publish it. 
  11. Create the workflow for the list.
  12. Add 'Set a Condition' action and set condition 'If Draft field value is equal to Yes' 
  13. If action value is NO add 'Set Approval Status' action to Approved.
  14. Add End Workflow action.
  15. Save these changes and publish it. 
graham

Day of the Week Number

Posted by graham May 29, 2018

Many people have requested a method of finding the date of the Monday in a week.

I have seen several quite complex solutions, but then I read this post https://community.nintex.com/thread/11519 and realised it is a trivial matter.

Firstly, create a collection of the 3-letter day abbreviations (this should be done for your current locale, for other locales use the appropriate 3-letter day name abbreviations) and should be in uppercase. The easiest way is to use a Regular Expression and split

MON;TUE;WED;THU;FRI;SAT;SUN

around the ‘;’ character.

Regex - Split

Then add a collection operation that tests if fn-ToUpper(fn-FormatDate(DoWDate,ddd)) exists in the collection of days, returning the result in a number variable DoWNum.

Collection operation

If you now subtract DoWNum from the given ‘DoWDate’, you will have the Monday date.

We have worked in a solution for the annually employee’s performance review process. The whole solution is powered by Nintex Technologies for SharePoint 2010 (I know, caveman here, sorry!), but that was not even the worst part. We faced few problems related to the fact that the form was pretty large and some users will need to have the form opened for a long period of time - typically during a manager/employee meeting that can last one or two hours. The issue is that SharePoint, by default, has the form digest value set to 30 minutes. This means that after this period, when one attempts to submit the form, the user will receive a nasty error message and will lose of all the data entered. This is a terrible situation and in this article, I will try to suggest two functionalities that combined can offer a way better user experience:

  • “Save”, “Save and Submit” and validation rules: Apparently with NF 2013 version and higher, the “Save and Continue” would do the job, but for 2010 we need to take the longer journey. On this must read post, Vadim Tabakman  explains pretty well the solution at the workflow level: http://vadimtabakman.com/nintex-forms-save-or-submit.aspx , but at the form level, “save” should ignore the validations and “save & submit” should apply the validation rules. That’s exactly what I will try to handle on the first part of this article.
    Note that the "Causes Validation" property is only supported for JavaScript button types

    After following the steps described on the Part I of this article, the form should handle “save” (ignoring the validation rules) and “save & submit” (applying the validation rules).

  • Keep form data alive: The “Save” button will give the possibility to save your form, but the user will have to do that every 30 minutes. In addition, the form will get closed after clicking on “Save”. Not handy at all. On this article http://www.ashu-tosh.com/2017/01/nintex-forms-implementing-auto-save.html Ashutosh describes an approach for  auto saving the form, but saving kicks the validation rules which could be a problem (addressed on the part of my article) and the form is closed after saved. While it is good that the work is automatically saved, the user will have to open the form again and continue with the editing.  What if we don’t wanna save, but continue to work on the form without interruption (well, with a minor post back interruption)? That’s what is addressed on the second part of this article.

 

Part I - Save, Submit and validation rules

 

1 – Create a textbox and name it Validate – add this anywhere in the form as this control will be hidden at the end.

2 – Set the textbox properties - set the default value to 0 and the Data Type to Integer. On the advanced tab, click make sure to set “yes” to the “Store Client ID in JavaScript variable” to yes and name the variable, like varValidate.

3 – Change the labels for the “Save” and “Save & Submit” buttons to “Save Backend” and “Submit Backend” respectively. Also change the css class to be saveButton and submitButton.

4 - Move these buttons to another area of the form, as they will be hidden at the end. Then create two new buttons “Save” and “Save and Submit”, but change the button action to be “JavaScript” for both of them. Those are the buttons that will be shown to in the form.

5 – Here is where we will do the logic with the Validate control. Basically we want to allow our users to Save or Save & Submit (our backend buttons), but we want to change the validate control (flag) on or off. So, the save button will change the value of the Validate control to 0 and then call the click event for the Save Backend button by using JavaScript.

The very same logic should be applied to the Submit button, but with a reference to the submitButton class on the Client Click.

NWF$("#" + varValidate).val(1);NWF$('.submitButton').click();

 

6 – Now we need to change our validation rules to consume the Validate flag. For exemplo, if you have a validation rule like…

 

You will need to add the “and” function and get check if the value of the validate control is equal to 1.

We will have to change each and every validation rules in the form in the same way.

 

7 – The very last part is to make sure the Validate, Save Backend and Submit Backend are hidden. Note that if you try to change the visible property to false, you will have an error because the control needs to exists as HTML element because it will used on the JavaScript code. So, we can just create a "HideAlways" Formatting rule.

And apply to the Save Backend, Submit Backend and Validate controls, by selecting them and choose “Add to selected controls”


 

Part II - Keep form data alive – auto form session renewal

 

 

1 – Add a button to the form in any location as it will be hidden at the end. Set the Button Action to “JavaScript” and change the CSS class to “AutoRefreshButton”.

In “Advanced”, for the Client Click, add the following piece of JavaScript code:


NWF$(this.form).submit();

 

So, the control settings should look like the image below:

2 – The end result will be that from time to time a post back will be fired and the page will be loaded again. We want to present to the users how long time it will take until the session is refreshed with a countdown. For that we need to add a text box control and a label control “form session renewal in”:

For the TextBox control we need to set “Store Client ID in JavaScript variable” to Yes and give the variable name “varSessionCountdown”

3 – We need to make sure that the AutoRefresh button (step 1) is "clicked" after (mins) minutes. So, in the form settings, add the following JavaScript:

 

 

var mins = 28;

var secs = mins * 60;

var currentSeconds = 0;

var currentMinutes = 0;

NWF$(document).ready(function () {

    SetAutoFormRefreshTimer();

});

function SetAutoFormRefreshTimer() {

    if (Is New Mode || Is Edit Mode )

    {

        setTimeout('Decrement()', 1000);

    }

}

function Decrement() {

    currentMinutes = Math.floor(secs / 60);

    currentSeconds = secs % 60;

    if (currentSeconds <= 9) {

        currentSeconds = "0" + currentSeconds;

    }

    secs--;

    //Set the element id you need the time put into

    NWF$("#" + varSessionCountdown).val(currentMinutes + ":" + currentSeconds);

    if (secs > -1) {

        setTimeout('Decrement()', 1000);

    }

    else {

        isFormSubmittedAlready = NWF$('.AutoRefreshButton').is(':disabled');

        if (!isFormSubmittedAlready) {

            NWF$('.AutoRefreshButton').click();

        }

    }

}

 

Note: Remember to replace the  "Is New Mode" and "Is Edit Mode" in the code with the proper references:

 

4 – The very last part is to hide the Auto Refresh Button and for that we can use the rule HideAllways mentioned on the step 7 of the first part of this post. You may also want to hide the controls related to the counter when in display mode. For that, just applied the rule below on the selected controls.

For testing, change the "mins=28" to "mins=1" and take it for a spin. 

 

That’s all folks! Happy Nintexing!


( developed for SP2013 on-prem, Nintex forms 2.10 )


This code was inspired by nmarples whose amazing blog post can be found here. He lifts the curtain on the Nintex rules engine and shows the power of combining Javascript with rules, providing clues to this realtime validation concept.

You can implement this solution right away on any form control without any additional configuration, cut and paste as shown below using these 4 simple steps;

 

1) make sure each form field control is named and the label is associated with the control:

 

2) paste this CSS in the form's Custom CSS setting:

 

.lp-border-red {
  background-color : rgba( 255,0,0,.2 );
}
.lp-border-yell {
  background-color : rgba(255,255,0,0.3);
}
.lp-border-grn {
  background-color:rgba(0,255,0,0.3);
}

 

 

3) paste this Javascript in the form's Custom JavaScript setting:

lpForm = {

 Validate: function( formControlCall, sourceContext, required, isValid ) {
  // Obtain the internal element input name.
  var formControlID = formControlCall.split( "'" )[1] || "";
  var internalElement = sourceContext.find( "[name^='ctl'][formcontrolid='" + formControlID + "']" );
  // During initial load, people control is a placeholder, no internalElement exists yet, so bail, validation will succeed later
  if ( internalElement.length == 0 ) return;
  var internalElement_name = internalElement.attr( 'name' );
  // Scrub the name.

  var intext = internalElement_name;
  var outtext = intext.split( '$' ).join( '_' );
  // Obtain the label associated for-name of internal element.
  var labelBorder = NWF$( "[for^='" + outtext + "']" )
    .closest( '.nf-filler-control-border' )
    .parent();
  // Required missing.
  if( required && isValid ) labelBorder
    .addClass( 'lp-border-red' ).removeClass( 'lp-border-yell' ).removeClass( 'lp-border-grn' );
  // Optional missing.
  if( !required && isValid ) labelBorder
    .addClass( 'lp-border-yell' ).removeClass( 'lp-border-red' ).removeClass( 'lp-border-grn' );
  // Not missing.
  if( !isValid ) labelBorder
    .addClass( 'lp-border-grn' ).removeClass( 'lp-border-yell' ).removeClass( 'lp-border-red' );
  return isValid;
 },
};

 

4) paste this expression into a new rule for each form field you wish to validate

 

( function( formControlCall, isValid ) { lpForm.Validate( formControlCall, sourceContext, true, isValid ) }( "{Control:Self}", {Control:Self} == '' ) );

optional : inside the expression, change true to false to change the field from required to optional

note : in the Condition window {Control:Self} will format itself to appear as {Self} once saved 

 

Done - Enjoy!


 

TL;DR Explanation

 

The above code is a prototype created in an afternoon. There are probably some edge cases that may require additional coding, but this appears to be suitable for all basic form controls.

 

The 3 important concepts from nmarples that he shares in his blog post are:

  • The Rule's Condition expression is evaluated as Javascript. ( This means you can point to any Javascript function in the Condition window and it will be executed )
  • You can pass to your function, both, a reference to the current control as a string parameter
    "{Control:Self}"
    and pass the resulting expression as a boolean parameter
    {Control:Self} == ''
    Nintex Runtime Functions this expression is the same as isNullOrEmpty({Control:Self})
  • During the OnChange event the function and parameters be executed in an IIFE ( what's an IIFE? Google it, it's useful… )

 

CSS

3 classes are used to set the associated control back-grounds to red, yellow or green.

 

Form JavaScript

lpForm : creates a unique namespace where I can safely use any name for my function.

Validate : takes 4 parameters.

formControlCall : a reference to the currently active control
sourceContext : a reference to the context of the DOM
required : true or false ( whether this form field is required or optional )
isValid : true or false ( the result of the provided validation expression - already evaluated )

 

The process of the function

  1. Navigate the DOM to locate the current control's internal element name, it usually looks like: 
    ctl00$PlaceHolderMain$formFiller$FormView$ctl26$ctl16$ac5d43fc_51e7_4d06_b3e8_150731c4bac9
  2. Scrub this name to replace "$" with underscores.
  3. Use the name to locate the associated label control - the label uses an attribute named for.
  4. Locate the parent-border control of the labels.
  5. Use .addClass.removeClass to set the label parent-borders to the appropriate CSS class ( background-color )

IIFE

The immediately-invoked function expression gathers the following run-time provided parameters:

a reference to the current control : "{Control:Self}"

and a the validation expression : {Control:Self} == ''

So the IIFE evaluates these two parameters and passes results into the interior function, were all four parameters get passed to the base Validation function.  Then the base function Validation ultimately returns back the isValid boolean, which could be consumed by the Rule too.

My requirement is to get all o365 users.

I tried two approches:

1) I followed the approach calling service through 'call http service' action but i got an empty results.

(Reference : https://community.nintex.com/message/25149)


2) I used 'o365 search query' action to get all users.

But couldnot get all the users in the response and not able to parse the XML response.

can you please help me out getting all the Users...?

Hi there, folks!

 

You may recall this blog post from a while back by Sean Fiene -- it's a great write-up on how to approach cascading look-ups in Nintex Forms using lookup columns in SharePoint. A summary is: for each set of data you want to create - you need to make a new SharePoint list. It makes sense!

 

But, I, personally, don't like having so many lists. I'd rather just have one place for myself and my clients to update. I wanted to find a new way - and, I have. I'd like to share that with you today so you can poke holes in it, or try it for yourselves. 

 

Let's look at a 1-list set-up for 4 different cascaded sets of metadata.

 

AnimalVegetable

Tier 1Unique 1Tier 2Unique 2Tier 3Unique 3Tier 4
AnimalYMammalYCatYCalico
AnimalMammalCatManx
AnimalMammalDogYPug
AnimalMammalDogBeagle
AnimalAmphibianYTree Frog
AnimalAmbhibianSalamander
VegetableYLeafyYLight GreenYIceburg
VegetableLeafyLight GreenRomaine
VegetableLeafyDark GreenYKale
VegetableLeafyDark GreenSpinach
VegetableLeafyPurpleYCabbage
VegetableRootYBrownYPotato
VegetableRootOrangeYCarrot
VegetableMarrowYOrangeYPumpkin
VegetableMarrowYellowYSpaghetti Squash
VegetableMarrowYellowButternut Squash

 

Let me explain:

 

An issue we have right now is that if we simply use a List Lookup and pull back Tier 1, we will get hella duplication of Animal and Vegetable. Perhaps some day we will have a "remove duplicates" functionality, but right now - we don't.

 

This is where views save the day.

 

  1. For each unique value in Tier 1, I put a "Y" in my Unique 1 column. For consistency, I always tag the first unique item as unique. 
  2. Then, I create a view: Tier 1 - Unique. Filter when Unique 1 = Y. 
  3. Now, when I set-up my List Lookup control in my Nintex Form, I tell it to look at the list called AnimalVegetable and return column Tier 1 using view Tier 1 - Unique. Perhaps I've named that List Lookup something crazy like "Tier 1".
  4. This is repeated for each column, as you'll see above, in terms of setting up views. So I'll end up with a Tier 2 - Unique, and Tier 3 - Unique. And, I can have as many tiers as I like. 
  5. When I want to filter my Tier 2 values based on Tier 1, I set my Lookup List to look at list AnimalVegetable, column name Tier 2, using view Tier 2 - Unique, filtered by control Tier 1. 

 

 

For me, this works really well. How about you? What are your thoughts?

 

Cheers!

 

Rhia

Introduction -

 

I have been wanting to make this blog post for a little while, and even though (due to time constraints) it probably will not be as thorough as I had originally planned, it will ultimately serve the purpose of introducing the community to a few advanced approaches to using the Nintex Form rule system. Though you will need a comfortable understanding of javascript to get the most benefit from this, but if you're curious and aren't keen on programming, don't let that stop you from learning! 

 

The Rule system, as it stands, is a good tool to validate control inputs and to alter the appearance of controls based on the Form's state. However, as I found myself enjoying their usefulness, I also found myself wishing that I could do other simple and useful things with them such as populating a field based on the amount of choices, normalizing the inputs of a field, or doing some type of advanced validation based on wild requirements. 

 

Though I cannot account for all of the ways that you might want to use the rule system, I can at least teach the fundamentals of how to use them in a more explicit / specific way, that will hopefully provide you more opportunity to develop form logic that would otherwise be tedious. 

 

On The Surface -

 

The Basics

 

The Rule system is broken up into several types of rules but the two that are presented via the Rules button inside of the Form Editor are Validation and Formatting [1].

 

Note [1]: If you are using the Responsive Form, there is a new type of Rule that is sometimes called an 'Action' rule, but is listed as a 'Set Value' rule. For all intents and purposes, this rule behaves in the same way that a Formatting rule does, but then goes on to evaluate whatever value is listed inside of the 'Value' formula dialog.

 

Validation Rules - are rules that will run, typically, whenever the control they are placed on has been changed or updated in some capacity, and also create a <span> element in the html of the form that is nested under the control in question. That span element can be thought of as the "physical" manifestation of the rule and contains references to the target control along with information about how the rule should be evaluated and the randomly generated rule name that is created each time you create a new rule. 

 

Formatting Rules - are rules that will run, typically, whenever a control that they have referenced has been changed or updated in some capacity. They do not create an element in the html tree. 

 

The Rule Editor - is the interface that allows you to Create, Delete, Setup, and otherwise Manipulate all of the Rules for the Form and its Controls. In Classic Form Mode it looks like: 

 

While in Responsive Form Mode it looks like: 

 

On The Differences Between Editors: The biggest changes between the two visually are the terms used to label each section, and the fact that the Responsive Forms Rule Editor has removed the Rule Type and replaced it with the ability to choose a single direct outcome (which can be selected in the 'Then' drop-down

 

Rule Conditions are the logical circumstances that will dictate whether or not the Rule Outcome is applied. Rule Conditions are set up inside of the Condition dialog box in the Classic Form Rule Editor:


And inside of the When dialog box in the Responsive Form Rule Editor: 

 

Rule Outcome, while not an actual term that is used in the Rule Editor, this is the 'result' of what will happen in the event that your evaluated Rule Conditions resolve to true. In the Responsive Form Rule Editor, this could be thought of as whatever you have selected inside of the 'Then' drop-down. 

 

 

On Rule Outcomes and Conditions: Whatever you'd like the outcome to be, whether it is invalidation, formatting, disablement, or hiding, the conditions that you write for the rule to evaluate must resolve to a Boolean true.

 

 

The Beyond

 

Referenced Named Controls - (the red link-like references [2] that you see inside of the formula dialog ) are replaced when the form is 'live' (as in being Previewed, Viewed, Edited, or invoked as a New form) with the following example code: 

NWF.FormFiller.Functions.GetValue('ad065df4-c555-44f7-aebe-5491cabcbd2c', sourceContext);

 

(Note [2]: While it is true that referencing other controls inside of the rule condition builder dialog will often result in the red link-like reference being inserted, when referencing the current control, you can type out the plain-text equivalent {Control:Self} (yes - with the curly brackets), and it will be replaced just the same. In many of my own examples, you will see me use the long-form version {Control:Self} as it can be easily copy / pasted without needing to insert it manually as you do for each of the other Named Controls)

 

 

Referenced Runtime Functions - are replaced when the form is 'live' with the full calls to their location inside of the NWF namespace as shown by the following example:

NWF.RuntimeFunctions.isNumeric.call(nullOrContext, someValue)

 

 

On Reference Replacement: The way that replacement works for both Control References, RunTime Functions, etc. is that it looks for a particular expression and attempts to 'remap' it if it recognizes it. For Referenced Controls it is looking for {SomeProperty:SomeValue}, whereas for Runtime Functions it is looking for FunctionName(). 

 

The RunTime Function replacements can be incredibly confusing and frustrating if you are trying to use a Native or jQuery (NWF$) function with an identical name, as it will be replaced with a call to the function that is native to the NWF object. 

 

If you write out: 

NWF$.isNumeric("444");

 

During run time it will be replaced like:

NWF$.NWF.RuntimeFunctions.isNumeric.call(someContext, "444");

 

Which will result in an error. You can sidestep this 'correction' by making your code a little sloppier. Putting a space between the function name (in this case 'isNumeric') and the open parenthesis for the arguments, it will fail to meet the conditions for a function that should be evaluated / replaced, and will be left alone. 

 

NWF$.isNumeric ("444");

// Yay! No error!

 

whew...

 

 

The Helpers

 

There are several Nintex created variables and functions that can help with the manipulation and utilization of the Rule System. Though I will not be covering them all, I do feel like these are the most useful for the majority of users

 

 

Variables

 

  1. Rules: All rules can be found using the 'Rules' variable, which returns an array of Objects.

  2. Page_Validators: All Validation rules can be found using the 'Page_Validators' variable, which returns an array of <span> elements. 

 

Functions

 

  1. NWF.FormFiller.Functions.ProcessOnChange(someControl): This function should receive a Form Control as the argument:
    NWF$("#" + someValue).val("Hello World");

    NWF.FormFiller.Functions.ProcessOnChange(NWF$("#" + someValue));

    and will evaluate any 'on change' rules that have yet to fire on the target control. Because you can change the value of a control without triggering the events that would normally be triggered to evaluate the rules, this is a handy way of getting that done. It should be noted though that most of the time you can accomplish the same thing by triggering the "change" or "blur" event manually using jQuery: 
    NWF$("#" + someValue).val("Hello World").trigger("blur");
    // Same results as above!

     

  2. Page_ClientValidate(): This function takes no arguments but will force the entire form to evaluate all of the Validation Rules upon execution. This is incredibly helpful in the event that you'd like some type of two stage process (for instance, a button that creates a confirmation "Are you sure you wanna submit this?" dialog which must be interacted with before submission) to test the page validity before submitting it to SharePoint. 

    This does however come with a few quirks. Firstly, it doesn't actually apply any of the invalidation styles that would normally get applied had the form been submitted proper. Secondly, it does create the top warning dialog that lists all of the current invalidation messages. 

    That being said, Caroline Jung created a handy little function that can apply those invalidation css classes to your controls right over here: https://community.nintex.com/thread/11554#comment-75684 

  3. NWF.FormFiller.Functions.GetParentContext(someControl): So... This function doesn't exactly do anything in terms of Validation, however it is incredibly useful for getting what is often called the 'sourceContext'. While the sourceContext is always passed into a Rule of any type, knowing how to get a correct context to any control can be helpful in developing your own functions and system that work with or sit on top of the existing Nintex Forms Rule system in the future.

    All a 'Context' is, is simply the closest 'containing' control that the target control is inside of. The context of a control that is inside of a Repeating Section is the row of the repeating section that particular control is inside of. However the context of a control that is just on the form proper, would be the form proper! 

Down The Rabbit Hole -

 

The Evaluated Conditions

 

While it is easy to suspect that things being evaluated inside of form Rules are special functions and value references, in reality, what's being evaluated is nothing more than plain ol' JavaScript [3][4]. As shown above, all of the references to named controls and functions are replaced at run time and evaluate accordingly. Because of that, we can actually do some really interesting things. This is especially true when we start to consider the usage of Immediately Invoking Function Expressions (simply known as IIFE. More info about those can be found here: An Introduction to IIFEs - Immediately Invoked Function Expressions - A Drip of JavaScript). 

 

Note [3]: Rules aren't the only things that evaluate javascript. The formulas for the Calculated Control can also evaluate JS.

 

Note [4]: So long as the return value of whatever it is you are evaluating as the Rule Conditions returns either a true or false boolean value, it will 'drive' the rule. This could be as simple as writing: 

 

true

 

Yes. It's just one word, but that would make the Rule apply either its formatting, invalidation, or action (in the case of responsive forms) from the very beginning and stay that way throughout the form session.

 

Why might this knowledge be useful? Well, to most people who aren't comfortable with javascript, it isn't! However, for people who find it easier to think using the functions that are either exposed via the DOM's api or jQuery, it can be a lot faster to prototype in a text editor (Sublime Text, Brackets, VS Code, Notepad++, etc. etc.) and then copy paste that into a Rule's condition area rather than to sit there and type it all out inside of a html rendered <textarea> element which is a terrible place to type code. 

 

Consider the following (terrible) Rule. Let's say that we want a specific Single Line Text control to always normalize the value inside of it to "0.00" if it's blank, or to the second decimal point if it isn't (so - 1.00, or 4.31, but never ever 4.311): 

 

(function(controlValue, myControlID) {
  "use strict";

  // Using our passed in control's ID in a variable
  // we'll set the variable internalElement to
  // our control.
  var internalElement = NWF$("#" + myControlID);

  // If the value of the control isn't empty...
  if (internalElement.val()) {

    // Then we'll need to test if it's Numeric
    // Notice that I am using the Nintex Forms function
    // of isNumeric rather than the jQuery function.
    if (isNumeric(internalElement.val())) {

      // If it is Numeric, then we can split at the decimal point delimiter
      var splitValue = String(internalElement.val()).split(".");

      // Test to see if there is anything in the integer portion
      // *that is, the value on the left side of the decimal point*
      // If there is a value. Keep it.
      // If there isn't. Set it to 0.
      var intPart = (splitValue[0]) ? splitValue[0] : "0";

      // Then we'll take the value to the right of the decimal point
      // If it exists...
      //
      //    Then we'll check the length of that value.
      //
      //      If it's under 2 then we'll add a 0 to the end of it.
      //
      //      If it's above or equal to 2 then we'll truncate off the numbers
      //      beyond the second decimal place.
      //
      // If it doesn't exist we'll just set it to "00"
      var fractionPart = ((splitValue[1]) ? ((splitValue[1].length < 2) ? splitValue[1] + "0" : splitValue[1].slice(0, 2)) : "00");

      // Then we'll put both halfs back together
      var joinedValue = intPart + "." + fractionPart;

      // And we will set the control to that value
      internalElement.val(joinedValue);
    } else {
      internalElement.val("0.00");
    }
  } else {
    // But if it is empty, we'll set the value to "0.00"
    internalElement.val("0.00");
  }

  // We're not actually doing anything with this rule other than
  // what is the equivalent of an event handler, so we don't
  // even need the rule to apply anything to the control.
  // Because of that, we can always return false.
  return false;

}({Control:Self}, myControlID));

// We'll pass in the Value of the Control
// and the javaScript ID of the Control

 

Alright. That does what we want... but as mentioned in the code comments. It's not really any more flexible than just setting up and using a standard Event Handler. 

 

Currently the only advantage over using an event handler is that you don't have to target your controls... and speaking of which... wouldn't it be awesome if you could reference the target control of a rule from within the rule itself? 

 

Self Referencing Part 1 - A New Hope

 

Being able to reference the control that the rule is currently evaluating on is what would ultimately make the rule system a wonderful tool to use... But there is no immediately obvious way to do this from the onset. 

 

While the above example code will only work for the control that has the javascript ID exposed (through the control properties) as the variable 'myControlID', we could make a 'universal' rule if we were only able to capture the control that was being referenced by the rule that was executing our code. 

 

Luckily the rule system provides a few bits of information that can help us achieve a self-reference, however, before we get into what those are, it is important to know how Rules are represented as javascript. 

 

Every rule, which is named dynamically upon the building of the Form essentially looks like this: 

function fnSomeVeryLongGUIDThingHere(sourceContext, rowIndex){
  return //(your code);
}

 

Whatever you have typed into the Condition / When are of the Rule will be evaluated (and subsequently returned) just beyond the return statement as indicated by the 'your code' comment in the example above. 

 

If your Rule's condition looked along the lines of: 

isNullOrEmpty({Control:Self}) || {Control:Self} < 100

 

Then the resulting Rule that is generated by the Form loading would look like: 

function fnSomeVeryLongGUIDThingHere(sourceContext, rowIndex){
  return NWF.RuntimeFunctions.isNullOrEmpty(NWF.FormFiller.Functions.GetValue('some-guid-forthe-formcontrolid-attribute', sourceContext)) || NWF.FormFiller.Functions.GetValue('some-guid-forthe-formcontrolid-attribute', sourceContext) < 100;
}

 

Though that may mean nothing to anyone immediately, you might wonder what those two arguments are (sourceContext and rowIndex) that get passed into the wrapping Rule Function.

 

As mentioned above, the sourceContext represents the 'context' (IE: The 'container') of the current control that the rule is running on. So that's already covered. However, the rowIndex is something different. rowIndex actually holds the id attribute of the control that is being evaluated! 

 

That means that you can essentially forgo the need of going into the Properties of a Control and setting up a javascript variable name for the id, because it can now be grabbed using that argument. 

 

Using that numeric 'normalizing' Rule we made above, it can now be rewritten in a more generic / dynamic way: 

(function(controlValue, sourceContext, rowIndex) {
  "use strict";

  var internalElement = sourceContext.find("#" + rowIndex);

  if (internalElement.val()) {
    if (isNumeric(internalElement.val())) {

      var splitValue = String(internalElement.val()).split(".");
      var intPart = (splitValue[0]) ? splitValue[0] : "0";
      var fractionPart = ((splitValue[1]) ? ((splitValue[1].length < 2) ? splitValue[1] + "0" : splitValue[1].slice(0, 2)) : "00");
      var joinedValue = intPart + "." + fractionPart;

      internalElement.val(joinedValue);
    } else {
      internalElement.val("0.00");
    }
  } else {
    internalElement.val("0.00");
  }

  return false;

}({Control:Self}, sourceContext, rowIndex));

 

And so now we can all live happily after ever. Right? 

 

Self Referencing Part 2 - Reference With A Vengeance

 

Sadly, that is not the end of the story. The variable rowIndex, while incredibly awesome and useful is only populated for Validation Rules... And because Validation Rules are only evaluated after they have been changed, if you want a rule to fire immediately after the form has loaded then you'll need to use a Formatting Rule. So how in the heck can we get the reference to the current control via a Formatting Rule? 

 

You may have noticed that a few code examples up, I showed what a Rule actually ends up being once it has been generated during the building of the Form. Inside of that Rule Wrapper, the references to the current control ({Control:Self}) were converted into a call to a Nintex Form function along with two arguments. The second argument was just the sourceContext, but the first argument was a string which I wrote out as 'some-guid-forthe-formcontrolid-attribute'. In reality that string would look more along the lines of '8381e2de-c48d-4f02-9e32-d26bb106af44'

 

What is that? Well. It's actually the attribute called formcontrolid, which every form control has, and is used as a link between those red colored Named Control references (like {Self}), and the controls that they represent as html elements on the page. This means that so long as we pass in the self reference and capture it as a string (otherwise it would be evaluated down into whatever value that Function call with those arguments should return), along with the sourceContext we can figure out which control the Rule is running on. 

Consider the following code: 

(function(formControlCall) {
  "use strict";

  // If you look at the {Control:Self} refernece we have passed
  // into this function as an argument (named: formControlCall), you'll
  // see that it's surrounded by quotes. Because of the way that
  // the Form 'transforms' references that it sees into the code to be evaluated
  // and doesn't care about the surrounding mark-up, it actually just
  // puts the fully transformed call right in between those quotes
  // resulting in a String being passed in.

  // The final result is that the variable formControlCall actually equals:
  // "NWF.FormFiller.Functions.GetValue('8381e2de-c48d-4f02-9e32-d26bb106af44', sourceContext)"


  // If you split the formControlCall at the single quotes, you end up with
  // an array with (3) items.

  // "NWF.FormFiller.Functions.GetValue(",
  // "8381e2de-c48d-4f02-9e32-d26bb106af44"
  // ", sourceContext)"

  // By Taking the value at Index 1 (the formcontrolid of the Current Control)
  // we can use it to grab the actual control as it is on the form.
  // If the reference to that Array Index is empty, then we'll get a blank string instead.
  var formControlID = formControlCall.split("'")[1] || "";

  // Assuming that the Array Index wasn't empty
  // formControlID now equals: "8381e2de-c48d-4f02-9e32-d26bb106af44"

  // Using the sourceContext, we can search for any control with a matching formcontrolid attribute.
  // Putting the class '.nf-filler-control' will allow us to identify the topmost Control Container <div>
  var targetControl = sourceContext.find("[formcontrolid='" + formControlID + "'].nf-filler-control");

  // This will vary between Control Types. In the case of Single Line Text controls, we can grab
  // the element that is under the parent container (stored in targetControl), and shares a
  // formcontrolid attribute and has a class of '.nf-assocated-control'.
  var internalElement = targetControl.find("[formcontrolid='" + formControlID + "'].nf-associated-control");

  // Please be aware that NOT ALL INTERNAL CONTROLS CAN BE OBTAINED USING THE METHODS SHOWN FOR
  // THE internalElement VARIABLE!

  // *I may come back later and write something that will absolutely always obtain the correct control
  // but don't hold your breath 

  return false;
}("{Control:Self}"));

 

Without Comments that's:

(function(formControlCall) {
  "use strict";

  var formControlID = formControlCall.split("'")[1] || "";
  var targetControl = sourceContext.find("[formcontrolid='" + formControlID + "'].nf-filler-control");
  var internalElement = targetControl.find("[formcontrolid='" + formControlID + "'].nf-associated-control");

  return false;
}("{Control:Self}"));

 

If we wanted to change that formatting rule above so that runs immediately when the form loads, and subsequently every time that the value of the control has been changed, instead of using a Validation Rules, we could use a Formatting Rule with the following code: 

(function(formControlCall) {
  "use strict";
  var formControlID = formControlCall.split("'")[1] || "";
  var targetControl = sourceContext.find("[formcontrolid='" + formControlID + "'].nf-filler-control");
  var internalElement = targetControl.find("[formcontrolid='" + formControlID + "'].nf-associated-control");
  if (internalElement.val()) {
    if (isNumeric(internalElement.val())) {
      var splitValue = String(internalElement.val()).split(".");
      var intPart = (splitValue[0]) ? splitValue[0] : "0";
      var fractionPart = ((splitValue[1]) ? ((splitValue[1].length < 2) ? splitValue[1] + "0" : splitValue[1].slice(0, 2)) : "00");
      var joinedValue = intPart + "." + fractionPart;
      internalElement.val(joinedValue);
    } else {
      internalElement.val("0.00");
    }
  } else {
    internalElement.val("0.00");
  }
  return false;
}("{Control:Self}"));

 

This is great for when you want something to be formatted in a particular way, but don't care to validate on it. On the other-hand, if you wanted to validate on it, you could just as easily use the Validation variant as shown above, and instead of returning false, return the condition result of how you would like it to be evaluated.

 

 

Self Referencing Part 3 - Attack Of the Review

 

To Recap, there are two ways to obtain a reference to the control that a Rule is currently running on. They are as follows.

 

Self Referencing For Validation Rules

(function(rowIndex) {
  "use strict";

  var internalElement = sourceContext.find("#" + rowIndex);

  return false;
}(rowIndex));

 

Self Referencing For Formatting Rules:

(new version (Updated: 2018-03-27)): 

(function(formControlCall) {
  "use strict";

  var formControlID = formControlCall.split("'")[1] || "";
  var targetControl = sourceContext.find("[formcontrolid='" + formControlID + "'].nf-filler-control");

 
  if (!(targetControl.data("DisableCounter") === undefined && targetControl.data("HideCounter") === undefined)) {
    if (targetControl.attr("data-formcontroltypeid") === "c0a89c70-0781-4bd4-8623-f73675005e15" && (!event || (event.type !== "readystatechange" || (event.srcElement && event.srcElement.text && event.srcElement.text.toLowerCase() === "add new row")))) {
      return false;
    }
  }
 
  /* return the condition  you actually are checking on */
  return true;

}("{Control:Self}"));

 

(old version - Do Not Use... unless the above code does strange things to you) 

/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
/* PLEASE SEE THE REVISION CODE EXAMPLE BELOW THIS ONE! DO NOT USE THIS EXAMPLE! */
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */

(function(formControlCall) {
  "use strict";

  var formControlID = formControlCall.split("'")[1] || "";
  var targetControl = sourceContext.find("[formcontrolid='" + formControlID + "'].nf-filler-control");

  // This will need to change based on the 'type' of control
  // but this works for Single Line Text which is probably the most used control.
  var internalElement = targetControl.find("[formcontrolid='" + formControlID + "'].nf-associated-control");

  return false;
}("{Control:Self}"));

/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
/* PLEASE SEE THE REVISION CODE EXAMPLE BELOW THIS ONE! DO NOT USE THIS EXAMPLE! */
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */

- Examples -

 

Because it may not be obvious how any of this stuff can be used, I've put together a few examples of how one might utilize the above knowledge to do things that would otherwise be difficult. 

 

Self Locking Control - This Formatting Rule (which should have the Disable box / action selected) that will check if the current control is set to any of the values as specified in the Array of values which is passed into the function's argument 'ignoredValues'. If the Control is not any of the values inside of the array, then it will be given a class of '.lockMe', and will return a true to the Rule Processor, resulting in the Disabling of the control. Otherwise the control is left untouched, and will remain Enabled for the remainder of the Form session unless there are other Rules that can Disable the control for other reasons: 

(function(formControlCall, ignoredValues) {
  "use strict";
  var formControlID = formControlCall.split("'")[1] || "";
  var targetControl = sourceContext.find("[formcontrolid='" + formControlID + "'].nf-filler-control");
  var controlValue = eval(formControlCall);
  if (!targetControl.hasClass("ignoreMe") && !targetControl.hasClass("lockMe")) {
    var canIgnore = false;
    if (!NWF$.isArray(ignoredValues)) {
      if (typeof ignoredValues === "number" || typeof ignoredValues === "string") {
        ignoredValues = [ignoredValues];
      } else {
        ignoredValues = [""];
      }
    }
    NWF$.each(ignoredValues, function(index, value) {
      if (!canIgnore && value === controlValue) {
        canIgnore = true;
        return false;
      }
    });
    if (canIgnore) {
      targetControl.addClass("ignoreMe");
    } else {
      targetControl.addClass("lockMe");
    }
  }
  return targetControl.hasClass("lockMe");
}("{Control:Self}", ["", "Some Other Value"]))

 

The Self Locking Control Rule can be useful if you have forms that contain controls which once filled out, should not be editable again. Or as in my case where I have a selection control with (3) values ("In Process", "Won", "Lost"), (1) of which ("In Process") can be changed from but (2) of which ("Won", "Lost") can never be changed out of once they have been selected and the Form has been Submitted. 

 

 

Automatic Option Selection - This is a Formatting Rule that will automatically select an Option from a drop-down control if there is only one option to select. This is useful for Lookups that are being filtered by other choices and have many different option counts based on said filters. While the code below doesn't reset the control once you have selected a filtering value that would result in more choices being available, it wouldn't be too difficult to set that up: 

(function(formControlCall) {
  "use strict";

  var formControlID = formControlCall.split("'")[1] || "";
  var targetControl = sourceContext.find("[formcontrolid='" + formControlID + "'].nf-filler-control");
  var targetSelect = targetControl.find("select.nf-client-control").get(0);

  if (targetSelect !== undefined) {
    if (targetSelect.options.length < 3) {
      if (!targetSelect.options[targetSelect.options.length - 1].selected) {
        targetSelect.options[targetSelect.options.length - 1].selected = true;
        NWF$(targetSelect).trigger("change");
      }
    }   
  }
  return false;
}("{Control:Self}"))

 

- Outro -

 

So there you have it. A whole lot of text and you have arrived at the end of this post (hopefully) with a new understanding of how you can utilize the Rule system in new and interesting ways. Armed with this knowledge you should be able to create "Action Rules" (aka: rules that can update a target control's value or influence the form in some meaningful way) in the Classic Forms (because why should the Responsive Forms have all fun?), and different approaches to validating complex combinations of things. 

 

For my own work I have developed a Validation System which sits on top of the existing one found in the Nintex Forms environment so that I not only have 'Invalid' controls, but also 'Valid' controls, and 'Warning' (also known as Optional) controls - all of which have their own styling that is applied when they reach one of those states, or as in the case of an Optional state, will start off showing that it's something that isn't needed all of the time, but might be needed *sometimes*.

 

 

Once that is refined a bit more, I may release it to the public so that people can add on to it, but it needs some more revisions (as the code base has changed), and I simply do not have the time to prepare those. 

 

I look forward to seeing what you all come up in your journey. 

 

Thank you for reading! 

 

 

 

 

PS: If you have any examples that you'd like me to add, or have any questions or corrections, please shoot me a direct message, or better yet, ask in the comment section below! 

 

- Edits -

 

Edit 1: So it would seem that I forgot a critical part of handling Rules for a Repeating Section. As far as I know there still is a rather glaring bug that prevents the event triggers that should be associated to the control / rule from being attached once a new row has been added (as seen here: Custom validation function not fired on repeating section). This is problematic as, ideally, you'd like all of the controls in every row of your repeating section to act the same regardless of when they were created (and without having to submit / reload the form). 

 

This can be accomplished by adding the following code, or by modifying your existing RegisterRepeaterRowAdded function with the code shown in this example: 

NWF.FormFiller.Events.RegisterRepeaterRowAdded(function () {  
  ValidatorOnLoad();
});

 

Now your rules should behave as you would expect them to inside of a Repeating Section, and life should once again be great! 

 

Edit 2: It would seem that Repeating Sections do silly things with Formatting Rules which requires us to manually prevent them from occurring. Because of the way that Formatting Rules process the Disable / Hide side of things (by using a ticker numeric value hidden in the data() jquery object on the main control div), we need to make sure that we do not arbitrarily increment or decremented that value in such a way that it would break how Disabling and Hiding work. 

 

We can do this specifically by including the following conditional checks before the main return statement of our rule that would actually check against the conditions that we wanted to check against (for the rule proper):

if (!(targetControl.data("DisableCounter") === undefined && targetControl.data("HideCounter") === undefined)) {
  if (targetControl.attr("data-formcontroltypeid") === "c0a89c70-0781-4bd4-8623-f73675005e15" && (!event || (event.type !== "readystatechange" || (event.srcElement && event.srcElement.text && event.srcElement.text.toLowerCase() === "add new row")))) {
    return false;
  }
}

 

Essentially, what the above code does is to first check and see if the hidden 'ticker' values (DisableCounter and HideCounter) exist on the data() object. If they do not then the rule will evaluate as we can assume that this is the first time that the rule is being ran. 

 

If they do exist, then we move into the next phase where we check the Control's Type (see: Form Control Property complex element). If it's a Lookup Control ("c0a89c70-0781-4bd4-8623-f73675005e15"), then we need to do some additional checking to make sure that the Control is in a state in which we actually would like to evaluate it.

 

While this really only effects Lookup Controls, it should be written in a way that you can plonk it into any Rule and it'll work regardless. 

 

 

Because of this I have revised the above 'Review' example for Formatting Rules. 

So, you want to save more than one field from a database query but you don't want to have multiple SQL Request controls in your form?  You can achieve this with a customized SQL query and JavaScript.

 

In the query, concatenate the fields you want to use.  In this example, a pipe character ( | ) is used as a delimiter.  Set the Value field to your concatenated fields ("Details") and the Display field to a reader-friendly field for your users to select.

SQL Request action

Set the JavaScript variable name for your SQL Request control as well as the other fields you want to populate:

JavaScript Variable Name

Use the Custom JavaScript area in the Form Settings to retrieve the fields.  In this example, the SQL Request control is displayed as a Drop Down List, so the JavaScript uses the Change event to get the values and then populates the textboxes with the fields from the database query.

Form Settings Custom JavaScript

Filter Blog

By date: By tag: