Business Rules and real time workflows have reduced the necessity to write Javascript in Microsoft CRM for really simple use cases. Once the requirements are a bit more complex and client side scripting seems the right choice, you can try using Typescript.
Pre-requisites
- Install Node
- Globally install gulp by typing “npm install gulp -g” into the command prompt
- Globally install Typescript compiler by typing “npm install typescript -g” in command prompt.
- Install VSCode
package.json
{ "devDependencies": { "babel-core": "^5.8.25", "del": "^2.0.2", "gulp": "^3.9.0", "gulp-babel": "^5.3.0", "gulp-load-plugins": "^1.0.0", "gulp-size": "^2.0.0", "gulp-sourcemaps": "^1.6.0", "gulp-tsc": "^1.1.1", "gulp-uglify": "^1.4.2" }, "engines": { "node": ">=0.10.0" }, "private": true }
Once you download the repo from https://github.com/rajyraman/crm-client-scripts/tree/master/typescript run “node install” inside the typescript folder from command prompt. This will bring across the required node modules.
The below is the config file for gulp.
import gulp from 'gulp'; import del from 'del'; import gulpLoadPlugins from 'gulp-load-plugins'; import source from 'vinyl-source-stream'; import buffer from 'vinyl-buffer'; import glob from 'glob'; import es from 'event-stream'; const $ = gulpLoadPlugins(); gulp.task('build', ['clean'], ()=> { glob('src/**/**form.ts', function(err, files) { var tasks = files.map(function(entry) { let fileName = entry.substr(entry.lastIndexOf('/')+1).replace('.ts','.bundle.js'); return gulp.src([entry]) .pipe($.tsc({keepTree: false, out: fileName})) .pipe(buffer()) .pipe($.sourcemaps.init({loadMaps: true})) .pipe($.uglify({preserveComments: 'some'})) .pipe($.sourcemaps.write()) .pipe(gulp.dest('build')); }); return es.merge.apply(null, tasks); }); gulp.watch(['src/**/*.ts'], ['build']); }); // Clean output directory gulp.task('clean', cb => del(['.tmp', 'build/*', '!build/.git'], {dot: true}, cb)); gulp.task('default', ['build']);
In this build file, I make these assumptions:
- Scripts for each entity are stored in a separate folder
- The main entity script is suffixed with .form
Since the dependant files are always included via the triple slash reference comment on all the “.form.ts” files, Typescript compiler will package up the output Javascript file with all the required dependencies.
There is also a gulp watch in the build task, so that any changes you make to the Typescript files, triggers the build task and hence the compiled Javascript files will always be in sync with the Typescript files. In order to start build, just type “gulp” in the command prompt from the folder containing the gulp.babel.js and the default task should take care of the rest.
Typescript Definitions
Dave Berry has published the tsd files for CRM Client side development. There are so many good reasons to use Typescript, and Intellisense is one of the top items in my list. There are community published tsds for other popular libraries and so you are not losing any thing by switching to Typescript.
Head to the Typescript playground to quickly familiarise yourself with the features and see how your Typescript code is compiled into Javascript. Here is a quick comparison on couple of the common ones, in terms of CRM development with Dave Berry’s tsd files.
Javascript | Typescript |
Xrm.Page.getAttribute(‘[NAME]’).setValue(‘hello’) | Xrm.Page.getAttribute<Xrm.Page.StringAttribute>(‘[NAME]’).setValue(‘hello’) |
Xrm.Page.getControl(‘[NAME]’).setDisabled(false) | Xrm.Page.getControl(‘[NAME]’).setDisabled(false) |
Xrm.Page.getAttribute(‘[NAME]’).setValue([{id: ‘[ID]’, name: ‘[NAME]’, entityType: ‘[TYPE]’}]) | Xrm.Page.getAttribute<Xrm.Page.LookupAttribute>(‘[NAME]’).setValue([{id: ‘[ID]’, name: ‘[NAME]’, entityType: ‘[TYPE]’}]) |
Xrm.Page.getAttribute(‘[NAME]’).setValue(new Date()); | Xrm.Page.getAttribute<Xrm.Page.DateAttribute>(‘[NAME]’).setValue(new Date()); |
These are the valid types for attributes types as per the tsd:
- NumberAttribute
- StringAttribute
- EnumAttribute (for Optionsets and bool)
- DateAttribute
- LookupAttribute
These are the valid control types as per the tsd:
- StandardControl
- GridControl
- FramedControl
- SilverlightControl
Why should you use Typescript
Types is a polarizing topic. Some prefer dynamically typed language, while some prefer strongly typed. With ever increasing Javascript adoption, there is a growing opinion that types are a good thing. Typescript still compiles into Javascript, but uses typing to improve developer productivity. It also adds some additional features that are not in Javascript. These are some of the advantages:
- Intellisense
- Compilation stage catches the obvious errors arising due to types
- Generics
- Modules (available in ES6 as well)
- Classes (available in ES6 as well)
- Union Types
- Microsoft product – great tooling support with VSCode and Visual Studio
- Open source
Screenshots
Image may be NSFW.
Clik here to view.
Image may be NSFW.
Clik here to view.
Final notes
I have also added a sample project on how to do this with ES6, Babel and Browserify. You can refer https://github.com/rajyraman/crm-client-scripts/tree/master/es2015 for this, if you still want to use just Javascript.
Image may be NSFW.
Clik here to view.
Clik here to view.
