Skip navigation
All Places > Getting Started > Blog > Authors scalawagd

Getting Started

3 Posts authored by: scalawagd

I recently had a client who needed a workflow that could handle voting in a way that was a bit challenging to get working.  I'm sure there a multiple ways to handle this, and I tried many unsuccessfully.  I wanted to share an approach that I was able to apply successfully in case anyone else has a similar scenario.  At a very high level, they need to gather votes and count the different responses, but the number of people who would actually respond might vary.

 

The business requirements were as follows:

 

  1. Allow for email reply (LazyApproval)
  2. Send reminders
  3. Auto-close the task(s) after a specified time
  4. Allow everyone to vote
  5. Tally the votes, including the number of "no response", and save back to the item

 

I'll go through the requirements individual and describe what I used to address them first.

 

Allow for email reply

This one was easy, enable LazyApproval in whatever task action I would use.

 

Send Reminders

Don't just put a number in there...

This was one of the requirements that drove the decision to use Flexi tasks.  Initially, during the design of the workflow, I put "5" into the "Number of reminders" field arbitrarily. 

This is no good... don't do it this way.

flexi task reminders config

Something unexpected happened with the escalations when I did this and it took me a while to put the pieces together.  Now, it's possible that I got this wrong, but it seemed like the items wouldn't do the escalation (Complete task) until after all of the reminders were sent.  I was not expecting a dependency there, and maybe it is a bug in the version I have or I just got it wrong, but everything I observed made me think this is how it was functioning.  If my item was set with a time to escalation that was 1 day away, but I had the 5 reminders above, it wouldn't complete the task until after all of the reminders were sent.  So, with that in mind, I did the following:

The right way

First, I will get the number of days (whole days, not partial) between the current date/time and the due date/time. I started with a Build string action, so I could take advantage of the inline functions like fn-DateDiffDays to get the number of days until the due date and time.

get days until due with date diff days function in a build string action

 

Next, I'll split the result of the DateDiffDays function to get rid of any decimals.  The reason for this here is that I will be using the number for how many reminders to send, so I just need the whole number.   Then, to get the number of minutes until the task auto closes, I will take the total number of minutes until it is due minus the number of minutes it was sending reminders.  There is a dependency here, and if you don't subtract the time it was sending reminders, your tasks will not close until all reminders have been sent AND the amount of escalation time has passed.  I didn't realize this at first, and I had a lot of tasks that were not closing automatically.  They would have 5 days until due for example, and send out 5 reminders... but the escalation timer didn't start until all of the reminders were sent!  

 

Anyway, on to the whole number of days... Split the variable.  Make sure to use the escape character "\" since the decimal is a special character for RegEx.  This was one of many lessons I learned during the development of this workflow.   Now, you will have the number saved into a collection variable.  If the result had been 2.3 days, the collection would now have 2 at index 0 and 3 at index 1.

split the number of days using a regular expression to get just the whole number

 

Next, the Collection Action to get just the whole number at index 0.  I am referencing a variable "numCollIndex" which is only used to grab index 0 of this collection.  It has a default value of 0.

collection operation to get the value at index 0 of the collection.  this is just the whole number

Here, the result is referenced in the Number of reminders field for the Flexi task.

flexi task config2

This gave me the variable number of reminders without rounding, so if the due date is 1.2 days away, I get one reminder, if it is 2.8 days away, I get 2 reminders.  

 

Auto-close the tasks after a specified time (escalation)

This was a requirement that pointed me to Flexi tasks.  The due date and time for the voting on these items could be specific, like in the middle of the day, so I couldn't just use days for this one.

 

We'll need a little math.  While we're waiting for all reminders to finish, we need to know the total number of minutes that will elapse.  We can use the whole number of days x 1440 to get the number of minutes (the variable is numReminderMinutes).  This will give us part of the equation we need to accurately determine how long to set for the task auto-escalation.

math operation to get the total number of minutes that will elapse while waiting for reminders

The next step is to get the total number of minutes until the due date/time.

Using a build string, you can get this number using the DateDiffMinutes function.  Now we have the minutes until the due date/time, but it is a text variable.

using the date diff minutes function inside a build string to get the total number of minutes until due

 

Convert the value to a number with a Convert Value action.  The variable is numTotalMinutesUntilDue.

convert value action to change from text to numeric

With a math operation, take the total minutes until due - number of minutes elapsed while waiting for reminders to get the number of escalation minutes.  This is how long the tasks wait after all reminders have gone out.  Once this is done, the auto close occurs.  This is saved in NumRBEscalationMinutes.  We'll put that into the Flexi-tasks later.

use math action to calculate total minutes until due - number of reminder minutes = number of escalation minutes

 

Here is the Flexi task with that variable for the Time to escalation:

flexi task with variable for escalation

I added an outcome and comments text to more easily track who didn't respond in the workflow tasks list.  Also, I need it for the tallying part later.

 

The Flexi tasks have an "Other" branch to handle the "No Response" scenario when the voting window has closed.

flexi task with 3 branches

 

 

 

 

Allow everyone to vote

The "Request approval" action has a vote option, but unfortunately, it doesn't have the reminders or the escalation options, so this became a challenge and a significant driver of the workflow design.  Ultimately, there are 7 teams that get a vote.  For the most part, there is only one representative, but there may be cases when two people are part of the team.  So, I used SharePoint permissions groups here to make sure the members could be changed easily.

 

I couldn't use just one Flexi task action assigned to all of the groups, or just one group with all of the members, because it doesn't allow for everyone to vote.  The tasks would close once a majority was reached.  With the all must agree options, the tasks closed when there was disagreement.  Your options are the following:

 

task behavior options

When I tried these options, the task would not allow for all responses in the way that we wanted that would be easy to understand for the process owners.  So, after trying a few approaches, I went with parallel actions.  I wanted to do a streamlined, elegant solution, but I opted for clarity and better supportability for my team later.

Here are a few of the tasks... there are just 7 branches of Flexi tasks.  Since all the votes get tallied, there are no actions in any of the specific branches under the Flexi tasks.  I'll describe what these are doing in the next section.

parallel flexi tasks

 

Tally the votes

The Flexi tasks have the standard Reject and Approve options, and we also need to know when people don't respond before the time to escalation elapses, so the "No Response" outcome is captured in those instances.  The escalation options for the Flexi task look like this:

flexi task config

 

A key part is to capture both the outcome and the task id for each of the voters.  We have 7 total, and below is the config for #3:

task config

 

After each of the Flexi tasks, I am using a Collection operation to capture all of the task IDs so I can get the specifics later with a list query action.

collection operation to gather the vote

 

The Collection operation just adds each task id from the corresponding variable:

 

Now, we do a For each through the voting tasks in the CollVoteTaskIDs collection.  I did a pause for 5 minutes here to make sure all the updates to the items in the task list were complete before trying to loop through them:

for each loop through vote tasks

 

Here is the For each configuration

 

The Query list

query list config

The variable "txtCurrentVoteOutcome" is the "Yes", "No", or "No Response" results for each voting group.  The "perCurrentAssignedTo" is the person who entered the vote.

 

Next, I am going to get the display name of the person and start creating a multiline of text field, so later on the process owner can get an email with all of the voters and their responses.

get display name and build string

 

The Set variable looks like this:

set variable

 

And the Build string looks like this:

build string

 

Now the tally at the end of the For each... I have 3 variables to store the tallied results, numYesVotes, numNoVotes, and numNoResponse.  The conditions are looking at the variable I got from the Query list action called txtCurrentVoteOutcome.

tally conditions

In the first condition, if txtCurrentVoteOutcome = "Approve", the Math operation adds one to the numYesVotes variable.  In the second condition, if txtCurrentVoteOutcome - "Reject", the Math operation adds one to the numNoVotes variable.  If neither of these are true, one is added to the NumNoResponse variable.  Then it goes back to the top of the For each and checks the next one.

 

After the loop, the tallied votes are put into the fields for the item.

update item with votes

 

At the very end is a final approval checkpoint.  This task goes to the process owner before the final "go/no go" meeting.

This is just a regular Flexi task, but it contains all the voting info in the notification to the process owner.

final approval email

it includes a summary of the number of votes along with the outcome of each vote from the multiline of text variable (mtxtVoteOutcome) that was created earlier.

 

In total, this voting component is part of a pretty large state machine workflow.  The rest of it deals with other parts of the business process, but this voting part was the most complex piece for me to figure out.  Hopefully, it gives you some ideas on a way to handle this if you have a similar scenario.  Happy Nintexing!

I recently had a customer who wanted status indicators in his list.  While this can be done using JavaScript, one of my co-workers had come across a simpler approach by using a calculated column that points to the images that already exist in SharePoint.  

 

That worked well and his list views now had a nice indicator related to the status of each item.  Here is a sample of the list view:

icons in list view

Instructions for this approach will be in at the bottom of this post.  It's really easy, I promise!

 

I thought it might be a nice touch to include those icons in the form as well.  Here is a sample:

status icons on form

I was surprised that the image controls lined up so well when switching between statuses.

 

Here are the steps that I used:

  1. Set up your list with choice column that will be used for the status.
    column settings
  2. From the list, click on the List tab.  Click on Nintex Forms, and then click on Customize the item form.
  3. For this example, a panel control is placed on top of the label control for the "Status Indicator".  This panel will contain the images.
    add the panel control
  4. Add an Image Control to the panel. 
    NOTE: I used an existing status icon that is available to everyone.  Enter the following into the "Image URL" field: /_layouts/images/kpinormallarge-0.gif
    add the image control into the panel
  5. Copy and paste the image control two times.  Change the "Image URL" to the following for a caution (yellow): /_layouts/images/kpinormallarge-1.gif and for a warning (red): /_layouts/images/kpinormallarge-2.gif
    NOTE: avoid overlapping the image controls.  There is a 1 pixel gap between the controls in this example.
    copy and paste the image controls
  6. Create formatting rules for each image.  From the Nintex Forms tab in the ribbon, click on the Rules button and then click Add.
    add rules
  7. Create a brief name for the rule, such as "hide warning".
  8. Rule Type should be "Formatting".
  9. The hide condition should include the name of the indicator choice control and the status value.  In this case, the "on track" green icon will be hidden when the dropdown does not equal "On Track".
  10. Create rules for the other statuses as well.
    create other rules
  11. Preview to test out the functionality, then save and publish!

 

 

Supplemental info: How to add status icons to a list view using a calculated column.

  1. In your list/library settings, click on create column.
  2. From the create column page, enter a name for the column and click the radio button for Calculated.choose calculated as the column type
  3. Enter a formula like this:
    ="<DIV><IMG src='/_layouts/images/"&IF(Status="On Track","kpipeppers-0",IF(OR(Status="At Risk"),"kpidefault-1","grefresh"))&".gif'/></DIV>"
    NOTE: "Status" is the name of a choice column in this list that the icon is related to (see the first image above).  The way this is configured, "On Track" and "At Risk" our captured in the formula as IF conditions. The else is "Warning"; in other words, if any other status is selected, it will return "Warning". You can customize the example formula to meet your specific needs by adding/removing choices.
  4. Choose Number for the data type returned, and click on the OK button.
    data type returned is number
  5. Modify your view to include the new "StatusIcon" column, and it should appear.

 

Some other files names of interest (replace kpipeppers-0 with the file name below, for example):

 

File nameLocation of imageImage
kpidefault-0.gif/_layouts/images/kpidefault-0.gif
kpidefault-1.gif/_layouts/images/kpidefault-1.gif
kpidefault-2.gif/_layouts/images/kpidefault-2.gif
grefresh.gif/_layouts/images/grefresh.gif
kpinormal-0.gif/_layouts/images/kpinormal-0.gif
kpinormal-1.gif/_layouts/images/kpinormal-1.gif
kpinormal-2.gif/_layouts/images/kpinormal-2.gif
kpipepperalarm-0.gif/_layouts/images/kpipepperalarm-0.gif
kpipepperalarm-1.gif/_layouts/images/kpipepperalarm-1.gif
kpipepperalarm-2.gif/_layouts/images/kpipepperalarm-2.gif
kpipeppers-0.gif/_layouts/images/kpipeppers-0.gif
kpipeppers-1.gif/_layouts/images/kpipeppers-1.gif
kpipeppers-2.gif/_layouts/images/kpipeppers-2.gif
kpitrend-0.gif/_layouts/images/kpitrend-0.gif
kpitrend-1.gif/_layouts/images/kpitrend-1.gif
kpitrend-4.gif/_layouts/images/kpitrend-4.gif
kpiryg-0.gif/_layouts/images/kpiryg-0.gif
kpiryg-1.gif/_layouts/images/kpiryg-1.gif
kpiryg-2.gif/_layouts/images/kpiryg-2.gif
Huge thanks to Dave for sharing this calculated columns approach and to Paul Frederickson for setting up the sample site in our Example Hub.  Here is a site with references to the locations of all of the images (there are a lot more than what I have in the table above): SharePoint 2013 OOTB Image Files - Obilogic Blog 

One of our site owners encountered an error when trying to create a Nintex form on a new list.  The error message was as follows:

index error

The key part of the error outlined in red was, "The server encountered an error processing the request.  The exception message is 'Index was outside the bounds of the array.'"

 

I could recreate the issue on that list with my admin account, but not on other lists on the same site.  I didn't find any community discussions about this, so I started looking at the list structure and settings.  I quickly noticed an unusual column.  One of the columns was named "#".  I changed the name to "Number" and retried launching the forms builder.  Lucky guess!  It worked!  To test it out, I tried some other special characters and ran into the same error.  Interestingly, if the column name had text and a special character, it seemed to work fine, but when it was just a special character, I received the error.  So, for example, using "#" or "$" as the column name resulted in an error.  Using "# of users" or "$ amount saved" did not result in an error. 

 

The lesson... avoid using just special characters as your column names.

 

For reference, we're using SharePoint 2013 on premises, and Nintex Forms version 2.7.0.0

 

Hope this helps!

Brian

Filter Blog

By date: By tag: