In my previous post, Dynamics Portals Field Validation, we discussed adding custom validation to your Portal solution using JavaScript. We took the snippet right from Microsoft documentation, wrapped things up in some nice helper functions, and then applied the new validation methods to Web Form Steps form fields.
In the script example from the post, our new addValidator
and addFutureDateValidator
methods embedded in the Web Form Step script block along side the application of the field specific validators. If you only ever use validation in one Web Form Step in your Portal solution, then this set up is manageable. But as soon as you have more than one Web Form Step that requires the same validators, it becomes pretty clear that we need a new method for script management.
This is what happened on my current project. We quickly saw requirements for special validation, such as conditional validation. For example, if the salutation value of Other is chosen, require the user to enter a text value for Other. This became a new validator method and we added it to a script library for reuse across our Web Form Steps. We also began to see other places where we wanted to reuse helper scripts, such as formatting a Social Security Number. If you have an issue in a script that you copy across multiple Web Form Steps, Web Pages, etc, fixing all those steps would be time consuming and be very prone to error. Best to fix things in one place and have the fix applied everywhere!
This is all standard stuff… Build shared libraries of scripts for reuse throughout a project. So, how do you implement this within a Portals solution?
Our method of choice
The method we chose for our project is to leverage Web Templates. Well, my first choice was to leverage Web Files but I immediately ran into issues with Note Attachments blocking JavaScript in the system settings. Here is a nice post describing some of those issues: Dynamics 365 portals: JavaScript as Web Files. I did test it a bit in our development environment by changing the settings as described in the post, but I also ran into some odd behavior with how the JavaScript resources loaded in our pages. So because of the odd behavior and additional security concerns around changing our system settings, we decided to leverage Web Templates.
Web Templates in Dynamics Portals is an entity that allows you to store web content as a record in CRM. Here is the documentation from the Microsoft documents site: Store source content by using web templates. In addition to the long list of predefined Web Templates included in the Portal such as Ads, Blogs, Forums, etc, users may create their own Web Template snippets. Content saved within your Web Template can then be referenced from your Portal using Liquid Templates and injected into your Web Form Step. A quick example might be a Web Template containing an HTML snippet for a logo. You would create a new Web Template record that looks something like this:
This Web Template is just a reusable HTML snippet that can be referenced by name. For example, using Liquid Templates, I can inject this snippet into a page using the following Liquid syntax:
{% include 'Futurez Logo' %}
The Liquid Template will find the Web Template by name This is a bit of a simple example, but if I were to change the URL to the logo, I need only change this snippet and any reference to it would be updated on the next page load. So we can apply this model to JavaScript and other Portal entities like Web Form Steps. Instead of an HTML snippet, we can just include JavaScript. For example, we might have a set of utility scripts, and our Web Template might look like this:
Notice that this is JavaScript and not TypeScript that I had used in my previous post. As with other areas where TypeScript is used, you will need to publish the compiled JavaScript. This utility library only contains the one function now but it can now be used across several Web Form Steps. For example, we can now reference this using Liquid Templates:
This Web Form Step now has the full content of the UI Utils
Web Template injected just prior to the call to the maskDate()
helper method. So when the Web Form Step renders, the script will be readily available when FUTZ.ui.maskDate()
is called. This model can apply to a Web Page as well. For example, if you would like to include or execute script for every Web Form Step on a Web Page, you can include the Liquid Template in the Web Page Custom JavaScript section. This is particularly helpful if you want to build out a custom library of scripts to be used across Web Pages, Web Forms, and Web Form Steps. We have many different validators as described in my previous post, so those methods are defined once and included with the parent Web Page which means they are then accessible to each Web Form Step. I fixed an issue just this week that was a one line fix to a helper script function and it fixed an issue that cropped up in 4 different places!
Cool Tools
I won’t go into too much detail around managing your scripts. I am going to assume your team leverages Git or TFS to manage and organize scripts, and your team might be working in TypeScript instead of straight JavaScript. We have lots of options here and I think that this will likely vary between solutions.
But I do want to mention another benefit to leveraging Web Templates: the ease in which we can update them. In my post Some Useful XrmToolbox Plugins, I described a plugin called Portal Code Editor by MscrmTools (Github). This tool allows you to browse Portal specific records and their JavaScript or CSS related fields.
With this tool, I can easily browse Web Pages, Web Templates, and Web Form Steps, etc. Within the code tab, I have a nice color coded editor that allows me to quickly save and update my scripts. So I am not required to navigate the CRM user interface to find all of my Web Template snippets and where they are referenced. If we were to use Web Files, we would be required to update Notes on the Web File record, first deleting it and then adding the file again. Not a tremendous amount of work, and there may be a tool for managing Web Files, but this method has worked out well for us between the flexibility of referencing our files and managing their deployment and updates.
Alternate methods?
So, how does this method compare to other methods you have used? This has worked out fairly well for our project and I believe I may use it on another upcoming project. In the meantime, I am looking to hear from those with more Portals experience than myself, pointing out potential issues with this approach or just alternate methods that have advantages over this one!
As always, comments, corrections, and suggestions are all welcome!