Showing posts with label Validation. Show all posts
Showing posts with label Validation. Show all posts

Tuesday, March 18, 2025

JavaScript - Name Spaces and Defensive programming in D365 Pt 1

What is defensive Programming?  Pt1

When we write programs, we (normally) have a very clear idea of what it is we want to achieve, When we look at JavaScript form manipulation in D365 specifically,  we know which fields, sections and tabs we want to manipulate, whether it’s making a field Read-only or mandatory, based on the value of another field, or hiding whole sections or tabs based on a user’s login and security role and we write the scripts accordingly.  However, other people may have access to the system and may be doing updates of their own.   If those updates happen to change a field or tab name we rely on in our code, it could cause problems.   How we guard against adverse effects of these changes is referred to as ‘defensive programming’.  Let me give you a common definition of defensive programming from our friend Mr Google:

Defensive programming is a proactive approach to software development that focuses on anticipating potential problems and implementing safeguards to prevent crashes, bugs, and vulnerabilities, ensuring the application functions reliably even under unforeseen circumstances. 

This blog is not going to teach you how to write JavaScript, but I will show you some of the basic techniques we can use when manipulating forms or responding to events on a Form in d365.

Name Space

When we write programs, we as programmers talk about the scope of variables or the scope of a function in relation to other functions or libraries.  Namespacing is an extension of managing ‘Scope’ and refers to the provision of scope (think boundaries) around functions.  JavaScript files (Web Resources in D365) are read into memory and used when called by an event, typically on the form.  Let’s consider two functions, written by two separate developers housed in two separate libraries.

The first function is called ‘set date’ and sets the ‘Last Contact date on a contact record.  The library is called ‘ContactFormEvents.js’.  The purpose of this function is to set the value of a field on the form called ‘Last Contact date’ when the form is saved.

Here is a snippet of the code

Function setDate(executionContext)
   let formContext = executionContext.getFormContext();
   var now = new Date();
   formContext.getAttribute("new_lastcontactdate").setValue(now);
}

 

Now suppose we have another library called CommonFunctions.jS  that a helpful dev. has created to organise all the common functions in to one simple library, only this Dev. Has thought that it would be a great idea to set the next contact date to 1 month after the record has been saved.  They create the following function

Function setDate(executionContext)
   let formContext = executionContext.getFormContext();
   var now = new Date()
   var nextDate = now.setMonth(now.getMonth() + 1);
   formContext.getAttribute("new_nextcontactdate").setValue(nextDate);

Ok, I think you can see where this is going.  Lets suppose both libraries are added to the contact form.  The first developer attaches an event to the on save for the form

‘setDate’

Which one is going to run, which is it the one the developer wants to run?  Both are valid and both are loaded in to memory, oh dear.

Whilst this is an over simplification, the issue is more than valid and more common than you would want to believe.  Don’t worry, there is a real simple fix and its not that hard once you get your head around it.  Lets look at how we can use a NameSpace to ensure only the correct ‘setDate’ function is called.

How do we create a NameSpace?

There are a couple of ways, and this is how I do it:

if (typeof ContactEvents == "undefined") {
    ContactEvents = {};
}

Here I check to see if the namespace ‘ContactEvents’ has been defined and if not I create it.

This is what the updated code snippet could look like using the new namespace

if (typeof ContactEvents == "undefined") {
    ContactEvents = {};
}
ContactEvents = {
   setDate : function(executionContext){
      let formContext = executionContext.getFormContext();
     var now = new Date();
      formContext.getAttribute("new_lastcontactdate").setValue(now);
   }
}

Now when I call the function in the on save event, I change the call to include the namespace so it looks like this:

ConactEvents.setDate

Now I know which function is being called.  Even if the common library doesn’t have a name space, but the contact form events library does, it means they won’t get mixed up.

Namespacing is only one component of defensive programming. The next one is 

Validation and Verification

If we assume that because we created the last contact field and we’ve added a namespaced function to update it, that everything is fine and dandy and we can have a nice pat on back while we drink our well earned coffee we could be in for a surprise.

Lets take the examples from above, and lets assume the our helpful second dev, has decided not only to add some useful functions, but they’ve also tidied up the form and created the last contacted filed with a slightly different name more in keeping with the rest of the naming used on the form.  Lets image the field has been recreated and is not called new_dateLastContacted, what happens to our function when its called.  BANG! It crashes and pops up some error message that confuses the user. Oh dear (again).

Don’t worry we can fix this too.  We interject a test, and a validation

First we check to see if the field is on the form we do this by grabbing the field by name and seeing if it there or not (null).  The following snippet tries to assign a field to the variable dateFld.  Then dateFld is compared to ‘null’ if it is null, it simply jumps out with no error

Var dateFld == formContext.getAttribute("new_lastcontactdate");
if(null !== dateFld){
}
Else {
   Return;
}
Now let’s verify the field that comes back is in fact a date field (as opposed to a text field for example)

   Var fldType == dateFld.getAttributeType();

   If (fldType == “datetime”){

   return true;

}

So now, we know how to ensure we call the right function, we know how to test in our function that the field is still on the form and that the field is the right (or expected) type, now we can execute knowing we have the correct function, the correct field and it’s of the right type.  Here is what the updated function could look like:

ContactEvents = {
   setDate : function(executionContext){
      let formContext = executionContext.getFormContext();
      Var dateFld == formContext.getAttribute("new_lastcontactdate");
         if(null !== dateFld){
            var fldType == dateFld.getAttributeType();
            If (fldType == "datetime"){
               var now = new Date();
               formContext.getAttribute("new_lastcontactdate").setValue(now);
            }
            else {
               return;
            }
         }
         else {
           return;
         }
   }
}

There is another component to defensive programming and it’s about testing the actual execution steps within the function have executed correctly without error, in JavaScript we use a function wrapper called ‘Try Catch’.  I’ll save the explanation of what a try-catch is and how to use it for another blog but the simplistic explanation is as follows:

We add a block around the execution statement and if an error occurs it is trapped by the catch block, where we can then show it or do something else.

try {
  Execution Block
}
catch (error)
{
   Display or do something with the error information
}

There are a couple of more pieces with the try-catch, they are ‘throw’ and ‘finally’, but I’ll cover these when I cover try-catch in more detail.


How to Create a PCF by Neeraj Agrawal

 I came across this great introduction to PCF controls today and rather than try to compete and write a similar post myself, I thought I...