Skip navigation
All Places > Dev Talk > Blog
1 2 3 Previous Next

Dev Talk

100 posts

Hello! I wanted a solution to remind my users that they had outstanding and overdue items. My current solution is to query a list for users with outstanding items and send them an email with a link to a page showing the items to do.

 

While this works to a point I wanted to spoon feed them a little more. I wanted the email to include information about each item and to have a link to each item. Something like...

 

 

The list for this example is a Diary list. A simple list that sends reminders on a due date for the Event Owner to do a job and then Close or Rollover the item. Of course many don't bother closing the item so we have lot's of events that look overdue. Hence the reason for this reminder.

 

We need to use a site workflow for this to work.

 

First couple of Actions. Query List to capture the EventOwners and then a Collection Operation to Remove Duplicates

 

 

Query List. Filter to just overdue Items in progress and gather the EventOwner field into a collection.

 

 

 

 

 

Collection Operation. Remove duplicates from the collection.

 

 

 

 

 

Now for each User in the collection we need to do the following....

 

 

 

For Each User in the collection, store in a Person Variable.

We need this as a person variable to get the ID and Name.

 

 

Get the users SharePoint ID. I need this because we are querying the list next and I need to filter outstanding items down to the user.

Get the Users name. Used in the email.

 

 

 

Lookup Outstanding items for user and get the fields we want to include in the summary email. You can see the filter is the same as the original query list with the addition of filtering down to the users ID.

And the fields I want to include in the summary email at the end . ID is a must and I'm keeping it simple by just bringing in the Title and Due Date. Each extra field you want needs a Collection variable and a Single Text Variable.

 

 

Now we want to summarize the items outstanding for the user. To do that for each item ID, we need to collect our required fields ( Title and Due Date ).

 

 

 

For Each ID in the collection. This also requires an index (number variable). This keeps the Title and Due Date fields together from the relevant item.

 

Run parallel actions. Lookup the fields we need from the item.

 

 

 

Last part of the Summary section.

 

 

 

Build String. Here I'm putting the Fields onto a single line.

Title - Due Date - Link.

 

{WorkflowVariable:V_Items_Title} - Due : fn-FormatDate({WorkflowVariable:V_Items_Due_Date},"dd/MM/yyy") : <a href="/Applications/Diary/Lists/DiaryItems/EditForm.aspx?ID={WorkflowVariable:V_Items_ID}">Update</a>.</br>

 

 

 

Add the Built string into a collection variable. 

 

 

Update the Index to get the Next item Info

 

 

Last bit! Now we tidy the string collection variable, send the email and clear the Task String collection for the next loop.

 

 

Regular Expression. Get rid of the ;

 

 

Send the Email! Send an email to the Assigned Person.

 

 

Clear Collection string for next user.

The End.

 

Full Workflow layout. Example attached.

 

 

 

There's probably a more efficient way to to this, as we could get all the information in the initial lookup but my tiny brain can't make that leap

 

Also of course you can schedule this site workflow to run when you want.

 

T.

On the back of my previous post about running workflows, I've created a list with a single form and workflow as a basic example behind the premise. You can find them attached.

 

I'm not a fan of running workflows. Where I can, I will look to process a form in a single pass of the workflow. It will set the stage, status, Assigned, content type, permissions and send emails in a single pass. It will only have one list ( No Task List ) 

 

When I started using Nintex I quickly found that some of the actions that require the workflow to pause and request data are great until you want to make changes. Ooh I need another stage or another field on the approval form. Oh god I have 3000 of these in flight. I need to adjust the task form and restart all the workflows and somehow get them back to the current stage they were at. 

 

With this approach that pain goes away. If I've added another field or stage, next time the form is processed it'll take into account those changes.

 

Onto the example. It's a simple request with an approval and review stage. My actual solution would be more along the lines of my original post, with a 'stages' list to lookup the info and multiple content types for the different forms (stages) but for this example, everything is on the one form so you can download and have a look yourself.

 

There is a single workflow that runs on new or modified. Based on a WorkflowProcess field, the workflow makes a choice as to the stage you've chosen, looks up the relevant data for that stage and updates the item to that stage. Buttons on the form are linked to the WorkflowProcess and simply enter a different stage value into that field for the workflow to work out which stage you want.

 

Another advantage of this is the ease at which you can move items about. If I type into the WorkflowProcess the stage I want the form to goto, the workflow runs as if the button had entered the value.

 

 

On our New form the button is linked to 

 

So the workflow runs and looks for the relevant data for that stage.

 

and updates the item info with the new stage, status and who to assign it to.

The form has now changed to the 'Approver' view. In this example I've used rules to hide the different sections. A better solution would be to have a content type (form) for each stage.

 

The advantage here is we are still using one list. It's the same item the applicant created. No task form to bring any required info back to. All the info is already on the form for the approver. I just disable the fields already input.

 

 

Here the Approver can send it on for review or reject it back. All the buttons are doing is entering stage 2.0 or 0.0 into the workflowprocess field.

 

Onto the review stage and as before I can see all relevant info and approve or reject. The form also shows an Audit and any comments that have been added along the way.

 

That's it. The reviewer can reject it back a step or approve and finish the item.

 

Ok! So apologies if I've stated the bleeding obvious. I've just been learning on the way by playing and reading this forum!

 

So advantages in a nutshell....

 

Single list. No need for a separate task list.

All the data captured during the process is captured in a single item.

Attachments. One item again. Attachments are there at any stage.

No running workflow. Items are processed to the next stage in a single pass.

Easily move items between stages as an admin.

Changes to forms or workflow are applied the next time the item is opened and \ or processed.

 

List and workflow is attached if you want to have a play.

 

T

Hello!

 

The requirement for doing this was as follows. I have a few lists across various sites that have near to 20,000 items in them. Absences and training registrations for example. When staff leave the company, I wanted to move their relevant items out of the main list into an archive list. I built a site workflow for each of these lists (they reside in different sites ) that allowed me to enter the users logon and items matching the logon would be copied to the archive and deleted.

 

Hence the reason for this post. I wanted to build a parent site workflow, which would allow me to choose the logon as normal and then pass that logon to each of my site workflows and run them, rather than me running each one individually.

 

So I'd not done this myself before so I'm sharing my findings after using the following resource...
https://community.nintex.com/docs/DOC-1048

 

In this example I have 3 site workflows that I'm looking to run and pass a parameter into. Training, Absences and Documents to read.

Note : Each archive workflow has a single parameter ( StaffLogon ) that is ticked so to appear on the start form.

 

Creating a new site workflow on the root of my site, it just needs a couple of variables and two actions for each workflow to run.

 

 

V_Staff_Logon is the parameter that I will populate when the main workflow runs.

V_Parameter1 is the parameter that will be passed off to each child workflow.

 

Each child workflow requires the following. Note I need the build string for each child workflow because they don't all have the same parameter name. If your parameter name is the same in all your child workflows you only need one build string.

 

 

The build string action configuration is very simple.

 

 

<Data>
<V_Staff_Member>{WorkflowVariable:V_Staff_Logon}</V_Staff_Member>
</Data>

 

V_Staff_Member is the parameter name for the child workflow that I'm passing into. You can see I've put the starting form variable as the data to pass. {WorkflowVariable:V_Staff_Logon}

 

The resulting string is then saved in V_Paramteter1.

 

The webservice action is also quite simple...

URL : This is the web address of where your child workflow resides plus _vti_bin/NintexWorkflow/Workflow.asmx
The username and password is that of an account with the relevant rights.

 

Web Method : StartSiteWorkflow.

 

WorkflowName : The name of the child workflow.

 

AssociationData : This is the parameter that's passed onto the child workflow. In this example it's the parameter from the build string action.

 

Note : make sure Encode inserted tokens is ticked.

 

That's it. You just need to add the extra child workflows, configured as required.

 

 

T.

Today I am going to illustrate practically how to capture LAZY approval comments from inside mail body in NINTEX on-premise. There could be different ways but the way I have implemented in recent project seems to be very easy and useful.

 

Actually from any task component inside in the workflow if you enable LAZY approval recipient will get an email in his mail box.(Configuring lazy approval : Click here)

User can then simple reply back to the mail putting his opinion (Like Approved, Reject, Rework etc) in the first line and additionally can put comments in the next line to move the workflow further. Its something looks like as follows:

 

 

Here Approved is the action word and the comment is ‘Everything looks good. Approving for the next step.’ (Highlighted in yellow colour)

We want to extract this comment i.e. ‘Everything looks good. Approving for the next step.’ from the mail body and log it.

Assuming user always will put additional comments from the second line (in first line it's assumed to be the keywords/opinion like Approved, Reject, Rework etc). Go through the following steps to extract the comments as follows:

 

Remember:
1. Set default value of index to 0
2. Set default value of Startindex to 0

 

Workflow overall structure looks like as follows:

 

 

 

Detail configuration of each component:

 

There are 12 components involved in the workflow to accomplish it. Details of each component in chronological order are given as follows:

 

                                                                              

 

N.B. Here ‘EmalContentSingleLine’ variable and break tag (<br/>) is appended with previous comment to give the new comment i.e. Comment = Comment + EmalContentSingleLine + “<br/>”

 

 

Hope this will ease your process to extract the comments from LAZY approval.

 

Today as a NETWOVIANS it’s a very special day and I am very happy to contribute to my community on behalf of NETWOVEN.

 

 

Cheers!

Intro

 

The topic of the Nintex Form Events has been covered before, most notably in the document located here: https://community.nintex.com/docs/DOC-1217

 

However, there are a few shortcomings and errors with this document undoubtedly because the Official SDK Documentation Help Page contains a lot of erroneous information (https://help.nintex.com/en-us/sdks/sdk2013/FormSDK/Topics/SDK_NF_CON_NF_Events.htm):

 

Though it would be easy to make an almost identical Blog or Document containing the corrected information, I wanted to take the time to delve a little deeper into how Nintex Forms fires its custom Events and the options it presents to you as a developer.

 

I should also take this time to get one of the bigger caveats of this blog out of the way. This is mainly for the Classic Forms and not the Responsive Forms. While I will get into how you can utilize them in the Responsive Forms, it's a HUGE hassle and ultimately isn't supported by Nintex... sadly. Until that is the case, it won't be particularly useful to that environment .  Actually, scratch that. No time to get into how to do this for Responsive Forms without making this a giant book. Sorry Responsive Users

All that aside… let’s get into it!

Brief Events Refresher

 

For the uninitiated, an event could be thought of as a notification. While Events are not a native part of the JavaScript Language, they ARE a part of the API presented to us by web browsers (specifically the DOM api), and because Nintex Forms are presented to us via the web browser, we have access to all of those events.

The special thing about Events is that you, as a developer, get to choose when you would like to or not like to pay attention, or ‘handle’, the event in question. Some of these exposed events may be familiar to you already. Most people who have done a little JavaScript have probably used or seen the ‘onclick’ event, the ‘change’ event, or the ‘blur’ event to name a few.

When you handle an event, such as ‘onclick’, you are saying to the browser, “Whenever someone clicks *some* element, I want to execute a chunk of code”.

 

Fundamentally it is this simple, but to learn more in depth please read: Introduction to events - Learn web development | MDN 

 

Nintex Form "Events" Primer

That being said, the 'Events' exposed to us in Nintex Forms are not like the events exposed to us by the DOM api / Web Browser. Instead, Nintex Forms Events are more like checkpoints. With a normal native event, you can call any of the exposed functionality built around them to alter the way that event is handled (see: Event.stopPropagation() - Web APIs | MDN). Nintex Form Events are actually called linearly just like any other function / expression, by the code that is executed whenever you interact with the Form in some meaningful way. 

 

You could think of the flow how Nintex Form Events work as being 

 

Native DOM Event (like "onclick") =>

Nintex Forms Processing Functions =>

Nintex Forms 'Starting Event' =>

Any Code That Was Passed Into That Particular "Event's" Collection =>

Continuation  of Nintex Forms Processing Functions =>

Nintex Forms 'Outro Event' => 

That Was Passed Into That Particular "Event's" Collection =>

Done

 

To give a more specific example, let's look at how the Add New Row button works on a Repeating Section. 

 

  1. User "CLICKS" on the Add New Row image. 
  2. This initiates / emits the (native) "onclick" event.
  3. When the Form was rendered, an Event Handler was setup on the form to handle this specific 'click' event on this specific image / link. The handler is as follows (courtesy of Nintex):
    formFillerDivCurrent.on('click', '.nf-repeater-addrow-link', function(event) {
      var addrowImage = NWF$(this);
      var thisRepeaterControl = NWF$(NWF$(addrowImage.closest('.nf-repeater'))[0]);
      NWF.FormFiller.Functions.BulkCalculationExecution = true;
      NWF.FormFiller.Functions.UseServerValueForCalculations = true;
      NWF.FormFiller.Functions.AddNewRepeaterRow(thisRepeaterControl, formFillerDivCurrent);
      NWF.FormFiller.Functions.BulkCalculationExecution = false;
      NWF.FormFiller.Functions.UseServerValueForCalculations = false;
      NWF.FormFiller.Functions.ProcessDeferredCalculations();
    });

    This handler is set to fire when you have clicked on an element that has the class "nf-repeater-addrow-link" and, after executing a few functions, eventually executes the AddNewRepeaterRow() function. 

  4. Inside of the AddNewRepeaterRow function lay all of the code to generate a brand new Repeater Row for you!
    If you were to look at the entire AddNewRepeaterRow function as a whole, it would look a lot like: 
    {
      AddNewRepeaterRow: function(thisRepeaterControl, formFillerDivCurrent) {
        var newRepeaterRow;
        var heightIncrease;

        NWF.FormFiller.Events.ExecuteRepeaterRowAdding(thisRepeaterControl);

        /*
          LOTS OF CODE DOING LOTS OF FUN REPEATING SECTION STUFF HERE
        */


        NWF.FormFiller.Events.ExecuteRepeaterRowAdded(newRepeaterRow);
      }
    }

    You'll notice that *around* the code where all of the 'fun repeating section stuff' happens are two lines of code that may seem familiar. 

    Specifically they are the lines: 
    NWF.FormFiller.Events.ExecuteRepeaterRowAdding(thisRepeaterControl);

    And:

    NWF.FormFiller.Events.ExecuteRepeaterRowAdded(newRepeaterRow);


    You may have also noticed that these Executed "events" are named in a particular way. This is the typical* layout of Nintex Form Events. Usually there is an "Intro" call that invokes things at the very beginning of something BEFORE it has even started, and an "Outro" call that invokes your code at the very END of whatever the main function's purpose was.

    In this case the Intro 'event' can be thought of as the RepeaterRowAdding, while the Outro 'event' can be thought of as RepeaterRowAdded.

    When RepeaterRowAdding is invoked...

  5. Any function that you have passed into the NWF.FormFiller.Events.RegisterRepeaterRowAdding() function, will be executed. 

    For instance, if I had the following code in the Custom Javascript section of the Form Settings (Classic Forms): 
    NWF.FormFiller.Events.RegisterRepeaterRowAdding(function(){
      console.log("The Row Hasn't Been Created Yet!"); 
    });


    Then once the ExecuteRepeaterRowAdding function was called during the AddNewReapeaterRow function, you would see the message "The Row Hasn't Been Created Yet!" in the console window of your browser! 



  6. The Same things will happen with the ExecuteRepeaterRowAdded function. Any number of functions that you have passed using the NWF.FormFiller.Events.RegisterRepeaterRowAdded() function will be executed at this time. 

    For instance, if I had the following code in the Custom Javascript section of the Form Settings (Classic Forms):
    NWF.FormFiller.Events.RegisterRepeaterRowAdded(function(){  
      console.log("The Row Has Been Totally Created!");
    });

    Much like before, you would see the console message "The Row Has Been Totally Created!" after the new Repeater Row had been added to the form. 

  7. With everything finished, the other remainder code executes and the user is none the wiser! 

 

Now that you understand how these work a bit more intricately, let's take a look at a list of all the available Nintex Form Events we have available to us! 

 

Available Form Events

 

Below is a list of every available Nintex Forms Event that will fire during the course of Form Initialization (loading) stage when you load up a form. Any arguments passed to the Event Function has been noted as a comment inside of the code example, along with a few console outputs to help you see exactly what is happening.

 

(Note 1: A few terms I use in here are things like "inner-control" or "outermost filler div". If you are unfamiliar with how Nintex Forms generates its HTML for the controls, it can typically be thought of as: 

<div class="nf-filler-control aka:OUTER CONTROL">
  <div class="nf-filler-control-border">
    <div class="nf-filler-control-inner">
      <div class="something-sometimes">
      <probably your INNER CONTROL(S)/>
      </div>
    </div>
  </div>
</div>

 

This is an terrible exaggeration, but anytime that you seem me write something like NWF$(outermost filler div); you know that the jquery object that is returned to you is referencing the outermost layer of the target control and NOT the innermost element which contains that actual VALUE of that control)

(Note 2: You'll notice that I have used colors for the names of the below events. The key is as follows:


Red: Indicates that the event is fired only ONCE during the loading of the Form, and never again.

 

Blue: Indicates that the event is fired MULTIPLE TIMES, but ONLY during the loading of the Form and never after.

 

Plum: Indicates that the event is fired both during the Form Load, and during the Normal Runtime of the Form after the user is able to interact with it.)

 

Lime: Indicates that the event is fired after the Form has been Loaded during Normal Runtime only!)

 

RegisterBeforeReady: This is the first Nintex Form event that fires AFTER all of the custom JavaScript has been loaded into the Form (Classic). This event will ONLY fire ONCE during a Forms Initialization. 

NWF.FormFiller.Events.RegisterBeforeReady(function () {
  console.log("Executing 'RegisterBeforeReady' ");
  /* arguments[0] === undefined */
});

 

RegisterControlProcessing: This event fires any time a Form Control is being processed during the initial generation of the Form. As far as I know, this is the only time this event fires. 

NWF.FormFiller.Events.RegisterControlProcessing(function () {
  console.log("Executing 'RegisterControlProcessing' ");
  console.log("Processing Control: " + arguments[0].closest(".nf-filler-control").attr("data-controlname"));
  /* arguments[0] === NWF$(inner-control) */
});

 

RegisterControlProcessedThis event fires any time a Form Control has completed processing during the initial generation of the Form. As far as I know, this is the only time this event fires. 

NWF.FormFiller.Events.RegisterControlProcessed(function () {  
  console.log("Executing 'RegisterControlProcessed' ");
  console.log("Processed Control: " + arguments[0].fillerDiv.attr("data-controlname"));

  /* arguments[0] === {
    fillerDiv: NWF$(outermost filler div),
    formControl: fillerDiv.children().children().children(),
    formFillerDivCurrent: NWF$("#formFillerDiv")
  }; */

});

 

RegisterControlHeightChangePropagating: This event fires any time a Form Control has to adjust its height because of something other than a Rule, and subsequently pushes that height change to every Form Container, eventually ending with a resize of the Form Canvas itself. When a Form is initializing, the Repeating Section will typically fire this as it generates its hidden 'root' row, and then again for it's 1st visible row. 

NWF.FormFiller.Events.RegisterControlHeightChangePropagating(function () {

  console.log("Executing 'RegisterControlHeightChangePropagating' ");
  console.log("Height Change Propagating For: " + arguments[0].attr("data-controlname"));
  /* arguments[0] === NWF$(outermost filler div); */
});

 

RegisterControlHeightChangePropagated: This event fires after all of the Control's Siblings have been repositioned, and its Parent Containers and Canvas have been resized. This follows the RegisterControlHeightChangePropagating event. 

NWF.FormFiller.Events.RegisterControlHeightChangePropagated(function () {

  console.log("Executing 'RegisterControlHeightChangePropagated' ");
  console.log("Height Change Propagated For: " + arguments[0].attr("data-controlname"));
  /* arguments[0] === NWF$(outermost filler div); */
});

 

RegisterAllControlsProcessed: This event fires after all of the Form Controls have been placed onto the Canvas and are ready to have their Formatting Rules processed. 

NWF.FormFiller.Events.RegisterAllControlsProcessed(function () {

  console.log("Executing 'RegisterAllControlsProcessed' ");
  /* arguments[0] === NWF$("#formFillerDiv"); */
});

 

RegisterControlShowHidePropagating: This event fires whenever a Formatting Rule that would Hide or Show the Control is being processed. This will only fire if the outcome of the rule would actually change the visibility of the Control.

NWF.FormFiller.Events.RegisterControlShowHidePropagating(function () {

  console.log("Executing 'RegisterControlShowHidePropagating' ");
  console.log("Show Hide Propagating For: " + arguments[0].attr("data-controlname"));
  /* arguments[0] === NWF$(outermost filler div); */
});

 

RegisterControlShowHidePropagated: This event, much like RegisterControlHeightChangePropagated, will accompany the RegisterControlShowHidePropagating event as indication that any height changes that would affect any other control, container, or canvas, have finished and control is about to be given back to the user. 

NWF.FormFiller.Events.RegisterControlShowHidePropagated(function () {

  console.log("Executing 'RegisterControlShowHidePropagated' ");
  console.log("Show Hide Propagated For: " + arguments[0].attr("data-controlname"));
   /* arguments[0] === NWF$(outermost filler div); */
});

 

RegisterRuleProcessed: When a Formatting Rule that Hides / Shows a Control has been successfully propagated, this event will fire indicating that the Rule has been fully processed. This is one of the few events that has no 'Intro' sibling so there is no way to know beforehand when a Rule is 'processing'. 

NWF.FormFiller.Events.RegisterRuleProcessed(function () {

  console.log("Executing 'RegisterRuleProcessed' ");
  console.log("Processed Rule For: " + arguments[0].resultControl.attr("data-controlname"));
  console.log("Hidden Status: " + arguments[0].hide);
 
  /* arguments[0] === {
    hide: Boolean(),
    resultControl: NWF$(outermost filler div)
  }; */

});

 

RegisterBeforeFillerVisible: This event fires right before the Controls on the Form Filler become visible to the User. 

NWF.FormFiller.Events.RegisterBeforeFillerVisible(function () {
  console.log("Executing 'RegisterBeforeFillerVisible' ");
  /* arguments[0] === undefined */
});

 

RegisterAfterReady: This event fires once the Form Filler becomes visible (that is, after 'RegisterBeforeFillerVisible'), and is the LAST event to fire after a form loads and is usable! 

NWF.FormFiller.Events.RegisterAfterReady(function () {
  console.log("Executing 'RegisterAfterReady' ");
  /* arguments[0] === undefined */
});

 

RegisterRepeaterRowAdding: This event fires any time the user clicks on the 'Add New Row' link / image, or the click event is trigged on said link / image. This event takes place BEFORE any of the New Row has been generated! 

NWF.FormFiller.Events.RegisterRepeaterRowAdding(function () {
 
  console.log("Executing 'RegisterRepeaterRowAdding' ");
  console.log("Repeater Row Being Added To: " + arguments[0].closest(".nf-filler-control").attr("data-controlname"));
  /* arguments[0] === NWF$(Row Container ".nf-repeater"); */
});

 

RegisterRepeaterRowAdded: This event fires AFTER a New Row has been added to a Repeating Section.

NWF.FormFiller.Events.RegisterRepeaterRowAdded(function () {
 
  console.log("Executing 'RegisterRepeaterRowAdded' ");
  console.log("Repeater Row Added To: " + arguments[0].closest(".nf-filler-control").attr("data-controlname"));
  console.log("Repeater Row Added: " + arguments[0].attr("id"));
  /* arguments[0] === NWF$(currentRow);*/
});

 

RegisterControlResized: This event, as far as I can tell, will only fire in-between the RegisterRepeaterRowAdding and RegisterRepeaterRowAdded events, and ONLY when a control that is inside of the New Row is hidden (by way of a rule or otherwise) at the time that the row is being generated. 

 

So if you had a control inside of a Repeating Section that was hidden until the user did something to a different control on the form, or in that repeating section, if that control's state was set to hidden upon the clicking of the Add New Row button, then this event would fire. 

NWF.FormFiller.Events.RegisterControlResized(function () {

  console.log("Executing 'RegisterControlResized' ");
  console.log("Control Resized For: " + arguments[0].formControl.closest(".nf-filler-control").attr("data-controlname"));
  console.log("Resize Height Difference: " + arguments[0].heightDifference);
 
  /* arguments[0] === {
      formControl: NWF$(outermost filler div).children().children().children(),
      heightDifference: Number()
    }; */

});

 

RegisterRepeaterRowDeleting: This event is fired when the user clicks on the 'X' of a Repeating Section Row to delete the row, BEFORE the Row has been deleted. It should be noted that, by default, this event will fire EVEN IF you are clicking the delete X on the only available row, meaning that if you have any code attached to this to do something, you'll need to be careful and handle the actual 'click' event on the delete button itself to make sure that the Row in question isn't the ONLY row! Otherwise, you're going to have a bad time. 

NWF.FormFiller.Events.RegisterRepeaterRowDeleting(function () {

  console.log("Executing 'RegisterRepeaterRowDeleting' ");
  console.log("Repeater Row Being Deleted From: " + arguments[0].closest(".nf-filler-control").attr("data-controlname"));
  console.log("Repeater Row Being Deleted: " + arguments[0].attr("id"));
  /* arguments[0] === NWF$(currentRow); */
});

 

RegisterRepeaterRowDeleted: This event is fired AFTER a Row has been successfully deleted.

NWF.FormFiller.Events.RegisterRepeaterRowDeleted(function () {

  console.log("Executing 'RegisterRepeaterRowDeleted' ");
  console.log("Repeater Row Deleted From: " + arguments[0].closest(".nf-filler-control").attr(
    "data-controlname"));
  /* arguments[0] === NWF$(Row Container ".nf-repeater"); */
});

 

(Note 3: There are two other Nitex Form Events, 'RegisterBeforeFillerVisibleFinal' and 'RegisterAfterFillerVisible', but I have never had them actually fire or be activated in the normal course of testing. Because of that I have left them out of the above Events)

 

The Order Of Operations

 

As you may have been able to tell already by the above list, the Nintex Form Events follow a fairly linear path when the form is loading. This gives you several opportunities to infer where you are at in terms of the loading process, and can help you to figure out the best places to do certain operations. While most people will probably stick to just using the RegisterBeforeReady and RegisterAfterReady events, it can still be helpful to know how a Form is loaded proper. 

 

Essentially, the order is as follows:

 

  1. All Javascript Code Loaded from the 'Custom Javascript' section of the Settings => Custom Javascript Panel
  2. Each line of 'http' included JavaScript, in order of appearance, listed in the Settings => Advanced => Custom Javascript Includes
  3. RegisterBeforeReady
  4. Native DOM 'ready' Event (or: NWF$(document).ready) 
  5. RegisterControlProcessing (if there are controls)
  6. RegisterControlProcessed (if there are controls)
  7. RegisterControlHeightChangePropagating (if there are controls that load with Height Changes like a Repeating Section)
  8. RegisterControlHeightChangePropagated (if there are controls that load with Height Changes like a Repeating Section)
  9. RegisterAllControlsProcessed (if there are controls that have been processed)
  10. RegisterControlShowHidePropagating (if there are controls that get hidden by way of a Formatting Rule)
  11. RegisterControlShowHidePropagated (if there are controls that get hidden by way of a Formatting Rule)
  12. RegisterRuleProcessed (if a control has a Formatting Rule that was processed)
  13. RegisterBeforeFillerVisible
  14. RegisterAfterReady (Done!) 

 

Other cases where this might be important would be if you are using the Page Viewer control to load in an iFrame of a different page (or Form) onto  your current one. While the iFrame exists upon the initialization of the main Form, the contents of the iFrame are not loaded until AFTER the RegisterAfterReady has fired! If you were to have Nintex Form with a Page Viewer to a different Nintex Form, you would need to wait until the innermost child Window (that is: the embedded iFrame Form) called its RegisterAfterReady event before you could be certain that everything was loaded! 

 

Freebies (AKA: Default Events I Use)

 

I have a few Nintex Form Events that I use in almost every Form. Below are the ones that get the highest usage, and that shouldn't affect anything unless you're already doing major javascript dev work. 

 

  1. Load NF.BaseDataAccessHelper: If you're a version of Nintex Forms which has the Responsive Forms in it, and are sometimes experiencing instances of your Repeating Sections for the Classic Forms not loading their borders correctly, it could be because of this missing library. This is by no means something that most of you should ever need, but for my environment, it's absolutely necessary for most Forms. Oddly, it loads correctly in a few... but there is no rhyme or reason as far as I can tell  

    NWF.FormFiller.Events.RegisterBeforeReady(function () {
      "use strict";

      try {
        if (NF.BaseDataAccessHelper === undefined) {
          NWF$.getScript(_spPageContextInfo.siteAbsoluteUrl.replace(/sites.+/, "") + _spPageContextInfo.layoutsUrl +
            "/NintexForms/JavaScriptStringHandler.ashx?" + "resourceType=jsfile&" +
            "fileName=NF.BaseDataAccessHelper.js&" + "culture=" + _spPageContextInfo.currentCultureName);
        }
      } catch (error) {
        console.log("Unable to load NF.BaseDataAccessHelper");
      }
    });
  2. Fix Canvas Resizing Issues: This is actually (4) different Nintex Form Events. Because all of the internal code that resizes the Form Canvas incorrectly does so, I have had to implement a low cost and easy solution so that I can resize controls to my heart's delight. By using these four Events and code therein, any control size change that results in the Canvas being resized will not ruin your form! 
    NWF.FormFiller.Events.RegisterControlShowHidePropagating(function () {
      "use strict";
      outerDiv.data("outerDivHeight", outerDiv.height());
    });

    NWF.FormFiller.Events.RegisterControlShowHidePropagated(function () {
      "use strict";
      if (arguments[0].data("RepositionControls") === true && outerDiv.data("outerDivHeight") !== outerDiv.height()) {
        outerDiv.outerHeight(outerDiv.height());
        outerDiv.data("outerDivHeight", outerDiv.height());
      }
    });

    NWF.FormFiller.Events.RegisterControlHeightChangePropagated(function () {
      "use strict";
      outerDiv.outerHeight(outerDiv.height());
    });

    NWF.FormFiller.Events.RegisterAfterReady(function () {
      "use strict";
      outerDiv.outerHeight(outerDiv.height());
    });

     

  3. Fix Validation Rules on Repeating Section: Since SharePoint 2013, there seems to be an issue with how the Validation Rules are attached to the controls on the New Row of a Repeating Section. This is, as far as I know, the easiest way to correct the problem so that your controls will validate (and more importantly, style!) across your entire form as one would expect! 
    NWF.FormFiller.Events.RegisterRepeaterRowAdded(function () {
      "use strict";
      ValidatorOnLoad();
    });
  4. Prevent the Delete Row Button From Firing the RegisterRepeaterRowDeleting Event: As mentioned above, by default, the Nintex Form Event 'RegisterRepeaterRowDeleting / RegisterRepeaterRowDeleted' will fire ANY TIME you click on the Delete Row button even if there is only (1) Row, and nothing to delete! This can cause all sorts of problems if you have code running when those events are fired. While this isn't a normal Nintex Forms Event, it is an actual DOM event, and because of that, we can actually prevent that code that is normally fired when you click that button from ever happening
    NWF$(".nf-repeater-deleterow-image").on("click", function (event) {
      var targetControl = NWF$((event.target) ? event.target : event.srcElement);
      var targetRow = targetControl.closest(".nf-repeater-row");
      var visibleRows = targetRow.siblings(".nf-repeater-row:not(.nf-repeater-row-hidden)");
      if (visibleRows.length < 1) {
        event.stopPropagation();
      }
    });


 

Outro

 

As you can see, there is a surprising amount of information that can be gained by understanding how the Form is behaving during its creation period and while it's 'live' during runtime. Using the above tools, you too should be able to do more interesting things using your Form, or at least create a sensible approach to untangling the mess of "when should this thing fire?". 

 

If you catch any errors in the above post, or you have additional Event related information to share, as always, leave a comment below so that an edit can be made! 

 

I hope this helps some of your developers out there in Nintex Land! 

hulisanil

nintex 2013 updates

Posted by hulisanil Mar 7, 2018

We have nintex form/workflow 2013 version 2.9.0.0 now want we want to run the updates but we doesn't seem to have the option to, Attached is the screenshot. Please advise.

Many times we might have noticed an email notification saying, "A scheduled workflow failed to run. Check the workflow is not already running or in an error state". I recently faced this issue and my mail box was flooded with emails notifications.

And there is no much information in the email except it is pointing to the workflow's schedule page and to workflow's status page.

When checked ULS logs and found an exception, "Microsoft.SharePoint.SPException: The sepcified user or domain group was not found".

 

Then I check for the user who scheduled the workflow and that user was no more working and his id got removed.

Fix: Open all schedule workflows's schedule and click "Save" with different user. 

Best practice: It is best practice to publish or schedule the workflows with a service account on PROD environment.

Other details: There could be other reasons to fail the scheduled workflows, below are the some helpful links to troubleshoot.

1. Link1

2. Link2

Description:

I have seen lot of developers like to put all the fields of original list inside the task form to give the exact look and feel/functionalities as like of the original form. This type of development have pros and cons from both side.

 

Pros: The task and the original form is having the exact look so that user can't distinguish and also can view/update the original list fields from task form on the course of running the workflow. Also reduce the headache of developers to develop. It's cool.

Cons: If we design the task form as like of original form, the size of the workflow get increased and consume more RAM during the run time. And if the instance of the workflow running inside the RAM get increased, its execution time, loading time etc. also get increased. Also mimicking all the task forms as like of original form, increase the development time and violates the re-usability principle.

 

Underlying Risk:
Now the situation is very risk. If user find the task form is taking substantial amount of time to load,substantial time to submit they could get irritated and can dislike to use NINTEX. This is our very recent experience we faced with a client. So we have to handle this situation very sensitively.

 

So, if a list is reasonably small then you can afford to put those fields(or a subset) inside task form but if a list is big, never ever try to mimic all the task forms as like of original form. Unnecessary it will increase the size of the workflow instance and increase the execution time and will have bad impact to the workflow performance. You can definitely put few fields that user want to see inside the task form but never try to mimic the look and functionality(rules, validations etc.) of the task form as like the original form.

 

Solution:
You can tell this is an infrastructural issues (RAM,CPU etc) from client end (On-premise) and they can install good machine in the place but still irrespective of those we can do something good in designing to enhance performance of the workflow.

To overcome this situation, it's a best practice to put a hyperlink inside the task forms that will redirect the user to open the original form in another browser. From there user can operate (read/update) on the original form. Here is the link where I have demonstrate to achieve in a pretty simple way.

 

https://community.nintex.com/community/dev-talk/blog/2017/11/15/enhance-user-experience-to-open-a-new-window-from-task-form-for-editing-purpose

 

In this way we can reduce the size (Bytes) of a running workflow instance (inside RAM) to a substantial amount by integrating the re-usability of Software development principle in NINTEX development and can make the application more faster and can also reduce the development time.

 

Hope you have enjoyed the blog.

MERRY X'MAS AND HAPPY NEW YEAR 2018!

Scenario and requirement:

In one of our project client was looking to add edit attachments in the course of running workflow. In task form you can drag the required fields (like text fields, dropdown fields etc) to edit directly (making some field level NINTEX configuration) but when you drag the attachment field in the task form you will simply get ‘True’ or ‘False’ value as a Boolean one. ‘True’ comes when you have attached any attachment in the original form during submission and ‘False’ if you not. You can’t even display the attachment/s in the task form by default NINTEX propertiesand so there is no question of edit at all. But we can display it by configuring some workflow components and ‘Web Service’ calls. So, the situation is bit complex if user wants to add/edit attachment fields in course of running workflow.

Solution:

One of the solution you can use is to put a link of the original form (Since ID of the original item you can access from inside the task form) inside the Task form and can open that original form in edit mode and then after editing whatever fields you want to edit (including the attachment field as well) inside the original form and then after submission come back to the task form for your approval or rejection. So basically, it’s a three-step process:

1. Open the Task form.

2. Click on the link inside the task form to open the original form in edit mode.

3. Come back to the task form once again and submit.

Problems:

In this process, you will get again another problem. You will find that clicking the link of the original form from inside the task form will open the original form in same window. And then saving the original form you will be redirected to the original list. So, you will get lost from the task form from where you started operating on the original form. This is not desirable. So, what we can do in this situation?

Solution:

Now if we can open the original form from inside the task form in new window our purpose can be resolved and user can have much better experience in filling up the forms. So, in this case user have two windows opened side by side to complete the operations. First one is the task form and another one is original form that he/she wants to edit. And after editing and submitting the original form he/she then come back to the task form (already opened in another window) to complete the entire operations.

To open the original form from task form in new window NINTEX doesn’t have a default support. For that you have to customize by a small chunk of code. Here it’s the implementation:

Step 1:

Place a calculated field inside the task form. And configure the Name and Formula as follows:

Step 2:

Drag ‘Rich Text’ control inside the task form and insert a hyperlink inside the ‘Rich Text’ control and configure as follows:

Step 3:

Now goto Settings and click on “Custom JavaScript” inside the Task form as follows:

Step 4:

Paste the required script:

Hope this will enhance the user experience.Frank Field

I would like to share my solution to a little problem that I recently encountered in a project.  I was using tabbed forms and noticed that submitting the form, if you re-open the form in view mode you will see that the form is not appearing with first tab selected. It is selecting the tab last viewed and displaying the visible panel for that tab. What’s happening here is the choice control is saving the value internally of last option (Tab) selected before the form is saved and that’s why when you are trying to view the form it’s selecting the last value it reached and displaying the required panel that is visible for that value. (Incidentially, if you’d like to know more about choice controls and rules, go here.)

That could really be confusing to the user of the form, but we can improve their experience!

 

So before saving the form if we can set the value of the choice control to the first option forcefully, the problem can be solved.

What to do?

 

Step 1:

For this you have to set ‘Store Client ID in JavaScript variable’ as yes and have to give ‘Client ID JavaScript variable name’ for the choice(Tabbed) control as follows:

 

Step 2:

Now Goto Settings and click on “Custom JavaScript” as follows:

Step 3:

Paste the required script to set forcefully the value of Choice(Tab) control

 

What the code snippet is doing here?

Before saving the form the required JQuery Submit function triggers first and it set the value of the choice control forcefully to the first option value(it could be different as well as per the requirement) before the form is saved. And now the if you open the form it will come up with the first tab selected.  

 

I hope this helps your users' experience.

vacoder

Remove WF Data and History

Posted by vacoder Sep 9, 2017

My farm is up to 170 Nintex content databases and I have been remiss in cleaning up old workflow data and history. Part of the reason for this is that we have a legal requirement to preserve some workflow data and try as I may I was never able to get a decisive answer to 'Exactly what data needs to be preserved?". Performance has been off lately so I decided to at least trim down the data from the maintenance workflows that we run. These are workflows that load a list from AD or changes the title of a list item. Nothing business critical and nothing that will land me in jail if I delete it .(kidding...I think).

 

You can tell how large your Nintex tables are by opening up SQL Server Management Studio, expanding a Nintex Content DB and highlighting 'Tables'. I'm on SQL Server 2014 but this is in earlier versions as well. Now in the ribbon Select 'Object Explorer Details' or simply hit the 'F7' key. Take a look at your WorkflowProgress and your WorkflowInstance tables. Some of our progress tables had 5 or 6 million rows. Across all 170 DBs we were over 100 million rows. That's not a huge number to SQL Server but given the fact that our performance was starting to take a nose dive I saw no reason to keep data that wasn't critical to our business in there. besides, if I didn't clean it up eventually it would get to be a very large number of rows so. Th eWorkflowProgress table is especially prone to bloat sinc eit stores a row for every action in ever workflow instance of every workflow in every site on your farm.

 

There are a couple of NWADMIN commands that clean this data up for you and these are what do the work in the script. These are PurgeHistoryListData and PurgeWorkflowData. I learned while testing the script that you have to first purge the workflow history list data and then purge the workflow data. If you do it the other way around you will end up with orphaned history list data as there will be no workflow Instance information to work with come time to kill the history. It sounds painfully obvious as I write this but at the time I had no idea but no harm done. It was Dev.

 

The script will go through every site in your web application and attempt to purge the workflows in the array you pass to it. The script could be modified to also use an array of sites if you wanted to work with a subset. 

 

It is very efficient in its use of CPU and RAM. I didn't notice a significant jump when I fired it up. It can take awhile to complete if you have never cleaned out your old data. It took mine 18 hours to finish in my production environment and a few hours longer on my QA farm but I have a lot of databases.

 

Enjoy!

 

PS. after running this on the farm that had a combined row count of over 100 million in the workflowprogress tables we ended up with just over 54 million rows across all 170 databases.

The Requirement :

To implement a department hierarchy structure using Employee information maintained in SharePoint Lists.

Solution and Implementation:

So rather than implementing a pure jquery solution , I saved myself some time and instead used Nintex runtime functions to retrieve the user profile properties from the user profile (sync to active directory).

Please refer my blog-post to see the implementation :

Using Nintex and Jquery to create a department hierarchy structure in SharePoint on-premise

 

Final Result

 

Please add in your feedback if any !

In my environment we are using host named site collections for a service that we offer to our clients. Each client has their own site collection and for security and data isolation we use dedicated content databases for both the SP and the Nintex databases. Occasionally a workflow or two will start acting wonky (usually after we upgrade our 3rd party software that we use Nintex to interact with). With over 160 clients you can imagine that it can be more than a couple having trouble and while we do get notified when workflows fail, sometimes a failing workflow is elusive. That's where PowerShell comes in. It may be possible to do this via CSOM but I've not experimented with that much. Using CSOM would let you write a script on your desktop and run it against your farm. It really depends on your permissions.

 

The trick to finding these workflows is looking at the workflows that are running on an item. Workflows in our environment run against SPItems though we also have a few that run on SPSites. 

 

After getting a reference to the spWeb and spList of your choice it's just a matter of looping through each item and inspecting each workflow, looking for the info you're after. The ParentAssociation.Name is the name of the workflow that you're looking at. In the example below I am looking for all previous versions on an item and writing them to a log if their state is Running, Faulting, Terminated. You can find your workflow names on the List under "Workflow Settings." in the ribbon. You can find internal states here.

 

foreach ($item in $list.Items) {
  foreach ($wf in $item.Workflows) {
    if($wf.ParentAssociation.Name -like "*Previous Version*"){
     if($wf.InternalState -match 'Running, Faulting, Terminated'){
     $counter++;

     write-output $item.ID "|" $wf.InternalState "|" $wf.ParentAssociation.Name  | Out-File $outfile -Append}
}
}
}

 

I have attached 2 versions of the script. One is for looking up workflows on a single list in a single site.Since I have vanity URLs I pass the sub domain and the name of the list for it to query. The second one is the farm one that looks at every workflow on every item on every list on every site on every web application in your SharePoint farm. It sounds like it would peg your CPU and chew up your RAM but its not bad. Try it on your DEV or QA farm first. 

 

I hope you find these useful and if you have any recommendations on improving them I'd love to hear them.

 

Dears,

 

Many Nintex customers working on Microsoft SQL Server are asking me how to trigger a Nintex Workflow (NWC) when an item/row is added to the database.

 

After looking at the "Start event" action settings in my NWC, Microsoft SQL Server connector is missing:

 

NWC Start event configuration

 

 

On the help portal for NWC, you can go to the following page related to Microsoft SQL Server connector and see that the feature is not yet available:

 


 

One of the solution is to use the "External Start" event:

 

 

 

You can refer to the blog post created by Renai Bell in order to provide a REST URL for the workflow:

 

Nintex Workflow Cloud External Start.

 

But still the challenge lays in the below:

How to call the above generated URL when an item is added to a table in my SQL database?

For sure it will not be a Transact-SQL trigger .

 

Let's note that in addition to the Transact-SQL language, we can use .NET Framework languages (C# for example) to create database triggers.

 

Among the benefits of using .NET Framework languages are:

  1. Language Richness by owning capabilities previously unavailable to SQL Server developers (We are using C# ).
  2. Debugging database triggers from Microsoft Visual Studio.

 

I will go for Common Language Run-time Integration (Commonly known as CLR) and create a trigger in .Net managed code. It will be executed like any other Transact-SQL trigger once an item is added to the database.

 

For more info on how to create a trigger in .Net managed code, check the below:

 

How to: Create and Run a SQL Server Trigger by using Common Language Run-time Integration

 

Below you can see my C# code for triggering event on item added to a table:

 

[SqlTrigger(Name = "UserNameAudit", Target = "Users", Event = "FOR INSERT")]
public static void UserNameAudit()
  {
   SqlTriggerContext triggContext = SqlContext.TriggerContext;
   SqlParameter userName = new SqlParameter("@username", System.Data.SqlDbType.NVarChar);

   if (triggContext.TriggerAction == TriggerAction.Insert)
    {
     using (SqlConnection conn = new SqlConnection("context connection=true"))
      {
       //Get UserName from inserted
       conn.Open();
       SqlCommand sqlComm = new SqlCommand();
       SqlPipe sqlP = SqlContext.Pipe;
       sqlComm.Connection = conn;
       sqlComm.CommandText = "SELECT UserName from INSERTED";
       userName.Value = sqlComm.ExecuteScalar().ToString();

       //Launch the external Start
       StartNWC(userName.Value.ToString());
      }
    }
  }

 

The above code will create a trigger named "UserNameAudit" associated to a table named "Users" on item inserted.

I will retrieve the value of the column "UserName" from the inserted item and then "send it" to my NWC in order to start.

 

Let's have a look on the StartNWC function where I will trigger my NWC by issuing an HTTP Request:

 

    public static void StartMyNWC(string UserName)
    {

        //Build HTTP Request
        HttpWebRequest Request = (HttpWebRequest)WebRequest.Create("Workflow URL with Token");
        Request.Method = "POST";
        Request.ContentType = "application/json";

        //Build the body of the Request
        using (var streamWriter = new StreamWriter(Request.GetRequestStream()))
        {
            string json = "{" +
            "\"startData\": {" +
                "\"se_user_name\": \"" + UserName + "\"" +
            "}," +
            "\"options\": {" +
                "\"callbackUrl\": \"\"," +
                "\"instanceToken\": \"\"" +
            "}" +
            "}";

            streamWriter.Write(json);
            streamWriter.Flush();
            streamWriter.Close();
        }

        //Issue the Request (Start the Workflow)
        Request.GetResponse();
    }

 

If you pay attention to the above code, you will find that I am sending the inserted "UserName" variable to the workflow.

Below you can check how to add a start event variable to my NWC workflow through the "Start event" action settings:

 

 

To know how to get the body and the URL of the HTTP Request with Token, please refer to  to the blog post created by Renai Bell or click on "External start URL" in workflow settings:

 

 

 

Finally, my workflow will start and and "UserName" value is handled.

I will send and email mentioning that a new user is inserted in a table "Users" in my Database:

 

 

 

Enjoy and runs on pure nintex adrenaline

Many times we have to validate attachment control inside a form on certain condition. For example, say, there is a checkbox on a form and when you check the checkbox you need to add an attachment (Mandatory) otherwise not. So how you will accomplish this? It's easy and here are the steps to follow:

 

  1. Create a custom function to check the named attachment is whether having a minimum attachment attached to it or not.
  2. Create a rule using that custom function where you have to pass the CSS class name of the attachment as a parameter to that custom function.

 

Follow the section below for detailed implementation:

 

The screen looks like as follows:

 

Now if you check the AttachmentFlag, it’s mandatory to attach attachments. For that follow the following steps:

 


 

Step 1:

Goto NINTEX Forms -> Settings -> Custom Javascript and write the following function CountAttachments

function CountAttachments(cssClassNameOfTheAttachment){ 

    return NWF.FormFiller.Attachments.GetAttachedFilesCount(NWF.FormFiller.Functions.GetFillerDivObjectForControl(NWF$("#"+NWF$("." + cssClassNameOfTheAttachment + " .nf-attachmentsRow")[0].id)).data('controlid'));

 }

as follows:

 

Step 2:

Select the attachment control and configure the CSS Class of it as follows:

Step 3:

Configure the name of the ‘Yes/No’ field (AttachmentFlag) as follows:

 

Step 4:

Now add a rule selecting the attachment control as follows:

N.B. Remember you have to pass the CSS class name of the Attachment control as a parameter inside the function CountAttachments().

Now when you submit the form checking the AttachmentFlag and without attaching any attachment the following messages will be displayed:

 

Hope this small blog will be helpful to you to validate any attachment control on demand. Thanks for viewing the blog!