I often use Script editors or Content Editor Web Parts linked to an Html file to launch a client application in SharePoint. My base approach to all these apps is to:
- Register all the scripts as with Script on Demand
- Call LoadMultiple passing in the Script Keys
- Executing my JavaScript app
- Wrapping it all in a closure
Today I was using the very excellent momentjs and moment-timezone libraries, which are super helpful when dealing with dates in JavaScript. I realised I had got inadvertently got myself into a race condition, in which I was often losing :(. The moment-timezone script would error with:
Uncaught TypeError: Cannot read property 'version' of undefined
Error: ReferenceError: moment is not defined
What I had missed was to delcare the dependency between moment.js and moment-timezone.js.
Here's an example of my client app with the fix:
<div class="myapp-wp">
<div class="myapp-wp-panel">
</div>
</div>
<script type="text/javascript">
var myappWrapper = function () {
var baseUrl = _spPageContextInfo.siteServerRelativeUrl;
if (baseUrl.substring(baseUrl.length - 1) === "/") {
baseUrl = baseUrl.substring(0, baseUrl.length - 1);
}
SP.SOD.registerSod("myapp.js", baseUrl + "/Style Library/Client Apps/myapp/js/myapp.js?rev=1");
SP.SOD.registerSod("moment.js", baseUrl + "/Style Library/Client Apps/Common/libs/momentjs/moment.min.js");
SP.SOD.registerSod("moment-timezone.js",
baseUrl + "/Style Library/Client Apps/Common/libs/momentjs/moment-timezone-with-data.min.js");
SP.SOD.registerSodDep("moment-timezone.js", "moment.js");//Moment is a dependency of moment-timezone, so register it.
SP.SOD.loadMultiple(
["SP.js", "myapp.js", "moment.js", "moment-timzone.js"],
function () {
//... Load the app here
});
}();
</script>
The moral of the story is this line:
SP.SOD.registerSodDep("moment-timezone.js", "moment.js");
That let's SharePoint know that we want to load up moment.js before moment-timezone.js.