Category Archives: DFFS

DFFS: Start SP2013 workflow from a button in a list item

The approach described below requires Dynamic forms for SharePoint to be set up in the form. You find DFFS here.

For this to work, your workflow must be set up to start manually, then you must go to the page where you can start the workflow and look at the button / link to get the “subscriptionId”. To do this, you can right click the button and select “inspect”. This opens the developer console and you can see the link like this:

<a href="javascript:StartWorkflow4('ab064e56-926c-477b-910e-0d3759f5b956', '12', '{18C41B2A-4C33-482F-BFC5-C06B92072B10}')" id="UI_Auto_ab064e56-926c-477b-910e-0d3759f5b956">ExampleWF</a>

The “subscriptionId” is the first parameter in the StartWorkflow4 function.

When you have the “subscriptionId”, add this to the custom js textarea in the DFFS:

spjs.workflow = {
	"text":{
		"successMessage":"The workflow was started",
		"errorMessage":"Something went wrong. To try again, reload the page and then start the workflow."
	},
	"data":{
		"dlg":null
	},
	"initListItemWF":function(subscriptionId){
		if(typeof SP.WorkflowServices === "undefined"){
			jQuery.getScript(_spPageContextInfo.webServerRelativeUrl+"/_layouts/15/sp.workflowservices.js",function(){
				spjs.workflow.start(subscriptionId);
			});
		}else{
			spjs.workflow.start(subscriptionId);
		}
	},
	"start":function(subscriptionId){
		var itemId = GetUrlKeyValue("ID");
		spjs.workflow.showProgress();
		var ctx = SP.ClientContext.get_current();
		var wfManager = SP.WorkflowServices.WorkflowServicesManager.newObject(ctx, ctx.get_web());
		var subscription = wfManager.getWorkflowSubscriptionService().getSubscription(subscriptionId);
		ctx.load(subscription, 'PropertyDefinitions');
		ctx.executeQueryAsync(
			function(sender, args){
				var params = new Object();
				var formData = subscription.get_propertyDefinitions()["FormData"];
				if(formData != null && formData != 'undefined' && formData != "")
				{
					var assocParams = formData.split(";#");
					for(var i = 0; i < assocParams.length; i++)
					{
						params[assocParams[i]] = subscription.get_propertyDefinitions()[assocParams[i]];
					}
				}
				wfManager.getWorkflowInstanceService().startWorkflowOnListItem(subscription, itemId, params);
				ctx.executeQueryAsync(
					function(sender, args)
					{
						spjs.workflow.closeDlg();
						SP.UI.Notify.addNotification(spjs.workflow.text.successMessage,false);
					},
					function (sender, args)
					{
						spjs.workflow.closeDlg();
						alert(spjs.workflow.text.errorMessage);
					}
				);
			},
			function(sender, args)
			{
				spjs.workflow.closeDlg();
				alert(errorMessage);
			}
		);
	},
	"closeDlg":function(){
		if(spjs.workflow.data.dlg != null){
			spjs.workflow.data.dlg.close();
		}
	},
	"showProgress":function(){
		if(spjs.workflow.data.dlg == null){
			spjs.workflow.data.dlg = SP.UI.ModalDialog.showWaitScreenWithNoClose("Please wait...", "Waiting for workflow...", null, null);
		}
	}
};

Then you can insert a HTML Section to one of your DFFS tabs with this code:

<input type="button" onclick="spjs.workflow.initListItemWF('ab064e56-926c-477b-910e-0d3759f5b956')" value="Start WF">

Post any questions in the forum.

Alexander

DFFS v4.365 released

Finally, after a long BETA period, latest version of Dynamic forms for SharePoint is released.

DFFS v4.365 – February 29, 2016

  • Added support for using DFFS with DocumentSets.
  • Added new trigger “Workflow status” that lets you check the status on a workflow in the current item.
  • Added option to share the Field CSS configuration between different forms in the same list.
  • Added new option to preserve the selected tab when navigating from DispForm to EditForm in a list item. You find this setting in the Misc tab.
  • Split the “showTooltip” out in a separate function to let advanced users override it.
  • Added new functionality to show a list of empty required fields above the form when the save is halted. The list is clickable and will take you to the correct tab / accordion and highlight the field. You can turn this feature on in the Misc tab. Please note that you must update the CSS files also.
  • Added option to set the default “To” and “Cc” in the “E-Mail active tab” feature to a people picker in the current form, or to a fixed email address.
  • Added option to send E-Mails from DFFS rules. You can configure the E-Mail-templates in the new “E-Mail and Print” tab in DFFS backend. Added support for delaying an email until a set “Send date” has been reached. Please note that this is only possible if you use the “Use custom list with workflow to send E-Mails”, and is not when using the built in functionality for sending E-Mails in SP 2013 (REST). You find more information on the help icon in the “E-Mail and Print” functionality in DFFS backend, and in the user manual. You find a video describing the workflow setup in the user manual.
  • Changed the “target” on the link to a document of type “pdf” or “txt” in a DFFS dialog so it will open in a new window.
  • For SP2007: Made the “Return to DispForm when editing an item and NOT opening the form in a dialog” checkbox visible in the Misc tab.
  • Fixed a possible backwards compatibility issue when using the latest version of DFFS with a configuration saved with an older version.
  • Fixed some issues with using “content type” as trigger in a DFFS form.
  • In triggers on date and time columns: added support for comparing with today like this:
    [today]+14 or [today]-5

    The number is the number of days you want to offset the value with. This same functionality can be used when comparing with a value pulled from another date and time column in the form – like this:

     {NameOfField}+14 or {NameOfField}-5
  • Changed the “debug output” to make it easier to read by collapsing some sections initially.
  • Fixed a bug with hiding a field by a rule while using the accordion functionality.
  • Fixed the “change trigger” on date columns so it will trigger the change event on invalid dates.
  • Changed the backend code for detecting the change of a PeoplePicker field.
  • Added support for using People pickers as trigger in SP 2007 and 2010. This requires that you update SPJS-Utility.js. This may not work 100% in all cases – post any findings in the forum.

You find the full change log here: https://spjsblog.com/dffs/dffs-change-log/

User manual

The user manual has been updated with the latest changes: https://spjsblog.com/dffs/dffs-user-manual/

Post any question in the forum

https://spjsblog.com/forums/forum/dynamic-forms-for-sharepoint/

Alexander

Time tracker in a DFFS enabled list

Here is an example of a simple time tracker in a DFFS enabled list.

Before you start you must set up DFFS. You find more info here.

Create the list

Create a custom list, and add these fields. Ensure you use the exact same FieldInternalName as described here. When the field has been created, you can change the name to whatever you like.

  • Title (Default field already present in the list)
  • Description (Multiple lines of text ) – This field is optional, and not required in the solution.
  • StartTimeString (Single line of text
  • TotalTimeString (Single line of text)
  • Activity (Multiple lines of text – plain text)
  • Log (Multiple lines of text – plain text)
  • TotalTime (Calculated) – with this formula – output as “Single line of text”:
    =TEXT(INT(TotalTimeString/1000)/86400,"hh:mm:ss")
  • Ticking (Calculated) – with this formula – output as “Yes/No”:
    =StartTimeString<>""

Configure DFFS

Enter DFFS backend in NewForm and EditForm, and set up DFFS like this (you can create NewForm first, and then clone it to EditForm):

TimeTrackerInDFFS_1

TimeTrackerInDFFS_2

TimeTrackerInDFFS_3

TimeTrackerInDFFS_4

Then add this code to the Custom JS textarea:

(function(){
 var a = [], b = [], tt;
 a.push("<tr style='font-size:18px;color:green;'>");
 a.push("<td colspan='2' style='padding:2px;'>");
 a.push("<span id='elapsedTime'></span><span id='totalTime'></span>"); 
 a.push("</td>");
 a.push("</tr>");
 $("table.ms-formtable").prepend(a.join(""));
 b.push("<span title='You can save and close the list item while the timer is running. It will keep tracking time until you edit the item and click \"Stop the timer\".'>");
 b.push("<input style='background-color:#C2CF8A;color:#444;' type='button' id='dffsTimeTrackerStartBtn' value='Start the timer' onclick='startTicker()'>");
 b.push("<input style='background-color:#D57C7C;color:#ffffff;display:none;' type='button' id='dffsTimeTrackerStopBtn' value='Stop the timer' onclick='stopTicker()'>");
 b.push("<span>&nbsp;</span>");
 b.push("</span>");
 $("input[id$='_diidIOSaveItem']:last").before(b.join(""));
 tt = getFieldValue("TotalTimeString");
 if(tt !== ""){
 $("#elapsedTime").html("Total time: "+getFriendlyTime(Number(tt)));
 }
})();

function startTicker(){
 var a= getFieldValue("StartTimeString");
 if(a === ""){
 setFieldValue("StartTimeString",new Date().valueOf());
 $("#dffsTimeTrackerStartBtn").hide();
 $("#dffsTimeTrackerStopBtn").show();
 $("#totalTime").html("");
 }
}

function stopTicker(){
 var a = getFieldValue("StartTimeString")
 , b = new Date().valueOf()
 , u = spjs.utility.userInfo(_spPageContextInfo.userId)
 , et = b-Number(a)
 , tt = Number(getFieldValue("TotalTimeString")) + et
 , log = getFieldValue("Log")
 , al = getFieldValue("Activity");
 setFieldValue("TotalTimeString",Number(tt));
 // Reset start time and log
 setFieldValue("StartTimeString","");
 setFieldValue("Activity","");
 if(a !== ""){
 if(log !== ""){
 log += "\n*******************\n";
 }
 if(al !== ""){
 al = "\n\nActivity log:\n"+al;
 }
 setFieldValue("Log",log+u.Title+"\nStart: "+new Date(Number(a)).toLocaleString(_spPageContextInfo.currentUICultureName)+"\nEnd: "+new Date().toLocaleString(_spPageContextInfo.currentUICultureName)+"\nElapsed time="+getFriendlyTime(et)+al);
 }
 $("#elapsedTime").html("");
 $("#totalTime").html("Total time: "+getFriendlyTime(tt));
 $("#dffsTimeTrackerStartBtn").show();
 $("#dffsTimeTrackerStopBtn").hide();
}

function getFriendlyTime(ms){
 var h, m, s;
 h = Math.floor(ms / 3600000);
 m = Math.floor((ms % 3600000) / 60000);
 s = Math.floor((ms % 60000) / 1000);
 return (h<10?"0"+h:h)+":"+(m<10?"0"+m:m)+":"+(s<10?"0"+s:s);
}

if(getFieldValue("StartTimeString") !== ""){
 $("#dffsTimeTrackerStartBtn").hide();
 $("#dffsTimeTrackerStopBtn").show();
}

setInterval(function(){
 var a = getFieldValue("StartTimeString"), b = new Date().valueOf(), tt = Number(getFieldValue("TotalTimeString"));
 if(a !== ""){
 $("#elapsedTime").html("Elapsed time: "+getFriendlyTime(b - Number(a))); 
 if(tt !== ""){
 $("#elapsedTime").append(" / Total time: "+getFriendlyTime(tt + (b - Number(a))));
 }
 } 
},1000);

Final result

When you press “Start the timer”, this is how it looks in the form:

TimeTrackerInDFFS_5

When you stop the timer, the total time is displayed like this:

TimeTrackerInDFFS_6

If you restart the timer again, it will count the current elapsed time, and the total time like this:

TimeTrackerInDFFS_7

You can save the list item with the timer running. When you  edit it again afterwards, press “Stop the timer” and save the item.

This is how it looks in the list view:

TimeTrackerInDFFS_8

Please note that the “TotalTime” field will only show the time after the timer has been stopped, and will not show the “live ticker”.

Post any questions in the forum for DFFS here

Alexander

 

AD-Group in SP-Group: Workaround for verifying membership

Change log
January 12, 2016
Fixed a bug with using “getByTitle” and not the correct “getByName” in the SP 2010 code example.

This is a workaround for verifying membership in a SharePoint group when the user is added to the group as a member in an AD-group, and not as an individual user.

For this to work, the SharePoint group must be set up to only allow members to view membership in the group:

You find two code examples below. The first one will work in SP 2013 only, but the last will work in both SP 2010 and SP 2013 (not SP 2007).

Disclaimer: I have NOT been able to test this as I don’t have any AD groups to add in my SP 2013 Office 365 test site.

Based on this post by Eric Alexander

How to set up a trigger in DFFS

In DFFS backend – add this code to the Custom JS:

SharePoint 2013:

function spjs_isCurrentUserInGroup(groupIdOrName){
 var endpoint;
 if(typeof groupIdOrName === "string"){
 endpoint = _spPageContextInfo.webAbsoluteUrl+"/_api/web/sitegroups/getbyname('"+groupIdOrName+"')/CanCurrentUserViewMembership" 
 }else{
 endpoint = _spPageContextInfo.webAbsoluteUrl+"/_api/web/sitegroups("+groupIdOrName+")/CanCurrentUserViewMembership" 
 }
 return jQuery.ajax({ 
 "url":endpoint,
 "type":"GET", 
 "contentType":"application/json;odata=verbose",
 "headers":{ 
 "Accept": "application/json;odata=verbose"
 }
 });
}

function checkADGroupMembership(){
 // 18 is the ID of the SharePoint group
 spjs_isCurrentUserInGroup(18).success(
 function(data){
 if(data.d.CanCurrentUserViewMembership){
 setTimeout(function(){
 spjs.dffs.triggerRule(["isInADGroup"]);
 },10);
 }
 }
 );
}

SharePoint 2010:

function spjs_isCurrentUserInGroup(groupIdOrName){
 var cc, gc, g, u;
 cc = new SP.ClientContext.get_current();
 gc = cc.get_web().get_siteGroups();
 if(typeof groupIdOrName === "string"){
 g = gc.getByName(groupIdOrName);
 }else{
 g = gc.getById(groupIdOrName);
 } 
 u = g.get_users();
 cc.load(u);
 cc.executeQueryAsync(
 function(sender, args){
 setTimeout(function(){
 spjs.dffs.triggerRule(["isInADGroup"]);
 },10);
 },
 function(sender, args){
 // No access
 }
 );
}

function checkADGroupMembership(){
 // 18 is the ID of the SharePoint group
 spjs_isCurrentUserInGroup(18);
}

The number 18 in the function “checkADGroupMembership” is the SharePoint group id, but you can also use the display name of the group – change it to match your group.

Add a rule to DFFS with the “Rule friendly name”:

isInADGroup

This rule is set up with the trigger “No trigger (must be triggered manually), and with all the actions you want to apply if the rule is triggered.

As this is a “manual trigger rule”,  you must add another rule to trigger this one when the form has loaded. This is necessary because the REST call cannot be used with the trigger “Custom JavaScript functions” directly.

To trigger the REST call / JSOM query, and the following trigger of the DFFS rule if the user is member of the group is done by another DFFS rule triggering on “The form is ready”.

Set this one up with the function name “checkADGroupMembership” in the “Run these functions / trigger these rules” field.

If the logged in user is member of the SharePoint group as a member in an AD-group, the rule “isInADGroup” will be triggered.

I hope this makes sense, and if not – post a comment below or in the forum.

Alexander

Redirect from NewForm to EditForm in DFFS

Change log
September 23, 2016
I had forgot to add “return false” in the PreSaveAction function – this could result in duplicates being added to the list.
January 05, 2016
Changed the code example to include the “InDlg” attribute if you are in a dialog.

Here is an alternative solution for redirecting from NewForm to EditForm when using DFFS.

This solution is based on entering NewForm, filling in the Title field, and hitting “Save” to continue in EditForm.

Here is an example on a NewForm

SaveAndContinue

Add this code to the Custom JS

function saveAndRedir(){
	var ok = spjs.dffs.check_Mandatory(["Title"]), data = {}, newItem, url;
	if(ok){
		data.Title = getFieldValue("Title");
		newItem = spjs.utility.addItem({"listName":_spPageContextInfo.pageListId,"data":data});
		if(newItem.success){
			url = location.pathname.substring(0,location.pathname.lastIndexOf("/")) + "/EditForm.aspx?ID="+newItem.id;
			if(GetUrlKeyValue("IsDlg")==="1"){
				url += "&IsDlg=1";
			}
			location.href = url;
		}else{
			alert(newItem.errorText);
		}
	}
}

function PreSaveAction(){
	saveAndRedir();
	return false;
}

This is it – test it and let me know how it works out  in the Forum.

Best regards,
Alexander

Dynamic forms for SharePoint v4.350 is out!

Production release is out!

I have finally finished the production release of DFFS v4.350 and vLookup v2.250 after a long BETA test period. I have not had all that much feedback on the latest BETA, and this can either mean there were no bugs, or that not so many have tested it.

I hope it is the first!

What is new?

The change log will be updated as soon as I can manage, but here is a few vital changes.

The installation process for all but the JSLink version for SP2013 has changed since the last production release. You find information in the updated installation manual. The user manual has also been updated with most of the new features, but I still have some parts left.

If you find a feature you cannot figure out, please look in the forum to see if the question has already been answered. If you cannot find it there, please post a new topic in the forum.

If you don’t have a user account, you find information in the top of each forum.

New license handling

All existing license codes (except the JSLink version) must be updated to a new format to support this new release.

This means you must send me an email to request an updated license.

Site collection scoped licenses

All site collection scoped licenses requires a “Challenge-Response” routine to generate the license key.

Please note that a site collection scoped license can only be used with one site collection. If you need more, you must upgrade your license. Read more here.

JSLink setup option

You find the “Challenge code” generation in the “Setup” page you created in the SPJS library.

CEWP setup option

You find a “License” tab in the backend or DFFS. The license added here will affect all DFFS instances in the current site.

Important information

I try to maintain backwards compatibility with older versions, but I cannot guarantee that all old configurations will upgrade without issues.

Back up you configuration before upgrading

Please BACK UP your configuration first by going to the Misc tab and Export the configuration to a text file.

This way you can restore your previous version if something did not perform as expected.

Plugins

All the plugins used with DFFS is included in this package

Download

Get the package here

Installation

See installation manual and user manual.

Best regards,
Alexander