One of the selling points of Power Platform is the "No code/low code" approach, which makes it easy for citizen developers to build apps without needing deep technical skills.
But if you ask anyone who was around Power Platform long enough, they'll tell you that the "no code/low code" ends pretty quickly.
I find it especially true when building Model-driven apps. Sure, the platform automatically generates the user interface based on the data model, and the modern UI lets app makers customize forms and views with ease. CRUD (Create, Read, Update, Delete) operations are handled by the platform, so makers can focus on what really matters. However, when it comes to adding more complex logic, things get tricky. The built-in business rules are quite limited, and for anything beyond basic functionality, app makers often need client scripts (JavaScript), custom PCF Components (TypeScript) , functions in Dataverse (PowerFx, today still in Preview), low-code plug-ins in Dataverse (PowerFx. still in Preview) or even Plug-ins (C#) .
This post focuses on extending forms in Model-driven apps with client script.
Getting started
If you haven't written any client scripts yet, I recommend the Perform common actions with client script in Power Platform - Training | Microsoft Learn guide on performing common actions with client scripts in Power Platform. This resource will provide you with a solid foundation and practical examples.
👉 Remember to add .js at the end of the client script resource. This will help you with debugging.
Reference other .js files
If you have external dependencies, such as other JS files, make sure to configure them as dependencies to the web resource so they are loaded with the form.
👉 Web resource dependencies do not provide any control over the order in which the web resources are loaded.
Forcing refresh of your client-side script
To ensure that the new version of your script is loaded to the user's browser, use the approach described in Force refresh of custom scripts in Power Platform model-driven apps.
Use TypeScript instead of JavaScript
I'm sure I don't have to convince you that TypeScript is better than JavaScript. It offers better tooling, type safety, and catches bugs early, which is a big win when building complex apps on the Power Platform.
If you're working with Dataverse and want a solid developer experience, the Dataverse DevTools extension for Visual Studio Code is a great choice. It helps you set up your project quickly, connect to your environment, and generate strongly-typed TypeScript classes for tables and columns. This makes it easier to write clean, maintainable code when working with client scripts.
👉If you don't see the "add typescript" after installing the extension, restart Visual Studio.
👉 The connection seems active even if it isn't. Always check if your scripts got deployed, or make a habit to reconnect in the morning.
Keep in mind that there are two build modes: build-dev
for debugging and build
for production deployment. When deploying production version (build
), all your files will be bundled into a single JavaScript file to avoid external dependencies.
👉 If you import just one method from a class, the entire class (including unused methods) gets included in the build. To keep the final file size smaller, it’s better to export only the functions you actually need.
Debugging
Debugging locally can save you a lot of time since you don’t have to wait for the file to be deployed and published every time you make a change. To make this easier, check out Microsoft’s guide on using Fiddler Auto Responder for script web resource development in model-driven apps.
Build in dev mode
Be sure to rebuild your project using the build-dev
mode for local testing.
Is Auto-responder working?
Ensure that capturing is enabled. If it’s active, and the mapping is configured correctly, the file information will be displayed in green.
Clear the cache
If your form was already open, the JavaScript might be cached. To clear it:
- Press F12 to open DevTools
- Go to Application > Cache Storage > WebResources
- Delete the folder
- still with DevTools open, use "Empty cache and hard refresh"
Unit tests
Once your codebase becomes more stable, it's a good idea to start writing unit tests. This helps ensure your logic works as expected and makes it easier to catch bugs when making future changes.
The Dataverse DevTools project installs @types/xrm
to provide type definitions, but keep in mind that the actual XRM context isn’t available in the test environment - it’s only present when the app is running in the browser.
When writing unit tests, you may choose to:
Mock the Xrm object manually: This is a simple and lightweight approach that works well for small or straightforward apps. You'll need to manually mock every method your code calls, which can get tedious as complexity grows.
Use the xrm-mock library: This provides a more structured way to simulate the XRM environment. It covers many common methods, though some of them throw "Not implemented". If something’s missing, you can still use
jest.spyOn
(or a similar method in your test framework) to mock specific return values or behaviors.
Both methods have their place. Choose based on your project’s complexity and testing needs.
Automated testing
👉 It's funny how some of the most useful tools seem buried, isn't it? One great example is the Power Apps Test Engine - a powerful but often overlooked resource. It’s packed with tools, guides, and best practices to help you apply low-code testing effectively in your Power Apps projects. Whether you're just getting started or looking to level up your testing strategy, it's definitely worth exploring.
Top comments (2)
As always a great series here @kkazala
As a Mac user, I found it better and more fluent to run a local node service that serves local web resource script files, and use request.ly (or equivalent) to set redirect rules to the served files, instead of Fiddler. “Fiddler Everywhere” (the version supported on Mac) is quite different to classic Fiddler. I can share a walkthrough if you think that would be helpful.
@euankennedy I think it's a brilliant idea. It's a pity that my posts are not always universal, and you adding the procedure for Mac users will have enormous value. Perhaps you want to write your own post and I will reference it in mine?