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

Abou­t

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).

Con­cept pic­ture­s

Some pictures of examples using this framework. See also examples chapter at the end.
Image collection


De­pen­den­ci­es

The SMARTAPP JS framework is dependent on the following javascript libraries.

Re­sour­ce fi­les

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.htm­l examp­le fi­le

Select all
<!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.


Fol­der st­ruc­ture

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.

View­s

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.

Re­gis­teri­ng view­s


Init func­tio­n

See example of Views/Login/Login.js below:
Select all
(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);

Ren­der func­tio­n

See example of Views/Login.html below:
Select all
<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>


Dia­log­s

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.

Re­gis­teri­ng dia­logs (c­rea­teDi­alog(..­.)­)



Cont­rol­s

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):
Select all
<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:
Select all
// 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:
Select all
// 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:
Select all
// 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

Re­gis­teri­ng cont­rols (c­rea­teCo­nt­rol(..­.)­)



Na­viga­tio­n

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).

Ope­ning dia­logs with "­data-dlg­nav" att­ribu­te­s

Opens a view in a Bootstrap modal dialog box using the current theme.
Select all
<button data-dlgnav="SignUp">Open sign up page</button>

Clo­sing a mo­dal dia­log

Select all
<button type="button" class="close" data-dlgnav="{close}" aria-hidden="true">&times;</button>

Full mo­dal dia­log HTML examp­le

Select all
<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">&times;</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>


Na­viga­tio­n by co­de (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


The­mes

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 Bootst­ra­p 3 the­me mar­kup

Select all
 

Chan­ge the­me run­time in Ja­vasc­rip­t

Select all
 


smar­tapp­2 - Func­tion­s

The AppBase class is a jQuery plugin working as base class for applications.

smar­tapp­2(­ser­vice­Url, views­Fol­d­er, op­tions) - Const­ruc­t­or

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.
Select all
$.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;
};

API­Get(­co­nt­rol­ler, met­hod, da­ta, op­tions­)

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.

Do­ne(­retu­rn­Func, ...­)

(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
Select all
$app.APIGet("Account","Login", {login:loginvalue,password:passvalue}, {background:true}).done(function(result) {
    $.fn.Alert("Login result: " + result);
});


API­Post(­c­ont­rol­ler­, met­hod, da­ta, op­tions­)

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.

Do­ne(­retu­rn­Func­)

See description in APIGet.
Select all
$app.APIPost("Account","Login", {login:loginvalue,password:passvalue}, {background:true}).done(function(result) {
    $.fn.Alert("Login result: " + result);
});


er­ror(ms­g)


get­Cur­ren­tView(­)


hi­deLoa­di­ng­(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.
Select all
$app.HideLoading("Finished processing lists");

Is­Touch­De­vi­ce

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.)
Select all
//...
if (!$app.IsTouchDevice) $me.Name.focus(); // Only focus fields if not touch device
//...

log(msg­)


Load­View­(view­Nam­e)


Load­View­T­emp­late(­v­iew­Name­)


Open­Dia­lo­gView(­vi­ew­Name­)

Opens the specified view in a Boostrap dialog box.
Parameter name Type Description
viewName string Name of view to open.

Pop­Cur­ren­tView(f­x)

Internal function do not use.
Removes the current view from the view stack.

Ret­ryVie­wNa­me

Automatically retry failed network operations (APIGet and APIPost function calls).
Select all
$.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

Examp­le JS co­de for a "­Ret­ry view"

Select all
(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);


Re­gis­ter­Hi­sto­ry(ur­l, tit­le, for­ce, da­ta)

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
Select all
// 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)

Rep­lace­Hi­sto­ry(ur­l, tit­le, da­ta)

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
Select all
// 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")

Sho­wEr­ror­(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.

Show­Loa­di­ng­(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(­me­ssa­ge, [ok­Func]­)

Displays an alert box using the current Bootstrap components and theme.
Select all
$.fn.Alert("Hello there", function() {
// Commands here are run after OK is clicked
});

Chan­ge alert but­ton text­s

Select all
$.fn.AlertSettings = {
    OKBtn: "OK, fortsett!"
};


Con­firm(­m­es­sage, [ok­Func]­, [can­cel­Fu­nc]­)

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.
Select all
$.fn.Confirm("Are you sure?", function() {
// User clicked OK
}, function() {
// User clicked cancel
});

Chan­ge con­firm but­ton text­s

Select all
$.fn.ConfirmSettings = {
    OKBtn: "OK, fortsett!",
    CancelBtn: "Avbryt"
};



App­Base event­s

View event­s

Generic example of how to use view events:
Select all
$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.


smar­tapp­2com­pone­nt - Func­tion­s

The smartapp2component plugin is a jquery plugin initialized on all views, dialogs and controls.

Ini­tia­liz­e(­)

The standard method to override and call when your view is setup. Place hooks for event handlers etc. in this.
Select all
(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);

Show­Moda­l(­)

Shows the view in a modal bootstrap dialog. Internal function. Use the $app.OpenModalView and data-dlgnav attribute.

Clo­seMo­da­l(­)

No parameters.
Closes a view if it has been opened in modal mode. Either via a data-dlgnav attribute or a OpenModalView call.
Select all
$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
});

Load­Cont­r­ol(­cont­ro­lNa­me, $con­tai­ne­r)

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:
Select all
$view.LoadControl("MainMenu", $("#Menu"));

Ac­ces­sing child cont­rol­s

After child controls have been loaded you can get a reference to their jquery plugin with the following code:
Select all
$.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 */);
    };
//.... 
}


Examp­les

See the http://smartapp.ikx.no page for more information and examples.