You can use a View Override in MDriven Turnkey to add custom HTML, site assets, and JavaScript to a ViewModel-driven page while retaining the standard Turnkey behavior; this session is for developers who need a custom interaction such as recording damage locations on a vehicle.
What Session 11 demonstrates
Session 11 extends the view-override approach introduced in Documentation:Turnkey session 9: View Override. The example adds a Car Damages action to a rental application. The resulting page lets a user mark damage on an image of a car.
The custom page combines these parts:
| Part | Purpose in the example |
|---|---|
| ViewModel data | Provides values such as the car name, registration number, user name, and the text properties used to store recorded positions. |
| Injected HTML content | Adds page-specific text and a canvas element where the user marks damage.
|
| Site asset | Supplies the car image used as the canvas background. |
| Page style | Applies the uploaded image as the background for the drawing area. |
| JavaScript | Handles mouse input on the canvas, converts clicks into coordinate data, and writes that data back to the AngularJS model. |
The standard Turnkey page remains in use apart from the content added by the override. This is useful when you need a specialized interaction without replacing all standard page behavior.
Before you start
Create the business data and ViewModel structure before writing the override.
In the demonstrated model, a DamageInfo class holds the damage coordinates:
XPosas textYPosas text
The rental contract creates DamageInfo objects. A Car Damages ViewModel exposes the values needed by the page, including the coordinate-related properties. The custom HTML and JavaScript can only work with data exposed through the ViewModel.
For example, the script can collect the X and Y positions of clicks in JavaScript arrays, then save the combined values to text properties that the ViewModel exposes. The model, rather than browser-only state, is the persisted representation of the drawing.
Build the car-damage interaction
1. Add an action and open a dedicated ViewModel
Add a Car Damages action for the car in the rental workflow and have it open the ViewModel intended for damage entry. The session uses a dedicated Car Damages ViewModel so that the custom page has a clear, task-specific data contract.
Keep validation and business rules in the model and ViewModel. See Documentation:Turnkey session 4: ViewModel validation for validation behavior in Turnkey pages.
2. Create or edit the View Override
Create a View Override for the ViewModel and use the ViewModel name for the override. Session 11 uses the override named Car Damages.
Choose the option that injects content into the standard page when you want the standard surrounding UI to remain available. Add only the page-specific markup, style, and script needed for the interaction.
The foundational override workflow, including replacing an entire generated view and binding ordinary controls, is documented in Documentation:Turnkey session 9: View Override.
3. Upload the car image as a site asset
Upload the image that represents the car as a site asset. In the session, the asset is a PNG image named car damage.
Reference that asset from the page-style section so that it becomes the background of the area where damage is marked. Use an image whose layout matches the coordinates your script records; changing the image size or layout changes the meaning of stored click positions.
4. Add the custom page content
Add markup that presents the vehicle information and the drawing surface. The session's custom content uses values from the ViewModel, including the car name, registration number, and user name, and introduces a canvas with the identifier canvas.
A canvas is an HTML element that JavaScript can draw on and receive pointer events from. The canvas identifier gives the script a stable way to locate the element it must control.
Conceptually, the override contains content of this form:
<div>
<!-- Bind and display values exposed by the Car Damages ViewModel. -->
<canvas id="canvas"></canvas>
</div>
Use the actual ViewModel property names from your model. Do not assume that a domain property is available in the page unless the ViewModel exposes it.
5. Add page-specific JavaScript
Put the drawing logic in the override's JavaScript section. The script must:
- Find the
canvaselement introduced by the custom markup. - Obtain the AngularJS scope for that page.
- Read and write properties exposed by the ViewModel through that scope.
- Handle mouse events on the canvas.
- Store the recorded coordinates in the ViewModel and apply the change.
In the session example, the mousedown handler starts an added click/mark. The script adds coordinates to JavaScript arrays while the user draws or marks the canvas. On mouse-up, an apply operation joins the arrays into text and saves the result to the AngularJS model.
The essential pattern is:
// Conceptual flow; use your actual canvas, scope, and ViewModel property names.
// 1. Receive mouse input.
// 2. Add the calculated coordinates to JavaScript arrays.
// 3. On mouse-up, join the arrays into text.
// 4. Write the text to an exposed AngularJS model property.
// 5. Apply the scope change so Turnkey receives it.
Do not keep the final damage information only in JavaScript arrays. Write it to the ViewModel property so that the normal Turnkey change handling can save it.
6. Test normal page behavior
Test the override as a Turnkey view, not only as an isolated HTML page:
- Open the Car Damages action and confirm that the custom canvas and car image appear.
- Add one or more marks and confirm that the page becomes changed, so the standard Save behavior is available.
- Save the change and reopen the view to verify that the model data is used.
- Test undo and redo after making a mark.
- Open the same view in two instances for the same signed-in user and make a change in one instance. The session demonstrates that the change appears in the other instance as well.
This behavior is the result of writing the data through the AngularJS model. A canvas can be custom UI, but the underlying changes still participate in the ViewModel-based interaction.
Design guidance
| Do | Why |
|---|---|
| Expose every value the override needs through the ViewModel. | The HTML and JavaScript have access to data derived from the ViewModel. |
| Store the result of a custom interaction in model-backed ViewModel properties. | Saving, undo/redo, and updates in other open instances depend on the normal ViewModel change path. |
| Use a site asset for the visual background. | The asset can be managed with the site and referenced by the page style. |
| Keep the override focused on presentation and browser interaction. | Put business data, creation rules, and validation in the model and ViewModel. |
| Test on different device sizes. | The demonstrated view retains Bootstrap-based adaptation, but custom canvas layout and coordinate handling still need testing. |
Common pitfalls
- The script cannot find the drawing surface: Ensure that the canvas identifier in the HTML matches the identifier the script looks up.
- A value is undefined in the page: Add or expose that value in the ViewModel; the override does not automatically receive every property in the domain model.
- Marks display but do not save: Ensure the script writes to an exposed AngularJS model property and applies the change after mouse input.
- Recorded positions no longer line up with the image: Check whether the canvas or background image dimensions changed. Coordinate data is meaningful only relative to the visual layout it was recorded against.
- Standard controls are missing unexpectedly: Check whether the override replaces the whole page or injects content into the standard page. Use injected content when you intend to retain the standard page around the custom content.
Watch the session
Watch MDriven Turnkey Part 11: More on View Override for the complete car-damage example, including the site asset, canvas script, model structure, and update demonstration.
