The AngularJS client is the standard Turnkey web client for developers who build interactive, ViewModel-driven web pages on MDrivenServer.
What the AngularJS client does
The AngularJS client is an implementation of the Streaming Client. It connects to the Turnkey server through the Streaming API and presents a user interface based on the current ViewModel.
A streaming client keeps the objects needed by the client in server memory and subscribes to changes. This makes the user interface respond when data changes. For example, when a user edits a customer field in a ViewModel-bound control, the client can signal that change to the server and the bound interface can reflect resulting updates.
The AngularJS client is part of the standard Turnkey web client. Its place in the overall solution is described in MDriven Turnkey Architecture.
How it fits into a Turnkey application
A Turnkey application can contain both AngularJS-rendered ViewModel pages and server-rendered MVC pages. Use the AngularJS client for interactive ViewModel user interfaces. MVC pages can still participate in navigation where required.
| Area | Responsibility | Example |
|---|---|---|
| MDrivenServer / Turnkey server | Maintains the objects and subscriptions required by the streaming client and exposes the Streaming API. | A change to data needed by an open ViewModel is available to the connected client. |
| AngularJS client | Renders the ViewModel-oriented interface in the browser, applies AngularJS binding, and signals user changes. | An input bound to a ViewModel column displays its current value and reports an edited value. |
| MVC page | Handles server-rendered pages and may redirect into an AngularJS ViewModel page. | A request handled by an MVC controller redirects the browser to a page that enters the AngularJS client. |
For the MVC-to-AngularJS navigation sequence and its requirement for two EcoSpaces, see Documentation:Serverside Turnkey and MVC functioning.
Work with ViewModel bindings
Use the generated binding suggestions when you customize how a ViewModel is presented in the AngularJS client.
- Open
https://<yoursite>/Turnkey/Development?view. - Find the ViewModel you are working on.
- Use the suggested AngularJS binding as the starting point for the relevant control or override.
- Keep the binding connected to the intended ViewModel column so that user edits can be detected and sent through the normal Turnkey flow.
For example, if you need an override for a text editor bound to a ViewModel column, begin with the binding suggested by the Development view instead of creating an unrelated client-side data structure.
See Documentation:Bindings for angular for the available binding suggestions.
Add JavaScript before AngularJS compiles
Add application-wide JavaScript includes when you need client-side code such as directives, integration libraries, or functions called from a ViewModel action.
- Create
AppWideAngularScriptIncludes.htmlinEXT_Scripts. - Add script tags for the JavaScript files that the AngularJS client must load before Angular compiles.
- Alternatively, place an
AppWideAngularScriptIncludesfile in anEXT_Componentsfolder when the scripts belong with that component. - On Linux, use the lowercase filename
appwideangularscriptincludes.html, because filenames are case-sensitive.
Example:
<script src="/EXT_Scripts/MyIntegration.js"></script>
Use Documentation:AppWideAngularScriptIncludes for the file locations and component-level loading behavior.
Call an existing browser function from a ViewModel action
When a ViewModel action needs to trigger an existing JavaScript function in the browser, use vClientScriptExecute. This is intended for cases such as executing a tracking function after an application action.
The client recognizes a function call with one double-quoted argument. For example, a ViewModel action expression can assign:
vClientScriptExecute:='ThisIsMyFunction("hello man")'
The function must already be loaded in the browser, for example through AppWideAngularScriptIncludes.html. If you need multiple values, encode them in the single available argument.
For the required function format, a complete test example, and the matching rules, see Documentation:ClientScriptExecute.
Integrate JavaScript callbacks with the current ViewModel
External JavaScript callbacks sometimes occur outside AngularJS code that already has a scope reference. In that case, you can obtain the current local ViewModel representation from #viewmodelWrapper and assign a ViewModel property.
var vmroot = angular.element('#viewmodelWrapper').controller().$scope.ViewModelRoot;
vmroot.MyViewModelColumn = somevalueFromACallBack;
MDriven Turnkey detects the changed property and handles signaling to the server and UI binding. Add defensive checks when the controller might not yet be available.
An alternative is to assign the result to a UI input already bound to the ViewModel column and dispatch its change event. This lets AngularJS process the update as a user interaction.
For defensive code, change-event integration, and running code after the AngularJS page has loaded, see Documentation:Finding angular scope from javascript.
Style AngularJS-rendered pages
The AngularJS application starts at #flexLayoutWrapper. Server-generated HTML is injected and bound within #contentWrapper, while the ViewModel area is under #viewmodelWrapper and #viewmodelSection.
Turnkey adds the ViewModel name as a CSS class high in the page hierarchy. You can therefore target one ViewModel without changing other views. For example, this rule hides the sidebar only when the ViewModel is named WorkBoard:
.WorkBoard #sidebar { visibility: hidden; }
Controls also receive CSS classes based on their control type, and controls without labels receive the NoLabel class. Use these classes to make targeted styling rules rather than relying on fragile page structure assumptions.
See Documentation:Layout and CSS for the complete DOM and stylesheet structure.
Use third-party AngularJS modules
When you add an AngularJS module that must provide directives to Turnkey, load its script before AngularJS compiles and add the module to MDrivenAngularAppModule. This is necessary because modules normally cannot be loaded after the main application module.
For example, the TinyMCE integration adds the ui.tinymce module to the Turnkey AngularJS application module and then uses a ui-tinymce directive in an override. Follow the component-specific instructions rather than copying that integration for unrelated editors.
See Documentation:TinyMCE editor for the TinyMCE example and required module-registration pattern.
