17 January 2013

codeless: on-change workflows

/TECH
When I started working in SharePoint nearly 3 years ago, I noticed a severe lack of looping functionality built-in to InfoPath or SharePoint itself. This was irritating because when I started work, I was still a student learning C++ and there loops are life-blood. So, what was a programmer to do in a designer's system?

The place I noticed the greatest need for looping was actually in the workflows that our custom forms used to notify approvers. And when I arrived to the SharePoint team, workflows were done in such a way that it would start when the form was created and keep running, waiting for changes before proceeding, and finishing when the form reached its completed state. The real problem occurred when there was a issue with a form and the process had to be reset. This meant terminating the workflow, making the changes, and then restarting the workflow. Even then, the workflow had to go through each of the steps again, even if the change affected only the last step. Wouldn't it be nice if it could keep checking everything until it was actually complete? Yeah, like you can with a loop.

This is when I noticed that the SharePoint team didn't utilize the option that a workflow would run when an item was changed. There were reasons, good reasons for this, but if it's there we should at least understand why we weren't using it for that workflow. The first form I worked on I discovered a really good reason not to use the on change option: if your workflow changes a field/column for the item it is running on and then completes, it detects there was a change to the item and the workflow is triggered again. Welcome to the infinite loop of SharePoint. The workflow in question had to first set the form's Status and then emailed the next person in the process (me). Because it finished so quickly, the Status change was detected as a change and the workflow triggered again. And again. And again. And again. And it proceeded to send me a constant stream of emails while I frantically tried to stop the loop. 15 seconds later I was deleting the 60+ emails I had received.

But this only occurred because something was being modified in the current item by the workflow. I quickly learned that it is better to handle changes in the form template as much as possible. To solve the problem however, I employed another workflow feature: Wait for Duration. This enabled me to change the field, wait, and then send the email a couple minutes later. By having it wait the event handler no longer saw the change as recent enough to start the workflow again. The problem with this solution was that it slowed down the process. And I still had to worry about workflows spamming because several processes I work with use more than one workflow and often one of those has to make changes to the item. In these cases I employ a flag for each email to mark which ones have been sent already. The flag can be added to the library or content type directly, but I prefer to add it to the template. This is because InfoPath forms have a much more powerful rule system built in than the ones that libraries and workflows can do. An excellent example of using these flags is actually in a process I'm currently working on.

Workflows that trigger on-change were essentially the "loop" I was looking for. We also discovered that this method reduced the server load significantly, an unintended benefit. Ever since then my boss has asked me that when I'm rebuilding a workflow that if I can change a workflow to triggering on change that I should.

The best practice in my opinion is to assess what needs to be accomplished to see if the on-change workflow fits your process. In my case, most situations benefit from the on-change style workflow.

Oh, and always test the workflow by having it send to yourself first. You really don't want to have to explain yourself to your boss's boss as to why you flooded his inbox with God knows how many emails.

Until next time:
Work hard. Play harder.

04 January 2013

codeless: double eval

/TECH
My current job title is SharePoint Developer. However, my work is a lot more specific than that. Yes I develop for SharePoint, but more specifically I develop custom, codeless web forms using InfoPath as my primary design tool. The key here is that everything I do doesn't contain custom code but rather out-of-the-box functionality used creatively. And boy do I get creative. Over the next several blog entries I want to explore some of the codeless designs I've found, developed, and refined.

The first trick I want to talk about is one that I use a ton: the double eval. When I first started developing with InfoPath I found that there were several things I couldn't do that I could in C++. Now, I understand that InfoPath isn't a programming language, but it is based on web-technology and several web languages support. So why the hell can't I systematically grab data from a repeating field?! Well, you can. I remember looking at all the functions I could use in an expression once and when I got to eval(), I had no idea how to use it. Even the description of for using it was cryptic: "Returns a node-set containing the result of the expression for each set of elements in the context field." If you added it to the expression, you got the following template:
eval(double click to insert field, "type expression here")
Now I don't know about you but I learn much more about a function by seeing an example of it being used. I finally saw an example one day of the following expression from Infopath codeless programming (walkthrough) 2:
eval(eval(Person, 'concat(my:AccountId, "|")'), "..")
At first I couldn't figure out what was going on, but after I used it several times in different forms I figured out how the two eval() functions were working together. Let's break this down starting with the inner eval().
eval(Person, 'concat(my:AccountId, "|")')
This eval() is referencing the field Person and then using concat() on it. The trick here is that the concat() function is being run relative to where Person is located. This means that if you need to do a comparison to another field with your concat(), you need to write the xpath as if the concat was running on Person. Say you want to filter AccountId based on Department. If you were to look at the xpath for the two fields you might get something like this:
- MyFields
  - Person
    = AccountId
  = Department
You'll notice that Person and Department are parallel and AccountId is a child of Person. For our concat() above to filter AccountId using Department, it would have to be done like so:
'concat(my:AccountId[../../my:Department = "IT"], "|")'
What this does is back up twice relative to where AccountId is located and then looks for Department. It's really important to know where in the hierarchy an expression is going to run. You may have also noticed that the entire expression for the eval() is enclosed in single quotes, not double quotes. That's because the expression needs to use double quotes to function correctly, thus you change the overall encapsulation to single quotes.
eval(eval(Person, 'concat(my:AccountId, "|")'), "..")
The outer eval is easier to break down and is where the "looping" action actually occurs. The outer eval() is treating the inner eval() as the field it is working on and the ".." as the expression. The unique thing about the expression here is that it is looking for one thing: when the field has to go back or up a level in the hierarchy. As soon as that happens, the outer eval returns the results of the inner eval() that occurred on each instance of Person, in this case, a string of concatenations that results in the output of a single string of text. The output would look something like this:
jcool|cbrown|ppatty|lucyvanpelt|
This is now a really useful way to gather info into a single field for further use and/or processing. I've used it to concatenate the usernames from a SharePoint list to use in a comparison in the form for security, creating a list of approvals still needed, and even doing a sort of "group by" query on a repeating table.

Thanks to Alec Pojidaev and posting that little trick to his blog. It's come in extremely useful. Check out his blog for some other codeless solutions. Click here to return to my listing of "codeless" blog entries.

Until next time:
Work hard. Play harder.

codeless

/TECH
My current job title is SharePoint Developer. However, my work is a lot more specific than that because the I nearly exclusively develop custom, codeless web forms using InfoPath as my primary design tool. The key here is that everything I do doesn't contain custom code but rather out-of-the-box functionality used creatively. And boy do I get creative. Over the next several blog entries I want to explore some of the codeless designs I've found, developed, and refined. To keep things tidy, I'll preface each post title with "codeless" so you know what you're getting into and additionally keep links to all my "codeless" posts here. If you're working with InfoPath, I hope these articles help you.

"codeless" articles:
Until next time:
Work hard. Play harder.