SMARTAPP2.JS Reference Manual
Lightweight jQuery library for creating HTML5 apps handling navigation between multiple views and browser history.
(C) 2014 - 2021 by DOPS AS | www.dops.no
Updated: 02.11.2022 17:09 (C) 2014 - 2021 by DOPS AS | www.dops.no
About
This framework was created during development of combined Web and Phonegap Build Applications. Using the same code base for both platforms (web browser, iPhone, WinPhone and Android).
Concept pictures
Some pictures of examples using this framework. See also examples chapter at the end.
Image collection
Dependencies
The SMARTAPP JS framework is dependent on the following javascript libraries.
Resource files
Name | Type | Description |
---|---|---|
jQuery 1.10+ or 2.10+ | Javascript | Library that handles DOM queries and plugins. Get it from www.jquery.com |
jQuery UI | Javascript | Library that extends jQuery with extra effects. Get it from www.jqueryui.com. Only JS, CSS is optional. |
Bootstrap3 | Javascript + CSS | Bootstrap3 library that has functions such as show modal. Get it from www.getbootstrap.com Some Bootstrap3 theme for modal views and also a great styling framework both recommended and entangled in the framework. |
Notify.js | Javascript | Used to show some system notifications. Get it from https://github.com/jpillora/notifyjs |
An app.html example file
<!DOCTYPE html> <html> <head> <title>A simple app example</title> <!-- Frameworks --> <script src="Js/jquery-2.1.0.min.js"></script> <script src="Js/jquery-ui.min.js"></script> <script src="Js/bootstrap.js"></script> <script src="Js/notify.min.js"></script> <script src="Js/jquery.smartapp.js"></script> <link rel="stylesheet" href="Views/YourAppName.css" /> <meta name="viewport" content="width=device-width, user-scalable=0" /> <!-- Your application and view JS --> <script src="Views/Login/Login.js"></script> <script src="Views/Welcome/Welcome.js"></script> <script> $(function () { $("#AppContainer").YourAppName("http://yourwebapiurl/API", "Views", { debug: false }); }); </script> </head> <body> <div id="AppContainer" class="container"></div> </body> </html>
We recommend that you bundle and minimize all your JS files together. This increases load speed of your app and makes it easier to deploy.
Many JS minified files combined will also make it harder to reverse engineer your JS source code.
Many JS minified files combined will also make it harder to reverse engineer your JS source code.
Folder structure
This is the normal and recommended folder structure for smartapp.js apps.
Name | Type | Description |
---|---|---|
Fonts | Folder | This folder is optional, but may contain font files for bootstrap themes such as font awesome etc. NB! Be aware of Phonegap's case sensitive file system |
JS | Folder | Optional folder. Normally a folder to store different Javascript libraries such as jquery, jquery UI and other libraries. |
Themes | Folder | Optional folder. Place any resources for themes here. |
Views | Folder + Subfolders | Contains atleast a folder with a HTML and JS file for the view. May also contain a CSS file for the view. Create sub folders for each view in the view folder. Your app must have a folder with all the views placed in each folder. The folder name for each view must be the same as the class name for the view in the HTML file and filename. Se examples in screens below. |
\ | Root folder | Contains atleast one app.html and multiple test files. Often also contains a web version, you could call it web.html. Create CMD / BAT files for building app. |
Views
Views are the equivalent of pages. Each view is constructed with a render function (or template file) and an initialization function.
What view you are currently on is shown in the browser URL.
What view you are currently on is shown in the browser URL.
Registering views
Init function
See example of Views/Login/Login.js below:
(function ($) { "use strict"; // Add any neccessary contructor parameters in side the function () below. Example function (otherControl), this will $.fn.Login = function($app) { // <-- Constructor method this.ViewBase($app); // Inherit viewbase class var $me = this; // Define the jquery class this.Initialize = function() { this.$base.Initialize(); $app.Log($me); $me.find("form").submit(function () { $me.ClickLoginBtn(); return false; }); }; this.Show = function() { this.$base.Show(function () { if (!$app.IsTouchDevice) $me.Username.focus(); }); }; this.LoginSuccess = function (login, pass, themeCssFile) { // Bytt view $app.SetLogin(login, pass); if (themeCssFile) $("#Theme").attr("href", "Themes/" + themeCssFile); $app.ChangeView("BrowseFolder"); }; this.ClickLoginBtn = function() { $app.HideError(); var login = $me.Username.val(); var password = $me.Password.val(); $app.CheckLogin(login, password).done(function(result) { // Async API call if (!result.Message) { // Logg inn OK $me.LoginSuccess(login, result.hash, result.themeCssFile); } else { // Logg inn feilet $app.ShowError("Beklager, du oppga feil brukernavn eller passord!"); if (login == "") { $me.Username.select().focus(); } else { $me.Password.select().focus(); } setTimeout($me.Shake, 300); } }); }; this.Shake = function() { $me.find(".center").effect("sha ke"); }; this.Initialize(); return this; }; })(jQuery);
Render function
See example of Views/Login.html below:
<div class="view"> <div class="row"> <div class="col-lg-3 col-md-3 col-sm-2"></div> <div class="col-lg-5 col-md-6 col-sm-8 col-xs-12 center"> <header> <div class="smartdox-logo-dark"></div> </header> <form class="jumbotron"> <div class="input-group input-group-lg"> <div class="input-group-addon"> <span class="glyphicon glyphicon-user"></span> </div> <input id="Username" class="form-control" type="email" placeholder="Brukernavn" value="" data-control="Username" required="required" /> </div> <div class="spacer"></div> <div class="input-group input-group-lg"> <div class="input-group-addon"> <span class="glyphicon glyphicon-lock"></span> </div> <input id="Password" class="form-control" type="password" placeholder="Passord" value="" data-control="Password" required="required" /> </div> <div class="spacer"></div> <nav> <button class="btn btn-block btn-lg btn-primary" data-control="Login"><span class="glyphicon glyphicon-log-in"></span> Logg inn</button> </nav> <div class="spacer"></div> <nav class="btn-group btn-group-sm btn-group-justified"> <a class="btn btn-default" data-subnav="ResetInitialize"> <span class="hidden-xs">Glemt passord</span> <span class="visible-xs">Glemt pass</span> </a> <a class="btn btn-default" data-nav="SignUp">Ny konto</a> <a class="btn btn-default" data-nav="Demo">Demo</a> </nav> </form> <footer></footer> </div> <div class="col-lg-4 col-md-3 col-sm-2"></div> </div> </div>
Dialogs
Dialogs are different from views as they do not change the current page URL. They are loaded on a layer on top of the current view.
Hitting F5 will return back to the view behind. Hitting F5 on a view will just reload the view.
Hitting F5 will return back to the view behind. Hitting F5 on a view will just reload the view.
Registering dialogs (createDialog(...))
Controls
By using the "data-loadcontrol" attribute you can load common controls (defined in your views folder) as part of both views and controls. Controls can be nested within controls in many levels but can't recursively contain itself.
Example (Loads a MainMenu control into a view):
<div class="BrowseFolder view"> <div data-loadcontrol="MainMenu"></div> ... More stuff ... </div>
Both views and controls are placed in the "Views" folder. See screenshot below.
Children controls can also be loaded by code with the "LoadControl" method. See further information in the "ViewBase" functions.
Example - Reaching controls within loaded controls from a container / parent view:
// Example where a view has a loadcontrol="MainMenu" in the markup. // The MainMenu view has a tag with the attribute data-control="Logo" OR id="Logo" $me.MainMenu.Logo.text("Hello!");
Each "loadcontrol" view will be added to the views own properties and can easily be navigated to as the code above shows. You can also call functions you have defined in your controls from the parent view the same way:
// Example where a view has a loadcontrol="MainMenu" in the markup. // The MainMenu view has function defined called LoadMenu that takes 2 parameters $me.MainMenu.LoadMenu(user.Id, 123);
Reaching a container / parent view from a loaded control:
// Example where $me is view loaded through a loadcontrol="MainMenu". // Reaching the container / parent view: $me.ContainerView.Control1.text("test"); // Setting a control text $me.ContainerView.function1(1, "test"); // Calling a function
Registering controls (createControl(...))
Navigation
Navigation is recorded into a stack. You can replace the view, open a subview (aka detail view) or a dialog view (loaded on a BOOTSTRAP modal layer).
Opening dialogs with "data-dlgnav" attributes
Opens a view in a Bootstrap modal dialog box using the current theme.
<button data-dlgnav="SignUp">Open sign up page</button>
Closing a modal dialog
<button type="button" class="close" data-dlgnav="{close}" aria-hidden="true">×</button>
Full modal dialog HTML example
<div class="modal"> <div class="modal-dialog"> <div class="modal-content"> <section class="modal-header"> <button type="button" class="close" data-dlgnav="{close}" aria-hidden="true">×</button> <h4 data-control="Header">Recent calls</h4> </section> <table class="table-striped table table-hover" data-control="RecentTable" style="display:none"> <tbody data-control="RecentList"></tbody> </table> <section class="modal-body" data-control="NoCallsMsg" style="display:none"> At the moment you have no recent calls. </section> <section class="modal-footer" data-control="LoadMoreItems" style="display:none"> <button data-control="LoadMoreBtn" class="btn btn-block"> <span data-control="LoadMoreTxt">Show more</span> <span class="glyphicon glyphicon-arrow-down"></span> </button> </section> </div> </div> </div>
Navigation by code (JS)
Navigation can also be done by calling JS methods on the app object.
Function name | Description |
---|---|
changeView | Changes active view to the specified view. For more info on these function see the "AppBase functions" chapter |
openDialog | Opens a view in a Modal bootstrap dialog. |
history.back(); | Navigates back to the previous view. (browser default) |
For more info on these function see the "AppBase functions" chapter
Themes
You may invent and create your own theming system. Bootstrap 3 is a suggestion and no requirement. The following example shows how to add a theme to your app and change it runtime with JS code.
HTML Bootstrap 3 theme markup
Change theme runtime in Javascript
smartapp2 - Functions
The AppBase class is a jQuery plugin working as base class for applications.
smartapp2(serviceUrl, viewsFolder, options) - Constructor
The constructor signature for the AppBase class.
Name | Type | Description |
---|---|---|
serviceUrl | url | Web API base URL |
viewsFolder | string | Relative path from the app html file to the folder containing all the views for this app. Normally "Views" is value for this path. |
options | {object} | A settings object for your app. Normally extended with extra settings for your app. - SharedViewFolder (bool) - Whether the views are placed directly in the "Views" folder (true) or if false each view has a seperate folder inside the "Views" folder. |
$.fn.MyApp = function(serviceUrl, viewsFolder, options) { this.AppBase(serviceUrl, viewsFolder, options); // Inherit from AppBase var $me = this; this.Initialize = function () { this.$base.Initialize(); //............. } this.Initialize(); return this; };
APIGet(controller, method, data, options)
Calls the server with a HTTP GET command: http://{serviceurl}/{controller}/{method}?{data}
Name | Type | Description |
---|---|---|
controller | string | Web API controller name (see URL description above) |
method | string | Web API method name (see URL description above) |
data | {object} | List of parameters and values, sent as request variables. |
options | {object} | Options for the call: background: true or false (default false) - If true the loading overlay is not shown. noretry: true or false (default false) - If true it will not trigger a retry on error. nologin: true or false (default false) - If true the login dialog will not show on ResultCode = -999. |
Done(returnFunc, ...)
(This is the standard jQuery done function.)
Parameter name | Type | Description |
---|---|---|
returnFunc | function | Function to execute after the API call has returned succesfully. |
... | See the jQuery docs for more parameteres |
$app.APIGet("Account","Login", {login:loginvalue,password:passvalue}, {background:true}).done(function(result) { $.fn.Alert("Login result: " + result); });
APIPost(controller, method, data, options)
Calls the server with a HTTP POST command: http://{serviceurl}/{controller}/{method}?{data}
Parameter name | Type | Description |
---|---|---|
controller | string | Web API controller name (see URL description above) |
method | string | Web API method name (see URL description above) |
data | {object} | List of parameters and values, posted as FORM values. |
options | {object} | Options for the call: background: true or false (default false) - If true the loading overlay is not shown. noretry: true or false (default false) - If true it will not trigger a retry on error. nologin: true or false (default false) - If true the login dialog will not show on ResultCode = -999. |
Done(returnFunc)
See description in APIGet.
$app.APIPost("Account","Login", {login:loginvalue,password:passvalue}, {background:true}).done(function(result) { $.fn.Alert("Login result: " + result); });
error(msg)
getCurrentView()
hideLoading(e)
If you have called the ShowLoading method, be sure to always call the HideLoading() method afterwards.
Parameter name | Type | description |
---|---|---|
e | string | Debug description for console window. Not required. |
$app.HideLoading("Finished processing lists");
IsTouchDevice
Is true if the current device supports touch gestures / has a touch display.
(A public variable, not a function. Don't call with parentheses, see example below.)
(A public variable, not a function. Don't call with parentheses, see example below.)
//... if (!$app.IsTouchDevice) $me.Name.focus(); // Only focus fields if not touch device //...
log(msg)
LoadView(viewName)
LoadViewTemplate(viewName)
OpenDialogView(viewName)
Opens the specified view in a Boostrap dialog box.
Parameter name | Type | Description |
---|---|---|
viewName | string | Name of view to open. |
PopCurrentView(fx)
Internal function do not use.
Removes the current view from the view stack.
RetryViewName
Automatically retry failed network operations (APIGet and APIPost function calls).
$.fn.MobileApp = function (options) { // <-- Constructor method options = $.extend({}, $.fn.MobileApp.gvDefaults, options); this.AppBase(options.ServiceUrl, options.ViewsFolder, options); // Inherit from AppBase var $me = this; this.RetryViewName = "Retry"; //.... }
Image collection
Example JS code for a "Retry view"
(function ($) { "use strict"; // Add any neccessary contructor parameters in side the function () below. Example function (otherControl), this will $.fn.Retry = function ($app) { // <-- Constructor method this.ViewBase($app); // Inherit viewbase class var $me = this; var failedCalls = []; this.Initialize = function () { this.$base.Initialize(); $me.RetryBtn.click(function() { $app.RetryView = null; $app.GoBack(); for (var i = 0; i < failedCalls.length; i++) failedCalls[i](); }); }; this.AddFailedCall = function(call) { failedCalls.push(call); }; this.Initialize(); return this; }; })(jQuery);
RegisterHistory(url, title, force, data)
Adds a new record in the users browser navigation history. Function is used to make Back / Forward usage work in browsers.
Parameter | Type | Description |
---|---|---|
url | url | Absolute or relative URL for domain. |
title | string | Title to register in browser history |
force | bool | Optional - Set true to register in history eventhough it is a duplicate. |
data | struct | Optional data that can be retreived from the history record |
// The smartapp is initialized in a variable called $app // Adds a new record in the users browser history $app.RegisterHistory("#/Account/Register", "Register new account", false)
ReplaceHistory(url, title, data)
Replaces the current new record in the users browser navigation history. Function is used replace the current history item. So the user can't navigate back to the current url later.
Parameter | Type | Description |
---|---|---|
url | url | Absolute or relative URL for domain. |
title | string | Title to register in browser history |
data | struct | Optional data that can be retreived from the history record |
// The smartapp is initialized in a variable called $app // Prevents the user from navigating back to the previous URL: $app.ReplaceHistory("#/Account/Register+1", "Register new account")
ShowError(text)
Fades in all .error and [data-control=Error] elements in view and sets the inner text to the message specified.
Parameter name | Type | Description |
---|---|---|
text | string | Message text to show inside the error labels. |
ShowLoading(e)
This method is used to show the loading symbol.
Parameter name | Type | Description |
---|---|---|
e | string | Debug information about what is loading. Is only shown in browser debug console window. Not required. |
Alert(message, [okFunc])
Displays an alert box using the current Bootstrap components and theme.
$.fn.Alert("Hello there", function() { // Commands here are run after OK is clicked });
Change alert button texts
$.fn.AlertSettings = { OKBtn: "OK, fortsett!" };
Confirm(message, [okFunc], [cancelFunc])
Displays a confirm dialog using the current Bootstrap components and theme.
Parameter name | Type | Description |
---|---|---|
message | string | Required message to display in dialog box. |
okFunc | function | Optional function to call if the user clicks the OK button. |
cancelFunc | function | Optional function to call if the user clicks the Cancel button. |
$.fn.Confirm("Are you sure?", function() { // User clicked OK }, function() { // User clicked cancel });
Change confirm button texts
$.fn.ConfirmSettings = { OKBtn: "OK, fortsett!", CancelBtn: "Avbryt" };
AppBase events
View events
Generic example of how to use view events:
$app.on("viewshowed", function(e, $view, $app) { $view.delay(1000).removeClass("slide"); });
- e - javascript event object
- $view - jquery object to container element for view
- $app - jquery object to container element for app
Event name | Description |
---|---|
viewclosing | Triggered when view has started closing. Will start animation and clean up code. |
viewclosed | Triggered after view has finished closing. After animation and clean up code. |
viewrestored | Triggered after view has been restored. |
viewshowing | Triggered when view has started showing. When animation starts. |
viewshowed | Fire after a view has been made visible and animation has finished. |
viewinit | Triggered when a view has been initialized. |
viewsuspended | Is triggered after a view has been suspended. |
smartapp2component - Functions
The smartapp2component plugin is a jquery plugin initialized on all views, dialogs and controls.
Initialize()
The standard method to override and call when your view is setup. Place hooks for event handlers etc. in this.
(function ($) { "use strict"; $.fn.Retry = function ($app) { // <-- Constructor method this.ViewBase($app); this.ViewBase($app); // Inherit the smartapp ViewBase class var $me = this; this.Initialize = function () { this.$base.Initialize(); // Initialize all your event handlers for this view here $me.RetryBtn.click(function() { // Example event handler $app.GoBack(); }); }; this.Initialize(); return this; }; })(jQuery);
ShowModal()
Shows the view in a modal bootstrap dialog. Internal function. Use the $app.OpenModalView and data-dlgnav attribute.
CloseModal()
No parameters.
Closes a view if it has been opened in modal mode. Either via a data-dlgnav attribute or a OpenModalView call.
Closes a view if it has been opened in modal mode. Either via a data-dlgnav attribute or a OpenModalView call.
$tr.on("click", function () { var $p = $app.GetCurrentView(); // Gets the current view behind the modal view var num = $(this).attr("data-number"); // Gets the selected number $p.SetDialNumber(num); // Calls a function in the view behind the modal view to update a value there $me.CloseModal(); // Closes the modal view });
LoadControl(controlName, $container)
Loads a control defined in the views folder into a the specified target container.
Parameter name | Type | Description |
---|---|---|
controlName | string | The name of the control to load. This control must be defined in the views folder with both a jQuery class and HTML markup file (like a view). |
$container | jquery object | The target container to place the loaded control. |
Example JS code:
$view.LoadControl("MainMenu", $("#Menu"));
Accessing child controls
After child controls have been loaded you can get a reference to their jquery plugin with the following code:
$.fn.ExampleView = function ($app) { // <-- Constructor method this.ViewBase($app); // Inherit viewbase class var $me = this; // Example code: this.Refresh = function() { var $c = $me.ChildControls[0]; // Here is a reference to the initialized plugin for control no. 1. Iterate through or count the reference index in your source files. // You can call any defined public methods on it like this: $c.ExampleMethod(var1, var2 /* etc */); }; //.... }
Examples
See the http://smartapp.ikx.no page for more information and examples.