Category: Sitecore

My 2019 Reflections

2019 is going great so far, wanted to share my contributions to the Sitecore community(Awesome!).

Presented Sitecore 9 Forms(Intermediate/Advance) in 7 SUG’s-

• April 18 2019 – SUG Bulgaria
• May 4 2019 – SUG Bangalore
• June 4 2019 – SUG Manchestor, NH
• June 6 2019 – SUG Belarus
• June 12 2019 – SUG Boston
• June 25 2019 – SUG NCR(Delhi -India)
• Aug 29 2019 – SUG Educador

 

The blog posts I have written and one of my blog post received ‘You are life saver, Thank you’ comment.

• Install Sitecore 9.1 quickly in 5 easy steps
• Sitecore 9 Forms: Redirecting to formbuilder on Submit?
• Sitecore 9 Forms: The required anti-forgery cookie __requestVerificationToken is not present
• Sitecore license file expired?
• Sitecore 9.1 Forms: Conditional Logic
• Sitecore 9 Forms: Custom Control – Conditional Section
• Sitecore 9 Forms: Success message
• Sitecore 9 Forms: Custom Submit Action
• Tips and Tricks : GIT Cherry Pick
• Sitecore Certification : Exam and Review
• Sitecore 9 Forms: Save Data
• Sitecore 9 Forms: Custom Regex Validation
• Sitecore 9 Forms: Custom Grouped dropdown
• Sitecore 9 Forms: Uncaught TypeError: Cannot read property ‘unobtrusive’ of undefined
• XConnect: Certificate was not found
• Sitecore 9 Forms: Access landing page fields in FormSubmitContext?
• Sitecore 9 Forms: The date range is invalid. Please select a date range that is within the range of the list.
• Sitecore Forms: Export Data to CSV shows Field Types on column header?
• Sitecore Forms: Redirecting to External URL

Youtube
• How to add Forms Custom Submit Actions – https://www.youtube.com/watch?v=wE_aaFN7GvY

Slack Community
• Active on #wffm-forms

Certification
• Sitecore 9.0 Certified Platform Associate Developer

Participation
• Hackathon

Conferences I attended
• SUGCON India
• SYMPOSIUM
• All SUG Boston meetups.

2020 Plans

Learn and contribute

  • Cortex
  • Sitecore AI Personalization
  • Sitecore 9.3 Forms
  • Sitecore 9.3 Overall

Co-organize (Virtual)

  • Quarterly SUG-Pittsburg meetup

Present

  • SUG Meetups
  • Sitecore SUGCON EU/Symposium 2020
0

Sitecore Forms: Export Data to CSV shows Field Types on column header?

I exported the Forms data using Export the selected data into CSV button and noticed one of the column header was showing field type not field name.

I checked at many places, couldn’t figure out. Later I checked on Content Editor – Forms and found that item name was showing the field type!

I gave the appropriate Field Name in Forms and the CSV file looks good now. 

Forms Field Name sets Item Name and Label sets the Title field in Content Editor.

Don’t forget to publish the Forms!

Happy Sitecoring.

0

Sitecore Forms: Redirecting to External URL

I came across a scenario where I need to redirect to a external url(thank you page) after form submission. It’s achievable using formSubmitContext’s RedirectUrl property on your Custom Submit Action.

Here is the code snippet – 

protected override bool Execute(string data, FormSubmitContext formSubmitContext)
		{
//Prepare model
//WebApi Call

//Redirect to external URL
var thankYouPageUrl = $"{HttpContext.Current.Request.Url?.Scheme}://{HttpContext.Current.Request.Url?.Host}/[thank-you-page-path]/";

formSubmitContext.RedirectUrl = $"{thankYouPageUrl}?id={add-any-querystring-if-needed}";
formSubmitContext.RedirectOnSuccess = true;              
return true;

}

Hope this helps someone. Happy Sitecoring!

0

Sitecore 9 Forms: The date range is invalid. Please select a date range that is within the range of the list.

I deployed the forms to Staging environment and see how the forms were performing.

I exported the data using Export form data into CSV button and i received ‘The date range is invalid. Please select a date range that is within the range of the list.‘ error.

I tried different range and it threw the same error. I checked the db([project]. ExperienceForms) and there was NO DATA!

I submitted the form and tried again. It downloaded the CSV file with an entry on it.

Hope this helps someone. 

Happy Sitecoring.

0

Sitecore 9 Forms: Access landing page fields in FormSubmitContext?

I came across a scenario where I needed to access landing page fields(the page where we add Forms) in Custom Submit Action’s FormSubmitContext. 

By default, the page item isn’t known at the Submit Action. So started thinking should i create a custom hidden field or use the Forms Extensions module? At the end of the day, i didn’t need either. 

Here is the quick way to access the current page using HttpContext’s AbsolutePath.

protected override bool Execute(string data, FormSubmitContext formSubmitContext)
{
 
var contextItem = GetContextItem.GetItem(HttpContext.Current.Request.UrlReferrer?.AbsolutePath) as ILandingPageContentItem;

// Access fields from ContextItem
}

public class GetContextItem
{
	public static IStandardTemplateItem GetItem(string path)
	{
		Item item = Sitecore.Context.Database.GetItem($"/sitecore/content/<tenant>/Home{path}");
		
		return item?.AsStronglyTyped();
	}
}

Hope this helps someone. Any questions, please leave a comment.

Happy Sitecoring!

0

XConnect: Certificate was not found

Experience Analytics was not working on Production environment. I checked the logs and it was throwing Certificate was not found error. 

Exception: System.InvalidOperationExceptionMessage: The certificate was not found.Source: Sitecore.Xdb.Common.Webat Sitecore.Xdb.Common.Web.CertificateWebRequestHandlerModifier.Process(HttpClientHandler handler)at Sitecore.Xdb.Common.Web.CommonWebApiClient`1.CreateRequestHandler()at Sitecore.Xdb.Common.Web.CommonWebApiClient`1.CreateClient()at System.Lazy`1.CreateValue()at System.Lazy`1.LazyInitValue()at Sitecore.Xdb.Common.Web.CommonWebApiClient`1.<ExecuteAsync>d__37.MoveNext()--- End of stack trace from previous location where exception was thrown ---at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)at Sitecore.Xdb.Common.Web.CommonWebApiClient`1.<ExecuteGetAsync>d__32.MoveNext()--- End of stack trace from previous location where exception was thrown ---at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)at Sitecore.XConnect.Client.WebApi.ConfigurationWebApiClient.<Refresh>d__4.MoveNext()
  • My first guess was certificate would have expired, but it was valid. 

  • Second guess was thumbprint could be wrong, but thumbprint was perfectly matching with the config value(\App_Config\AppSettings.config file , in the validateCertificateThumbprint setting).

  • Started wondering why it can’t find the certificate for some reason?  Came to know that need to add an application setting to the web app called WEBSITE_LOAD_CERTIFICATES and the value needs to be the certificate thumbprint.

  • This application setting is required for the app service to load the certificate into the local certificate store of the host running the app service. 

Once the setting is added and I no longer see the error in logs and the Experience Analytics started showing some number/graphs. Yay!

Hope this helps. Any questions, please leave a comment.

Happy Sitecoring.

0

Sitecore 9 Forms: Custom Control – Conditional Section

I came across a scenario to implement Conditional Section for Sitecore 9.0 to hide/show fields based on user input. This feature was introduced on Sitecore 9.1(Checkout my other blog here). Since the project is in Sitecore 9.0, I decided to create a custom control using speak. 

Let’s get started.

Step 1: Create form element in core DB using speak

  • Switch to Core DB
  • Go to /sitecore/client/Applications/FormsBuilder/Components/Layouts/PropertyGridForm/PageSettings/Settings
  • Create a template based of Form Parameters. (I couldn’t find it when i tried from Insert Template, so i duplicated the existed one- MutliLine Text. If you know, how to add Form Parameters template(not using Sitecore Rocks), please leave a comment.)

 

  • Add the FormTextBox Parameters template. Since I duplicated MultiLine Text field, it came with the Details, Validation, Styling and Advanced. I feel it’s best shortcut to create quick.
  • Fill out FormLabel, IsLableOnTop and BindingConfiguration fields. 
  • Repeat the fields as many as you need. Here i added one more to compare the value.
  • NOTE: IsLabelOnTop is unchecked for additional fields

Step 2: Create form template in Master DB

  • On Master DB, create a custom template under Basic/Lists/Security/Structure folders based on Field Type template(/sitecore/templates/System/Forms/Field Type). I created under Structure Section as it’s Condition Section.
  • Fill out Property Editor field by choosing the custom control that was created in Core DB. You can see all the fields listed shown in below screen shot. 
  • Fields(View Path, Model Type)will be filled out after creating code behind and razor view files.

Step 3: Create model and view in Visual Studio

  • Create model and view in project under Helix structure
    public class ConditionalViewModel : FieldViewModel
    {
        public string TargetField { get; set; }
        public string TrueValue { get; set; }

        protected override void InitItemProperties(Item item)
        {
            base.InitItemProperties(item);

            TargetField = StringUtil.GetString(item.Fields["Target Field"]);
            TrueValue = StringUtil.GetString(item.Fields["Show Value"]);
        }

        protected override void UpdateItemFields(Item item)
        {
            base.UpdateItemFields(item);

            item.Fields["Target Field"]?.SetValue(TargetField, true);
            item.Fields["Show Value"]?.SetValue(TrueValue, true);
        }
    }
@using Sitecore.ExperienceForms.Models
@using Sitecore.ExperienceForms.Mvc.Html
@using Sitecore.Mvc
@model  Sitecore.Project.Example.Views.CustomControl.ConditionalViewModel

@{
    var viewModel = Model is IViewModel vModel ? vModel : null;
}

<div @(Sitecore.Context.Request.QueryString["sc_formmode"] != null ? "" : "hidden") class="@Model.CssClass cond-@Model.targetField-@Model.trueValue">
    @Html.RenderFields(viewModel)
</div>

@if (Sitecore.Context.Request.QueryString["sc_formmode"] == null)
    {
        <script type="text/javascript">
            const condArr = [];

            function initConditional() {
                const conditionals = document.querySelectorAll('[class*="cond-"');
                conditionals.forEach((e) => {
                    e.className.split(" ").forEach((c) => {
                        if (c.includes('cond-')) {
                            condArr.push(parseClassName(c));
                        }
                    });
                });
                condArr.forEach((cond) => {
                    const element = document.getElementsByClassName(cond.field_name)[0];
                    element.setAttribute("data-cond", cond.field_name);
                    element.onchange = () => {
                        conditionalChange(element, condArr);
                    }
                });
            }

            function conditionalChange(element, condArr) {
                condArr.forEach((cond) => {
                    if (cond.field_name === element.getAttribute("data-cond")) {
                        if (cond.value === element.value) {
                            document.getElementsByClassName(cond.class)[0].removeAttribute("hidden");
                        } else {
                            document.getElementsByClassName(cond.class)[0].setAttribute("hidden", "true");
                        }
                    }
                })
            }

            function parseClassName(class_name) {
                const arr = class_name.split("-");
                if (arr.length < 3) {
                    console.log(`Malformed className: ${class_name}`);
                } else {
                    const obj = {
                        class: class_name,
                        field_name: arr[1],
                        value: arr[2]
                    }
                    return obj;
                }
            }

            initConditional();
        </script>

Step 4: Update the template fields

Now you should see the new form control on the elements panel. Drag and Drop to any form and fill out the Target Field and True Value fields appropriately and put any element(s) inside Conditional Section to show/hide the element(s).

Don’t forget to publish all the templates and forms!

Happy Sitecoring! Leave a comment if you have any questions.

0

Sitecore 9 Forms: Uncaught TypeError: Cannot read property ‘unobtrusive’ of undefined

Are you getting this error on Sitecore 9 Forms Submission? I got it and it took me some time to figure out. It’s all related to Validation. Here are the points to check to narrow down the issue —

  • If you have form fields set it to mandatory, change it to optional and see if that makes the submission successful. If so, one of the field validation is causing trouble.

  • It happens for custom form control quite often, where you need add the validation to razor view file and make sure you have this attribute – GenerateUnobtrusiveValidationAttributes.
<label for="@Html.IdFor(m => Model.Value)" class="@Model.LabelCssClass">@Html.DisplayTextFor(t => Model.Title)</label>
<select data-trigger class="@Model.CssClass @Model.Name" name="@Html.NameFor(m => Model.Value)" id="@Html.IdFor(m => Model.Value)" data-sc-tracking="@Model.IsTrackingEnabled" data-sc-field-name="@Model.Name" @Html.GenerateUnobtrusiveValidationAttributes(m => m.Value)>
</select>
@Html.ValidationMessageFor(m => Model.Value)
  • Compare your custom control razor file to any one of inbuilt form controls ([iis-site-folder]\Views\FormBuilder\FieldTemplates ) like below and if you see any difference on attributes, add it out.
  • Finally a simple check: make sure to publish all the forms and view the landing page in live mode(not in preview mode)

Hope this helps. Happy sitecoring.

0

Sitecore 9 Forms: Custom Grouped dropdown

I came across a requirement from a client that they wanted to show Country and it’s states grouped in a dropownlist. I created a custom grouped dropdown to fit into the scenario. Since this is an extension of dropdownlist, no speak knowledge required. 

Let’s get started

Step 1: Create custom dropdown list

Create a custom dropdownlist under
/sitecore/system/Settings/Forms/Field Types/Lists based on Field Type(/sitecore/templates/System/Forms/Field Type) template like below

Step 2: Create a code behind class and razor view

create a code behind class like this in VS project

using System.Collections.Generic;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.ExperienceForms.Mvc.Models.Fields;

namespace Sitecore.Project.Example.Views.StateDropdown
{
	public class StateDropdown : DropDownListViewModel
	{
		protected override void InitItemProperties(Item item)
		{
			Assert.ArgumentNotNull(item, nameof(item));
			base.InitItemProperties(item);
		}

		protected override void UpdateItemFields(Item item)
		{
			Assert.ArgumentNotNull(item, nameof(item));
			base.UpdateItemFields(item);
		}

		public Dictionary<string, Dictionary<string, string>> Regions()
		{
			if(string.IsNullOrEmpty(DataSource)) return new Dictionary<string, Dictionary<string, string>>();
			Dictionary<string, Dictionary<string, string>> counrtyCollection = new Dictionary<string, Dictionary<string, string>>();
			Item item = Context.Database.GetItem(DataSource);
			var children = item.GetChildren();
			foreach (Item child in children)
			{
				counrtyCollection.Add(child.Fields["Name"].Value, new Dictionary<string, string>());
				foreach (Item desc in child.Children)
				{
					counrtyCollection[child.Fields["Name"].Value].Add(desc.Fields["Name"].Value, desc.Fields["Code"].Value);
				}
			}
			return counrtyCollection;
		} 
	}
}

Create a razor view like this and build project

@using Sitecore.ExperienceForms.Mvc.Html
@model Sitecore.Project.Example.Views.StateDropdown.StateDropdown
@{
	var regions = Model.Regions();
}
<label for="@Html.IdFor(m => Model.Value)" class="@Model.LabelCssClass">@Html.DisplayTextFor(t => Model.Title)</label>
<select id="@Html.IdFor(m => Model.Value)" data-trigger name="@Html.NameFor(m => Model.Value)" class="@Model.CssClass" placeholder="Select Your Work Location" data-sc-tracking="@Model.IsTrackingEnabled" data-sc-field-name="@Model.Name" @Html.GenerateUnobtrusiveValidationAttributes(m => m.Value)>
	<option placeholder>Select Your Work Location</option>
	@foreach (var region in regions)
	{
		<optGroup data-id="@region.Value" label="@region.Key">
			@foreach (var state in region.Value)
			{
				<option value="@state.Value">@state.Key</option>
			}
		</optGroup>
	}
</select>
@Html.ValidationMessageFor(m => Model.Value)

Step 3: Fill out the fields

Fill out the View Path, Model Type and Property Editor(should be Property Editor Settings/DropDown List).  

you are now all set to utilize the custom dropdown list in Forms Designer. Don’t forget to publish the field!

Hope this is helpful. Any questions, please leave a comment.

Happy Sitecoring.

0

Sitecore 9 Forms: Custom Regex Validation

I came across a scenario where i implemented a custom validation on Sitecore 9 Forms. Sharing my knowledge here. You can achieve this in three simple steps.

Step 1: Create custom validator

Create a custom validator under
/sitecore/system/settings/forms/validation based on Validation(sitecore/templates/System/Forms/Validation) template like below

Step 2: Fill out the fields

Fill out your own regex and error message. You can copy the Type value from other validator.

Step 3: Assign the custom validator

You can now add the new custom validator to any Form fields(
/sitecore/system/Settings/Forms/Field Types). All set and no code required!

Hope you found this blog helpful. Any questions, please leave a comment.

Happy Sitecoring!

0