Posted on 24. May 2015

Turbo Forms: Get your JavaScript ready for CRM2015 Update 1

With the introduction of 'Turbo Forms' in CRM2015 Update 1 I thought I'd give you a heads up on what you'll need to address in your JavaScript to support this new form rendering engine. The Dynamics CRM Team Blog has a very good article on the changes but there have been some misunderstandings of the statement 'we have parallelized as many operations as possible'. In actual fact the script loading of custom web resource scripts has not really changed since CRM2013 - It remains the same as I describe in my CRM2013 Script Loading Deep Dive. The operations that are parallelized with turbo form rendering are the internal form load operations rather than custom ones. Custom JavaScript loading has always been parallelized since CRM2013.

Turbo Form Page Differences

Before Turbo Forms both global scripts and your custom web resources would have been loaded into a content IFRAME within the main window each time you navigate between records.

The biggest change with Turbo Forms is that the content IFRAME is kept in memory and re-used for performance reasons. This parent content IFRAME is even kept in memory between navigation between different entity types. Any custom JavaScript is then loaded into a child IFRAME (via the ClientApiWrapper.aspx page) so that when you navigate between records they are re-loaded.

SparkleXRM solutions already have a load order mechanism that ensure that your custom scripts are loaded in order that they are needed.

Impact on unsupported code

If your JavaScript is using only supported SDK calls then there will be no impact from this new loading mechanism. Sometimes it is necessary to use unsupported functions or referencing parameters of the Content IFRAME (such as the query string). Since your custom JavaScript is now running in the context of the ClientApiWrapper (rather than the content IFRAME) any reference to window methods such as window.openStdWin or window.location.href will fail. In order to access these objects you will need to reference parent.window.

The ribbon workbench 'how-to' article that shows starting a dialog from a ribbon button does infact use openStdWin to ensure consistency with the out of the box dialog experience. I have updated the code to use the parent window when required.

Footnotes

There are a couple of other notable aspects of Turbo Forms that I thought I'd point out:

IFRAMES that are collapsed by default are not sized correctly.

If you have an IFRAME or HTML Webresource inside a Tab that is collaposed by default you will find that they are not sized correctly when the tab is expanded. This will be fixed in an upcoming update but until then you will need to show the tab by default and collapse when the form is loaded.

entityType vs typename

Turbo Forms have dropped the typename attribute of Lookup values.

In the past, the following code would return the same:

Xrm.Page.getAttribute("parentcustomerid").getValue()[0].typename
Xrm.Page.getAttribute("parentcustomerid").getValue()[0].entityType

With Turbo Forms only the documented entityType is available. The typename attribute was left over from the CRM4 days and just had not been removed until now!

@ScottDurow

 

Posted on 20. January 2015

The cream cracker conundrum (or customising the sub grid command bar)

I still find the streamlined user experience offered by the Command Bar a welcome change from the CRM2011 Ribbon. The sub-grid command bar is the only possible exception with the loss of the ability to add custom sub-grid buttons. There are only at most two buttons on a sub grid – 'Add' and 'Open Associated Sub-Grid'

The user must click on the 'Open associated sub-grid' button to show the full associated view and the full command bar with custom buttons. I say 'possible exception' because in fact there are still the same number of clicks involved (users had to click on the sub grid to show the contextual ribbon before) but it does feel as though we should have the ability to add buttons to the sub-grid command bar. I can think of some good reasons why this design decision may have been made (performance for one!) – but this post details what you CAN do to the sub-grid command bar.

Because the 'Open associated sub-grid' button is a bit of a mouthful, I'll refer to it from now on as the 'cream cracker' because it kind of looks like one and is equally a bit of a mouth full! (Thanks goes to my friends at the British Red Cross who first named it this way!)

Hiding buttons

We have established that you cannot add buttons to the form sub grid, but both the 'Add New' and 'Cream cracker' buttons are customisable in terms of their command and visibility (but you cannot change the image or the tool tip text).

To hide the sub grid buttons you have the following options:

  1. Hiding based on a security role (if the user does not have access to append a record to the parent or create new records of the sub grid type, the 'add new' button will be invisible
  2. Hiding all of the time using a 'Hide Action'
  3. Hiding conditionally using a security role
  4. Hiding conditionally using a custom JavaScript rule.

A common requirement is to hide the Add New button on a sub-gird until a specific criteria is met on the parent form. The standard ValueRule cannot be used because this rule will only work when the command button is added to a form command bar. So to achieve the conditional show/hide we must use a Custom JavaScript Rule.

The first hurdle is to determine which button needs to be customised. The sub grid 'Add New' button calls a different command depending on the nature of the relationship.

If you have a foreign-key attribute on your child entity that is marked as Field Requirement = 'Optional' then the Add New button will be the AddExistingStandard since it allows you to search for an existing record first. If the Field Requirement = 'Business required' then the button will be AddNewStandard

 

 

Once you've identified the right button, you can then open the ribbon workbench and click Customize Command and add the Value Rule as described by my user voice article.

Changing the command actions

Although we cannot add new buttons (did I mention that?!) we can change the command actions that either of those two buttons call. Since we can't customise the button, the only option here is to customise the command and change its behaviour in a very similar way to adding custom enable rules.

  1. Right click the button in the Ribbon Workbench and select Customise Command
  2. Expand the command in the Commands node in the Solution Elements panel and select the command that has been created for you to customise.
  3. Right click Edit Actions and you can simply delete the standard action and add your own custom ones.
  4. Remember to mark all the enable and display rules that you don't want to customise as IsCore=True.

Once such use of this technique is to replace the standard add new button with a custom dialog.

Refreshing the sub grid Command Bar

You will find that when the form is loaded and the sub grid is refreshed for the first time the EnableRules are evaluated. If however the conditions for the EnableRules change (e.g. a value changes on the parent form) the sub grid command bar will not automatically refresh to reflect the new state. Upon adding or deleting rows in the sub grid the command bar is refreshed – but this isn't much use in this case.

The main form command bar can be refreshed using Xrm.Page.ui.refreshRibbon() however this will not refresh sub grid command bars. Instead, we can add an onchange event to the fields that are used in our ValueRule and call:

Xrm.Page.data.save();

This will refresh the sub grids and re-evaluate any of the EnableRules however it will also save any other dirty attributes and so should be used with caution if you do not have auto-save enabled.

Responding to new/deleted rows in the sub grid

Since the sub grid command bar is refreshed when new rows are added or deleted we can use the fact that the EnableRules will be re-evaluated to call custom JavaScript when the sub grid changes. This simulates a sub-gird onchange event and was first described by James Wood's blog post for CRM2011. He states on his blog that this technique doesn't work for CRM2013 – however if we add the custom EnableRule to the existing command (rather than use a new button as James describes) then this technique works well in CRM2013 and CRM2015. So we can customise the command for the Add New or cream cracker and add a Custom JavaScript Enable Rule that always returns true in just the same way that you might use the EnableRule to dynamically show/hide the button but rather we just run our onchange code.

Perhaps in the future there will be more possibilities but for now that about sums up the possibilities for customising the sub grid command bar.

@ScottDurow

Posted on 2. January 2015

SparkleXRM for CRM2015 with process API support

I've just committed an update to SparkleXRM with CRM2015 support and the process client API. One of the design decisions I made early on with SparkleXRM was to stick with a CRM2011 solution format to allow installation on both CRM2011 and CRM2013. Now that CRM2015 does not support installing CRM2011 solutions I've had to branch and make both CRM2011 and CRM2015 versions available. The code base still remains the same but they are distributed through two separate solution files depending on your target version. You can download the new CRM2015 SparkleXRM solution from github.

The new client side process control API is such a welcome addition. The latest version of SparkleXRM contains support for this so that you can:

Write code to run when the stage is changed or the user selects a process tab (such as hiding/showing sections on the form.

// Add On Process Stage change
Page.Data.Process.AddOnStageChange(delegate(ExecutionContext context){
    // Stage Stepped forwards backwards
});

// Add On Process Stage change
Page.Data.Process.AddOnStageSelected(delegate(ExecutionContext context)
{
    // Stage Tab Selected
});

Write code to get the current process and stage so that onload functions can show/hide sections on the form.

// Get Current Process
Process process = Page.Data.Process.GetActiveProcess();

Stage stage = Page.Data.Process.GetActiveStage();
Script.Alert("Process = " + process.GetName() + " Stage = " + stage.GetName());

Write code to get the stages and steps of the current process and find the attributes that are referenced – I've not found a use for this yet!

// Get Stages
ClientCollection stages = process.GetStages();

if (stages.GetLength() > 0)
{
    // Get Steps
    Stage stage0 = stages.Get(0);
    ClientCollection steps = stage0.GetSteps();
    steps.ForEach(delegate(Step step, int index)
    {
        Script.Alert(step.GetName() + " " + step.GetAttribute());
        return true;
    });
}

Write code to show/hide or collapse/expand the process ribbon:

// Show/Hide Process
Page.Ui.Process.SetVisible(true);

// Expand/collapse
Page.Ui.Process.SetDisplayState(ProcessExpanded.Collapsed);

Write to advance/step back the stage or change the process/stage completely:

// Change stage
Page.Data.Process.MoveNext(delegate(MoveStepResult result)
{
    Script.Alert(result.ToString());

});

// Change process
Stage currentStage = stages.Get(0);
Page.Data.Process.SetActiveStage(currentStage.GetId(), delegate(SetActiveStageResult result)
{
    Script.Alert(result.ToString());
});

// Change process to the first available process that the user has access to. 
// If the same as the current process, this does nothing.
Page.Data.Process.GetEnabledProcesses(delegate(Dictionary processes)
{
    Page.Data.Process.SetActiveProcess(processes.Keys[0], delegate(SetActiveProcessResult result)
    {
        Script.Alert(result.ToString());
    });
});

Along with the server side branching support for processes – I think this really finishes off this feature nicely. The business process flow feature is now by far my favourite in terms of innovation, business usefulness and developer API. First it was gold in CRM203 RTM, then green in SP1 - now with CRM2015 I especially like the calming cool blue that the process ribbon is now rendered with!

Cheers,

@ScottDurow

 

Posted on 28. January 2014

Chrome Dynamics CRM Developer Tools

Chrome already provides a fantastic set of Developer tools for HTML/Javascript, but now thanks to Blake Scarlavai at Sonoma Partners we have the Chrome CRM Developer Tools.

This fantastic Chome add in provides lots of gems to make debugging forms and testing fetchXml really easy:

Form Information
- Displays the current form’s back-end information
- Entity Name
- Entity Id
- Entity Type Code
- Form Type
- Is Dirty
- Ability to show the current form’s attributes’ schema names
- Ability to refresh the current form
- Ability to enable disabled attributes on the current form (System Administrators only)
- Ability to show hidden attributes on the current form (System Administrators only)


Current User Information
- Domain Name
- User Id
- Business Unit Id


Find
- Ability to open advanced find
- Set focus to a field on the current form
- Display a specific User and navigate to the record (by Id)
- Display a specific Privilege (by Id)


Test
- Ability to update attributes from the current form (System Administrators only)
- This is helpful when you need to update values for testing but the fields don’t exist on the form


Fetch
- Execute any Fetch XML statement and view the results


Check it out in the chrome web store - https://chrome.google.com/webstore/detail/sonoma-partners-dynamics/eokikgaenlfgcpoifejlhaalmpeihfom

Posted on 2. November 2013

CRM 2013 Script Loading Deep Dive

Ever since the script Web Resource loading behaviour changed in UR12 from series to parallel I've been interested in how to best standardise management the loading of script Web Resources. The fact that scripts are loaded from a variety of places makes the subject even more interesting. This post attempts to answer all of my questions about how scripts are loaded.

In order to fully understand how CRM 2013 loads scripts I examined the following script load points:

1. Form Libraries

Each form can specify multiple libraries, and a set of Events Handlers that are called when the form is loaded.

2. Ribbon Xml Command Actions

Command Bar JavaScript functions that are called when a Command Bar button is clicked. Multiple JavaScriptFunctions can be included in a Command Action and is often used to specify dependency scripts. The following example shows common.js being a dependency to library.js. The 'isNaN' function is simply a dummy function call because common.js only needs to be loaded.

<Actions>
    <JavaScriptFunction FunctionName="isNaN" Library="$webresource:new_common.js" />  
    <JavaScriptFunction FunctionName="fooBar" Library="$webresource:new_library.js" />
</Actions>

3. Ribbon Xml Enable Rule

Enable Rule JavaScript functions are evaluated to determine if a Command Bar is enabled (visible). Again, multiple functions can be specified for an enable Rule and is often used to specify dependency scripts in the same way as shown above for Command Actions.

<EnableRule Id="new.new_valuerulestest.BoolYes.EnableRule">
    <CustomRule FunctionName="isNaN" Library="$webresource:new_ common.js" />
    <CustomRule FunctionName="fooBar" Library="$webresource:new_ library.js" />
</EnableRule>

Approach

I created 6 scripts that each used console.log to write messages as they were loaded and when the functions were being executed. I also used Fiddler to introduce latency into the script downloads so that I could see the order that they were being requested. The terminology I use is in the results are as follows:

  • Script Download - The process of downloading the script web resource from the server.
  • Script Load – The actual evaluation of the script once it has been downloaded from the server. The script load defines any functions and object prototypes. If you have any code that is not contained within a function, then it will be executed at this time. Script load order becomes important when the Script Load includes references to functions that exist in other libraries such as name spacing functions or jQuery constructs. It is advisable to keep these kind of dependencies to a minimum due to requirement to have scripts loaded in a particular order.
  • Script Event Handler – Function registrations that are called on form events such as OnLoad or OnChange that call a function in a loaded script web resource. The Event Handers are different to the Script Load in that the Event Handler is called after the Script has been loaded.
  • Executed – If there is a function that is referenced by an Enable Rule or Command, the function is executed after the script is loaded.

Here are the things you need to know!

The following section summaries the results I discovered from my deep-dive:

Form Scripts

1) Form Script will download in parallel unless they are already loaded by an EnableRule.

2) Form Scripts are not guaranteed to load in the order that they are specified in the form properties. They will be requested asynchronously in parallel and then loaded in the order that they received from the server. This is similar to the CRM2011 UR12-UR14 behaviour meaning that you can't guarantee that a dependency script is loaded before a dependant script without using some custom code to handle dependencies.

3) Form Script OnLoad Event Handlers will execute only after ALL script specified in the Form properties are loaded.

4) Form Scripts that are loaded only by the Form (and not Enable Rules) will appear as a 'normal' script element with WebResource URL in the IE F12 debugger.

Enable Rules

1) EnableRule CustomRule Scripts are downloaded, loaded & executed in series and in the order they are specified in the EnableRule. The next script is loaded after the previous one has been loaded and executed.
2) EnableRule functions are executed immediately after their script is loaded and before the OnLoad form even handler. The function is re-evaluated if the ribbon is refreshed and when the button is clicked (before the command action is executed).

3) Form Scripts will start downloading after all Enable Rule Scripts have been loaded and executed. The Command bar is then available before the form on-load event has been run.

4) An interesting by-product of the fact that Enable Rules load in series before the form scripts is that if you specify the same scripts in an Enable Rule that are referenced by the Form, your scripts will always load in the correct order! I had some situations like this on an upgrade from CRM2011 and I couldn't work out why on some forms the scripts were loaded in series and some in parallel.

5) Scripts loaded by EnableRules will appear as dynamic 'script block' and not a named WebResource URL in the IE F12 debugger.

Commands

1) Command Action JavaScript Function scripts are loaded and executed in series and in the order that they are specified in the Command.

2) Command Action scripts are loaded when the button is clicked and not when the page is loaded (unless they are used by the form or enable rules in which they are already loaded).

3) Scripts loaded by Command Actions will appear as dynamic 'script block' and not a named URL in the IE F12 debugger.

4) I found an interesting boundary condition that if the same scripts were used in the form load and in command actions; you could click the button before all the scripts were loaded so that only part of the command would run. This would have the potential to cause script errors if a user clicked on a command button before the on-load event had fired.

General

1) Scripts are loaded only once per page even if they are referenced in multiple places (Commands, EnableRule and Form Libraries).

Script Loading Process Flow

So that you can fully understand the script loading process, I've attempted to show a good approximation in flow chart form.

Key points of note on the flow:

  1. Enable Rule Scripts are loaded in series
  2. Form Scripts are loaded in Parallel.
  3. Command Action Scripts are loaded in series
  4. Command Actions can be executed before the Form Scripts are loaded.

     

Working around the parallel loading of Form Scripts

When parallel loading of scripts first became an issue in CRM2011 with UR12 I used a timeout style approach to waiting for dependant scripts to load. You can read more about this on my blog post on the subject.

Now rather than use a timeout wait, I feel that a more deterministic approach would be more suited. By wrapping the script web resources in the following, my tests showed that were always loaded in the correct order. The scriptLoader uses a dependency registration mechanism that allows registration of scripts to be loaded only when all of the dependant scripts are also loaded.

var scriptLoader = scriptLoader || {
    delayedLoads: [],
    load: function (name, requires, script) {
        window._loadedScripts = window._loadedScripts || {};
        // Check for loaded scripts, if not all loaded then register delayed Load
        if (requires == null || requires.length == 0 || scriptLoader.areLoaded(requires)) {
            scriptLoader.runScript(name, script);
        }
        else {
            // Register an onload check
            scriptLoader.delayedLoads.push({ name: name, requires: requires, script: script });
        }
    },
    runScript: function (name, script) {      
        script.call(window);
        window._loadedScripts[name] = true;
        scriptLoader.onScriptLoaded(name);
    },
    onScriptLoaded: function (name) {
        // Check for any registered delayed Loads
        scriptLoader.delayedLoads.forEach(function (script) {
            if (script.loaded == null && scriptLoader.areLoaded(script.requires)) {
                script.loaded = true;
                scriptLoader.runScript(script.name, script.script);
            }
        });
    },
    areLoaded: function (requires) {
        var allLoaded = true;
        for (var i = 0; i < requires.length; i++) {
            allLoaded = allLoaded && (window._loadedScripts[requires[i]] != null);
            if (!allLoaded)
                break;
        }
        return allLoaded;
    }
};

scriptLoader.load("Script Name", [("Dependency Script 1","Dependancy Script 2"}, function () {

// TODO: Your script goes here!

});

You must encapsulate every form script that is a dependant or a dependency. The load function has the following parameters:

  • Name – Specify a unique name of each of your scripts
  • Requires – Specify an array of script names that must be loaded before the current one is loaded.

Of course, the script can be minified to reduce its impact on your individual Web Resources.

Conclusions

Armed with the information I've discovered in this deep-dive, I feel I'm equipped to make the right decision when designing solutions that include multiple script Web Resources.

@ScottDurow

 

 

Posted on 8. August 2013

jQuery and jQuery UI with Dynamics CRM 2011 & 2013

Since I’ve been converting Silverlight web resources over to Html & JavaScript and working on www.SparkleXrm.com , I’ve worked extensively with jQuery and jQuery-UI.

In the early days of Dynamics CRM 2011, you could use both these libraries without a problem, but with the Activity Feeds solution an instance of jQuery appeared that interfered with your custom scripts.
This is still the case in Dynamics CRM 2013 and so here are some simple steps to ensure your libraries are safe and will co-exist with other instances from other solutions.

1. Decide on a custom ‘namespace’ for your jQuery library. I am using ‘xrmjQuery’

2. On the end of your jquery.js script add the following line:

/* jQuery script goes here */
window.xrmjQuery = jQuery.noConflict(true);

3. Inside your jquery_ui.js script (notice the ‘-‘ has been changed to an underscore since CRM doesn’t allow them in web resource names), wrap the whole file in the following lines:

(function ($,jQuery) {
	/*! jQuery UI Goes here */
})(window.xrmjQuery,window.xrmjQuery);

4. Inside your JavaScript web resource that use jQuery and jQuery-UI, wrap your code in the following:

(function($){
// Your Javascript goes here and can reference $ as usual
// e.g. var someField = $('#fieldName');
})(window.xrmjQuery);

This technique is called encapsulation and namespacing of jQuery.

My friend Carsten also has a blog post on a similar theme.

www.SparkleXrm.com uses the same technique and namespace is also ‘xrmjQuery’, so if you would like to quickly get access to the jQuery libraries in Dynamics CRM, you can install the SparkelXrm managed solution and include the web resource named ‘sparkle_/js/SparkleXrmUI_Dependancies.js’ – this is a single library that has both jQuery, jQueryUI as well as a few other goodies such as Knockout JS!

 

@ScottDurow

Posted on 29. March 2013

Asynchronous loading of JavaScript Web Resources after U12/POLARIS

We all know that UR12/POLARIS was a monumental release for Dynamics CRM what with the new Process Forms and Cross Browser support, but also included were some performance optimisations. One such improvement was a change to the way JavaScript Web Resources are loaded on forms so that they load and execute asynchronously rather than in the order that they were added to the form. The drawback with this optimisation is that it can cause the '..is undefined' script error if you have scripts that depend on other scripts being loaded first.

This post describes the loading behaviour and some possible solutions.

How did it work before UR12/POLARIS?

In my example I have 3 scripts, each dependant on the last. Mscorlib.js is the Script# system library that is needed before any other libraries can be loaded. I'm not talking about code that runs in the 'onload' event of a form but global code that is run after the script has downloaded used to define the prototypes of the objects that are used by the onload code.

In the Client.js, I might have some Script# generated code that requires a core Script# (ss.IEnumerable) type that is defined in a different script file.

Xrm.Sdk.DataCollectionOfEntity.registerClass('Xrm.Sdk.DataCollectionOfEntity', null, ss.IEnumerable);

For this code to run, the mscorlib.js must be loaded and executed first. The same applies if you are using jQuery and jQuery-UI.

The form definition used to have each script added in order so that they would be added to the 'head' section of the page as follows:

<head>
..
<script src=”/%7B635001685810000000%7D/WebResources/fdocs_/js/mscorlib.js” type=”text/javascript”></script>
<script src= /%7B635001685810000000%7D/WebResources/fdocs_/js/Xrm.js” type=”text/javascript”></script>
<script src=” /%7B635001685810000000%7D/WebResources/fdocs_/js/Client.js” type=”text/javascript”></script>
..

The resulting load pattern would be something like:

  • The script load/execution would be approximately:

    1. Mscrolib.js downloads and then executes
    2. Xrm.jsd downloads and then executes after mscrolib.js has completed executing since it follows it in the <HEAD> section of the page
    3. Client.js downloads and then executes after Xrm.js has completed executing since again it is added to the <HEAD> section in this order.
    4. The On Load event code then runs when all the scripts have loaded and finished executing

     

     

    What changes with the UR12/POLARIS update?

    Scripts are no longer in the <HEAD> section but are loaded asynchronously via the 'loadScriptAdv' function:

    loadScriptAdv('\x2f\x257B635001707050003339\x257D\x2fWebResources\x2ffdocs_\x2fjs\x2fmscorlib.js', '\x2f\x257B635001707050003339\x257D\x2fWebResources\x2ffdocs_\x2fjs\x2fmscorlib.js', false);
    loadScriptAdv('\x2f\x257B635001707050003339\x257D\x2fWebResources\x2ffdocs_\x2fjs\x2fXrm.js', '\x2f\x257B635001707050003339\x257D\x2fWebResources\x2ffdocs_\x2fjs\x2fXrm.js', false);
    loadScriptAdv('\x2f\x257B635001707050003339\x257D\x2fWebResources\x2ffdocs_\x2fjs\x2fClient.js', '\x2f\x257B635001707050003339\x257D\x2fWebResources\x2ffdocs_\x2fjs\x2fClient.js', false);
    

    The new asynchronous load behaviour results in the OnLoad being run after a smaller wait time since each script can execute without waiting for the preceding ones. This is a good performance gain but causes scripts to fail if the dependant scripts are not loaded at the point of execution.

  • The interesting thing is that this wasn't immediately apparent or was only an intermittent problem because once the scripts are loaded into the browser cache, the execution would usually be in the correct order. I can consistenly reproduce the issue by clearing down the browser cache and then disabling all caching.

    Ribbon JavaScript

    It's been a common technique to add dependant libraries to Ribbon Commands by adding them as Command Actions with a function of 'isNaN'

    <Actions>
    <JavaScriptFunction Library=”$webresource:mscorlib_crm.js” FunctionName=”isNaN”/>
    <JavaScriptFunction Library=”$webresource:xrm.js” FunctionName=”isNaN”/>
    <JavaScriptFunction Library=”$webresource:RibbonCommands.js” FunctionName=”someCommand”/>
    </Actions>
    
    

    It seems that the same issue exists with these libraries since they are loaded in an asynchronous fashion.

    Solutions

    Unfortunately, any solution that uses depending scripts in this way has to be updated – and like with all things, the right solution depends on your specific case.

    1) All script in a single library

    By far the simplest solution is to put all of your scripts into a single file in the correct order.

    I didn't' settle for single script option for the following reasons:

    1. A single script is harder to maintain
    2. Common libraries can't be shared between solutions
    3. All code must be downloaded on first use, rather than only downloading what is required at the time.

    2) RequireJs or HeadJs

    There are some good JavaScript loading libraries out there such as RequiresJs or HeadJs. These libraries allow you to dynamically load dependant script before you execute code that needs them.
    Gayan has an example of this technique on his blog. Maarten also has a good tutorial on his blog.

    I didn't settle for the RequireJs/HeadJs option for the following reasons:

    1. It requires you to manually set the Cache key to ensure that scripts are not downloaded every time they are needed
    2. It completely bi-passes the Dynamics CRM script loading mechanism in an 'unsupported' way
    3. There is some possibility that a backward compatibility option may be added into a future release (I'm ever the optimist!). Adopting this approach would make it harder to revert back to the standard script registration approach.

    3) Manually wait for required libraries to load

    The approach I took was to build a simple wait function to wrap code in that prevented execution until the required scripts had loaded. Each time a script completes, it adds its name to a semaphore array that is waited on by other libraries. The result is much the same as before UR12:

  • The difference here is that the scripts start executing as soon as they are loaded, but then wait using setTimeout until the required scripts have completed. The code will work on pre-UR12 systems as well, but because the wait is unnecessary, the code will simply execute the script without checking dependancies. setTimeout is used to release control to other scripts because Javascript is single-threaded.

    The Code

    Each script that has dependencies must be wrapped in the following:

    waitForScripts("client",["mscorlib", "xrm",],
    function () {
    //Original Code goes here
    });
    

    The first parameter provides the name of the current script, and the array is the list of scripts that must be loaded first.

    So in the Xrm.js library, you would wrap it in:

    waitForScripts("xrm",["mscorlib"],
    function () {
    //Original Code goes here
    });
    

    Each script must also include the waitForScript function at the bottom:

    function waitForScripts(name, scriptNames, callback) {
        var hasLoaded = false;
        window._loadedScripts = window._loadedScripts || [];
        function checkScripts() {
            var allLoaded = true;
            for (var i = 0; i < scriptNames.length; i++) {
                var hasLoaded = true;
                var script = scriptNames[i];
                switch (script) {
                    case "mscorlib":
                        hasLoaded = typeof (window.ss) != "undefined";
                        break;
                    case "jquery":
                        hasLoaded = typeof (window.jQuery) != "undefined";
                        break;
                    default:
                        hasLoaded = window._loadedScripts[script];
                        break;
                }
                allLoaded = allLoaded && hasLoaded;
                if (!allLoaded) {
                    setTimeout(checkScripts, 10);
                    break;
                }
            }
            if (allLoaded) {
                callback();
                window._loadedScripts[name] = true;
            }
        }
        // Only check for async loading of scripts if later than UR12/POLARIS
        if (typeof(APPLICATION_FULL_VERSION)!='undefined' && parseFloat(APPLICATION_FULL_VERSION.replace('5.0.',''))>9690.2835) {
    	setTimeout(checkScripts, 0);
        }
        else {
    	callback();
            window._loadedScripts[name] = true;
        }
    }

    Script# 'Script.template'

    I almost exclusively use Script# in my Dynamics CRM projects. What made this solution really work well for me was that I just include the code in the Script.template file to wrap the '#include[as-is] "%code%"'. The beauty is that I can now forget it's there and it just gets minified along with the rest of the code when deployed.

    This issue has affected a number of people I know, and I'm sure it'll start to become more of an issue as people start to upgrade to the latest Rollup. If you have any suggestions/comments, please let me know.

    The code was originally posted by me in the MSDN forums:

     http://social.msdn.microsoft.com/Forums/en-US/crmdevelopment/thread/fdca4779-e866-4e51-bab9-97a159f9cd37

     

    UPDATE: This issue is now fixed in UR15 -http://support.microsoft.com/kb/2843571

    @ScottDurow

    Posted on 12. January 2013

    getServerUrl is Deprecated. Use getClientUrl instead.

    Although at the time of writing UR12 is not yet released - I was checking though the changes in the latest SDK documentation.

    In addition to the Ribbon Workbench being listed (yay!) I noticed the following statement about the getServerUrl function

    "Deprecated. Use getClientUrl instead. This method is deprecated as of Microsoft Dynamics CRM 2011 Update Rollup 12 and the Microsoft Dynamics CRM December 2012 Service Update."

     

    Out with the old

     

    Using getServerUrl on it's own always had the potential to cause 'Access Denied' messages if the browser domain Url was different to the server Url stored in the CRM database. This was to do with cross domain access restrictions in IE. A work around was to use a method similar to Daniel Cai gives in his post on the subject - http://danielcai.blogspot.co.uk/2012/02/get-right-server-url-in-your-crm-client.html

    In with the new

    The SDK described the new getClientUrl as:

    "Returns the base URL that was used to access the application."

    The function nolonger blindly return the server Url in the database - but looks at the url that was used to access CRM so that cross domain access issues will be a thing of the past!

    Read more in the SDK:
    http://msdn.microsoft.com/en-us/library/d7d0b052-abca-4f81-9b86-0b9dc5e62a66#BKMK_getClientUrl

    @ScottDurow

     

    Posted on 27. September 2012

    Script# (ScriptSharp) delete statement

    I've been using Script# very succesfully for sometime now to generate CRM2011 Javascripts (you can get a version of the Xrm library for Script# at http://sharpxrmpage.codeplex.com/).

    I problem I encounted recently was where I needed to issue a delete statement. E.g.

    delete xmlDoc;

    There is only Type.DeleteField support in Script# which allows deleting of a field on an object, but there is no way of outputing a simple local scope delete statement.

    I orignally used:

    Script.Literal("delete xmlDoc");

    This worked fine for debug scripts, however when using the release scripts that are minified, of course the variable xmlDoc is output as something like $1_0 and so the literal statement fails.

    After some research I found that the following statement works:

    Script.Literal("delete {0}",xmlDoc);

    Hope this helps.

    Posted on 18. January 2012

    iPad killed the Silverlight star?

    After the initial Statement of Direction in May and then the interview with Brad Wilson the then general manager of Dynamics CRM, there has been quite some excitement about cross-browser support for Dynamics CRM 2011. The timescale given was "the first half of 2012" being release with UR8. The thought of access to Dynamics CRM from an iPad is quite an attractive prospect I have to admit - and I'm really excited to see how Microsoft are going to structure the CRM user interface when they deliver it through cross browser HTML5.

    • Are we going to get a single cross browser interface, or will there still be a IE specific one with richer functionality?
    • Will the cross browser support be more like the mobile client - with it's own form design - Will IE still be the preferred browser?
    • You will still need IE to use the Outlook Client so will the cross browser support be more of a 'selling point' than something that actually makes a significant difference to business users?

     

    Cross browser HTML5 will mean replacing the IE specific .htc 'behaviours' which is quite a considerable piece of work - but a subject closer to my heart is the future of Silverlight in CRM2011. Silverlight is supported on most modern browsers (http://www.microsoft.com/getsilverlight/get-started/install/default.aspx#) but not on iPads. Could this mean an end to Silverlight WebResources just so that we can get iPad support?

    Only time will tell, but it might make it harder to choose the developer productivity and user experience gains that come with Silverlight. The iPad is not a desktop replacement. There are limitations with SalesForce.com on the iPad (http://www.crmverse.com/using-salesforce-com-on-ipad/). Unless a client has decided to use iPads as a primary user interface device, I am still recomending developing Silverlight WebResources but structuring them in a way that will make it easier to port them to an HTML5 user interface when the developer tooling support is improved.

    Maybe with Windows 8 Tablets the problem will go away...then again...maybe not!

    References: