CRM 2013 – Javascript null setting oddity

I had an odd error where I was trying to null a lookup field in Javascript in CRM 2013 Service SP1.

When the user changed a lookup field, I wanted to blank out a few fields to make them select those fields again.  The fields being nulled were dependant on selection of the first lookup field and the options and values they could pick changed.

It’s good practise to reduce the number of choices users have by filtering out values in option sets and lookups, hiding/showing fields.  This makes the forms more cohesive, less noise for the end users.  Read more about CRM Form design in the article below

Good CRM design should not make users think

The initial code was in a function and looked like this

        if (Xrm.Page.getAttribute("field1").getValue() != null) {
            Xrm.Page.getAttribute("field1").setValue(null);
        }


        if (Xrm.Page.getAttribute("field2").getValue() != null) {
            Xrm.Page.getAttribute("field2").setValue(null);
        }
        

Oddly field1 was correctly set to null but field2 refused to be set to null.

To add to the annoyance of not setting the field to null, the not nulling triggered the OnChange event for the lookup which set other values on the previous not nullable value!!!

This made me angry

Stepping through

When bug fixing the goal is understand exactly what is happening, once you understand what is happening it might be possible to work out why or work around it.  There is a big difference between

  • Knowing what is happening
  • Your assumptions about what is happening

Assumptions are dangerous because they can easily be wrong.  When bug fixing don’t assume anything and prove everything.  I have wasted plenty of time with assumptions and investigating the wrong section of code.

I started debugging and stepped through the setting the values to null.  The handy part of debugging JavaScript is the console allows you to integrate the values.

The values on the GUI looked like fields1 and fields2 were both not being set to null.

I debugged and stepped through the code, field2 wasn’t being set to null but the OnChange event was running for field2 which was setting field1 and field2 to the values based on the previous field2 value.

One change at a time

One of the golden rules when debugging a problem is to change one thing at a time, monitor the effects of the change.  This rule is particularly inportant if the change is a configuration change which will be changed on multiple environments (DEV, TEST, PREPROD, PROD).

When changing values or code, making a solitary change will show you the effects of the one change.  If you change 5 things at once which resolves the problem, you don’t know what change has fixed the problem.  In the multiple change scenario you would either need to go back and change one variable at a time or make all the changes in all the environments.

When making changes to code/config it’s good practise to minimise the changes, which minimises the potential unknown effects of these changes and reduces bugs coming from these changes less likely.

I tried

  • removing field1 change
  • swapping the order, changing field2 before field1
  • double checking javascript
  • Asking fellow CRM developers

Asking fellow CRM developers did bring a few mumbles of maybe having seen something like it before but no one could remember what is was or what they did (if only they wrote a blog post about it!!)

None of the other changes did much.

To the Internet

 

Searching the internet didn’t bring up anything directly relevant (how often does that happen!), it did lead me to this page

Javascript, onChange events no longer work on an empty field

This wasn’t the problem I was experiencing

I just noticed that if you have a form field that triggers a Javascript function on the onChange event it no longer triggers the function if you clear the field, but ONLY when you change the field data. For instance; if you have a Name field populated with a name, and you remove the name – the function isn’t triggered. It’s left empty. You have to change the text inside the field.

 

The problem being talked about here is setting required fields to null didn’t trigger the onchange.  I had this reverse of this problem I was setting field2 to null, it wasn’t setting but triggering the OnChange, which means Microsoft fixed the problem report (the forum posts were Feb 2014).

The forum post go me thinking, lets change the field requirements and see what happens.

Setting field requirements using Javascript

Fields have three levels of requirements

  • none
  • required
  • recommended

For some reason accessing these programmatically seems quite different from setting/adjusting them using the GUI.  Looking at the list what is the point of recommended, it should be required or none.  Why you would want to change a field to have a requirement level of recommend?

The code is string based, which seems a little odd and prone to syntax errors.  To find all the Javascript methods use this page on the CRM SDK

Xrm.Page.data.entity attribute (client-side reference)

Here is an example using the trusty field2

  • Xrm.Page.data.entity.attributes.get(“field2”).setRequiredLevel(“none”);
  • Xrm.Page.data.entity.attributes.get(“field2”).setRequiredLevel(“required”);
  • Xrm.Page.data.entity.attributes.get(“field2”).setRequiredLevel(“recommended”);

I changed my code to set the required level to none, set field2 to null and then reset the required level to required.

//I had to set required level to none because assign null wasn't working, might be fixed in future roll ups
	if (Xrm.Page.getAttribute("field1").getValue() != null) {
            Xrm.Page.getAttribute("field1").setValue(null);
        }

        Xrm.Page.data.entity.attributes.get("field2").setRequiredLevel("none");
        if (Xrm.Page.getAttribute("field2").getValue() != null) {
            Xrm.Page.getAttribute("field2").setValue(null);
        }
        Xrm.Page.data.entity.attributes.get("field2").setRequiredLevel("required");

Leave a comment

If you have written some unusual code as a work round for a limitation in design or a known bug, it’s good practise to leave a comment explaining to other developers (and maybe your future self) why you have put the code.

Reasons why you should comment unusual code

  • A developer could easily delete the code without realising what is meant to do
  • It could be confusing for other developers to read and understand
  • A rollup/service patch might fix the code and it could be safely removed
  • The developer reading the code might know the solution to this problem
  • It’s good practise
Advertisement

Hosk Cowboy Coder – YEEHAW

 

In yesterday’s blog post which had a bit of a cowboy theme with the Good, the Bad and the ugly, it was about the Bad for..in loop in Javascript

One of my twitter followers, posted today I was a cowboy coder which I found funny but then someone just retweeted that to 2346 followers

Cowboy Coder

 

I love the thought that 2346 of @recuweb twitter follows will just see the tweet @BenHosk Cowboy coder, no explanation, it’s awesome

Below is the twitter conversation

YEEHAW

Embrace your bad code

There are two types of CRM Developers

  • Those who know they make mistakes
  • Those who think they don’t

I’m not saying you should all rush out and write cowboy code but I am saying be ready to admit you will write code that can be improved or even thrown away.

I was going to use the subtitle of “Embrace your bad code and then strangle it”.

The point I’mmaking is you will make mistakes, you will write bad code, create customizations which could be improved but these present you with opportunities to learn and improve.

Everyone makes mistakes and sometimes your code gets peer reviewed and slammed.  Don’t take it personally, use it to find out what’s wrong with it and why you shouldn’t do it a different way.

Make it work and then Refactor

When I write code my first goal is to make it work and do what needs to be done (what ever that may be).  The next stage, which is a stage many poor CRM Developers miss out (the word contractor jumps into my mind) is the refactoring and tidying stage.

Everyone is under time pressure, but not cleaning up the code will only make it harder for you to maintain and fix the code later.  Fixing code now, when you understand how it works and what it is supposed to do will take a lot less time than trying to find a bug in messy code 6 months down the road.

Talk/blog about it, learn from it

Talking to CRM Developers or blogging about your coding experiences you will learn where your mistakes were madimportantly you will understand why they wrong.  I always find when I understand the logic of something, I am creating more mental pathways to that information and increasing my chances of not repeating my mistakes.

When ways make logical sense to me it makes me want to do them.

In yesterdays blog, I found a bug and fixed it

CRM 2011/2013 – What does setSubmitMode do? and how does it work?

I then talked about it with a developer and learnt there was a bad For..in loop in Javascript

Beware of the Bad Javascript for loop

Today Guido from the excellent CRMAnswers blog left me a comment on how to do the code in one line

for this specific case the forEach method of the collection can be used:

Xrm.Page.data.entity.attributes.forEach(function(attribute, index){attribute.setSubmitMode(“never”)});

just 1 row, no bad loops 🙂

 

The one bug has lead me on a journey and I have learnt

  • Javascript for statements can return functions
  • isNAN will only return numbers
  • How to open a page impersonating IE8
  • There is a bad for loop and a good one!
  • The solution to the bug
  • A one line solution to the bug
  • That lots of people think I’m a cowboy 🙂

 

Suck a little bit less everyday

My goal is to keep learning, continuous improvement and suck a little bit less every day and become a better CRM Developer.

I view every mistake I can avoid making, hopefully means I have replaced the mistake or poor code with some good code

 

Finally – Don’t forget there are some good cowboys out there

Beware of the Bad Javascript for loop

I should have written this blog post on halloween, wooooooo but I hadn’t seen the bug then so that would involve time travel and I haven’t got time for that.  Wait if I invented a method of time travel I would have all the time I would need.  Oh no another bad loop I have got myself in.

Yesterday I blogged about an error I had with a for loop, you can read it below

CRM 2011/2013 – What does setSubmitMode do? and how does it work?

 

This was the code that caused the problem

var attributes = Xrm.Page.data.entity.attributes.get();

for (var i in attributes) {
{ attributes[i].setSubmitMode(never); }
}

 

The problem was when looping round the variables in attributes it was also returning functions, which caused a crash.

I fixed the code by doing this

for (var i in attributes) {

{
i f (isNa!N(i)) {
attributes [i]setSubmitMod.e(“never”);
}
}
}

 

 

Not Quite Right

Something was bugging me about the code.  If that problem was a problem whcommon y had I never seen that code before?

Why had I never seen this error before?

I mentioned the problem and solution to another developer and he instantly said

 

The code must have been using the bad for loop

What!, no one told me there was a bad for loop in Javascript, why has no one told me about the bad for loop, come on people.

 

The Good, the bad and the ugly of For statements

 

The Bad – For In Loop for Array Iteration

I searched the internet and found this forum discussion with a great explanation

http://stackoverflow.com/questions/5263847/javascript-loops-for-in-vs-for

I am copying the top answer because it’s awesome

 

Don’t use for..in for Array iteration.

It’s important to understand that Javascript Array’s square bracket syntax ([]) for accessing indicies is actually inherited from the Object

obj.prop === obj['prop']  // true

The for..in structure does not work like a more traditional for..each/in that would be found in other languages (php, python, etc…).

Javascript’s for..in is designed to iterate over the properties of an object. Producing the key of each property. Using this key combined with the Object‘s bracket syntax, you can easily access the values you are after.

var obj = {
    foo: "bar",
    fizz: "buzz",
    moo: "muck"};


for ( var prop in obj)  {
    console.log(prop);      // foo / fizz / moo
    console.log(obj[prop]); // bar / buzz / muck}

And because the Array is simply an Object with sequential numeric property names (indexes) the for..in works in a similar way, producing the numeric indicies just as it produces the property names above.

An important characteristic of the for..in structure is that it continues to search for enumerable properties up the prototype chain. It will also iterate inherited enumerable properties. It is up to you to verify that the current property exists directly on the local object and not the prototype it is attached to with hasOwnProperty()

for ( var prop in obj)  {
    if ( obj.hasOwnProperty(prop) ) {
        // prop is actually obj's property (not inherited)
    }
}

(More on Prototypal Inheritance)

The problem with using the for..in structure on the Array type is that there is no garauntee as to what order the properties are produced… and generally speaking that is a farily important feature in processing an array.

Another problem is that it usually slower than a standard for implementation.

Bottom Line

Using a for...in to iterate arrays is like using the butt of a screw driver to drive a nail… why wouldn’t you just use a hammer (for)?

 

Hosk Interpretation

The important point here is ForIn statements in javascript return user defined properties as well as numeric indexes.  EEK this explains why I was getting “IndexOf” in my for loop.

It also suggests the index numbers are not gauranteed to come out in a sequential order.  This might not be a problem because all the numbers will come out but if you were expecting them in order the for…in could sneak in a very odd bug to find.

Performance is also slow using the forin loop (although in this case it wasn’t really a problem/consideration), this forum discussion also discusses more about performance of for loops if you are interested in finding out more

http://stackoverflow.com/questions/13645890/javascript-for-in-vs-for-loop-performance

 

The Good

So what For loop should you use in your Javascript for iterating arrays.

When I stepped through this for statement the “IndexOf” value wasn’t returned

var attributes = Xrm. Page. data. entity. attributes. get ();

for ( var i = 0; i < attributes. length; i++) {

attributes[i]. setSubmitMode("never"); }


The Bad

The bad was the original bug someone put in there, it’s the wrong, evil for loop, didn’t the developer know anything!  Well technically I didn’t know about the bad for loop until today.

for (var i in attributes) {
{ attributes[i].setSubmitMode(never);}} 


 

 

The Ugly

The ugly was my original fix

for (var i in attributes) {
    if(!isNaN(i)) {
    attributes [i]setSubmitMod.e(never);}}
    


 

It worked but it wasn’t quite right, it was working around the problem of using the wrong for loop.  It took longer because it was returning functions as well as numbers.

 

what have I learnt

I have learnt there are good and bad for loops in Javascript, yes, I went back and changed the code to use the correct for loop.

I  learned it’s good to discuss things with your fellow developers because you might teach them something new or they might teach you a new trick or way to do something.

 

It’s good to talk

It’s good to talk/blog about quirks and problems you experience programming.  Often developers build up areas of expertease which is usually based around the experience they have gained from projects they have worked on.

 

Be willing to learn

I believe in continuous improvement, always striving to learn and improve.  Every mistake/bad coding practice you can get rid off will be replaced by good code.

More good code == better developer

 

Don’t base your knowledge just on experience

Good developers learn the best practices through their own ideas/experience, reading articles/books on programming.

Good developers are always trying new technology/releases, not only does this get them ready for the new functionality but it gives them ideas

On a related subject is my blog on why you should read the what’s new for CRM 2015, it’s all about learning baby!

CRM 2015 SDK – Why you should read the What’s new for developers

 

I believe CRM certifications (customization and extending) are good ways to learn the new functionality in CRM 2013 and broaden your CRM development knowledge.  I  read and used parts of CRM I hadn’t used in any projects I had worked on but which came up in future projects.

My point is you can learn areas of coding/CRM you haven’t used in a project by reading and trying the functionality yourself.  When the time comes to use it in a project you already have a good idea (and maybe a bit of experience) of how to use it, which means your learning curve on new functionality will be shorter than someone with no knowledge of it.

With CRM 2013 it’s easy, you can easily create a CRM 2013 on line trial to try out all the new functionality, you have no excuse because I have created a blog on how to get a CRM 2013 up and running

Step by Step guide to creating a CRM 2013 Online trial

 

Times change but standards must remain

and if the Hosk catches you writing poor code, I will send round the heavy mob

CRM 2011/2013 – use the debugger console to enabled/disable controls on a form

I was trying to fix a small bug but I was getting bogged down with the business logic (which I didn’t need/want to change) on the form.

The problem was there was lots of business logic which kept disabling the fields I wanted to change.

I tried briefly to understand the business logic but it was complex and detailed and I wasn’t really interested in understanding the form logic and/or briefly amending the JavaScript onload.  All I needed to do was to enable an optionset on the form, which would enable a ribbon button.

So it’s time for a bit of off the cuff hacking

I loaded the form

Press F12 to bring up the debugger window

You can use the console to manipulate the fields and enable/disable certain fields.

You have access to the CRM JavasScript objects

So I used the Xrm.Page, selected the control (not the field attribute) and did a setDisabled(false); which enables the control.
Xrm.Page.getControl(customerid”).setDisabled(false);
This didn’t enable the ribbon button because although the JavaScript function which is used by the ribbon button (e.g. the enable rule for the Ribbon button) the ribbon hadn’t been refreshed.

So I used the console to do a Ribbon Refresh

Xrm.Page.ui.refreshRibbon();

Fantastic, now my field was enabled and the ribbon button was enabled and ready to be pressed.

 

Other uses for F12 JavaScript debugger is to get the guid of the record, which I did on this blog post

 

Browser bookmark

An alternative to bringing up the F12 debugger is to create a bookmark, this will enable you to pass javascript into a form before loading it.

The blog post below created a God Button, which enables all fields

http://www.magnetismsolutions.com/blog/paulnieuwelaar/2014/07/29/activate-god-mode-in-crm-2013—don-t-let-your-users-see-this

 

This blog post will talk you through the logic and is the first part in a series of blog posts on the subject

http://blog.sonomapartners.com/2014/01/crm-2013-javascript-bookmark-series-part-1.html

 

CRM 2013 Video – How to Quickly way to get a guid for a record using Chrome and IE

I created a new video on my YouTube channel Hosk CRM Dev and as you can see from the logo I have been a busy CRM bee.

https://www.youtube.com/user/hoskcrmdev

Hosk CRM Dev Bee Trimmed

I highly recommend you visit the channel as there are lots of useful and interesting videos on CRM on things like Plugin Development, JavaScript, MB2-703 CRM 2013 Customization and Configuration study material, CRM 2013 Tool Reviews, quick tips and other stuff.

The video shows you how to get the guid from opening an account record and then getting the JavaScript debugger up and then getting the guid in both Chrome and Internet Explorer.  Below is the JavaScript I used

Chrome

Xrm.Page.data.entity.getId()

Internet Explorer

frames[0].Xrm.Page.data.entity.getId()