Angular


 
Genelet’s JSON APIs follow a unique URL format. One of the benifits is to write easily the web frontend i.e. View (in MVC) as a single-page HTML5 using Javascript. We demo below our special way to do it in Angular 1.2. You should make better solution using your favored JS Framework. Just FYI, if you run the help command, the samples files will be generated onto disk.

 

URI Mapping

Genelet’s APIs use the format:
http://WEBSITE/HANDLER/role/json/component?action=string&query…     (1)

Your HTML5 page URLs should put role, component, action and query in hash:
http://WEBSITE/#/role/component?action=string&query…                            (2)

 

File Layout

The layout of the HTML5 files is organized in the document root as:

/index.html
/init.js
/genelet.js
/role1/header1.html
/role1/footer1.html
/role1/component1/action1.html
/role1/component1/action2.html
/role1/component2/action1.html
/role1/component2/action2.html

/role2/header2.html
/role2/footer2.html
/role2/login2.html
/role2/component1/action1.html
/role2/component1/action2.html
/role2/component2/action1.html
/role2/component2/action2.html

Here is index.html:

<!DOCTYPE html>
 <html lang="en">
 <head>
 <meta charset="utf-8">
 <meta name="fragment" content="!" />
 <meta http-equiv="X-UA-Compatible" content="IE=edge">
 <meta name="viewport" content="width=device-width, initial-scale=1">
 <title>MYPROJECT</title>
 <script src="/bootstrap/js/jquery.min.js"></script>
 <script src="/bootstrap/js/bootstrap.min.js"></script>
 <script src="/bootstrap/js/angular.min.js"></script>
 <script src="/bootstrap/js/spin.min.js"></script>
 <script src="/init.js"></script>
 <script src="/genelet.js"></script>
 <link href="/bootstrap/css/bootstrap.min.css" rel="stylesheet">
 <style>
 body { padding-top: 50px; }
 .starter-template { padding: 40px 15px; text-align: center; }
 .nav, .pagination, .carousel, .panel-title a { cursor: pointer; }
 </style>
 </head>
 <body ng-app="app_wavelet" ng-controller="body_wavelet">
 
 <ng-include src="partial_header"></ng-include>
 
 <div class="container">
 <span id="spinner"></span>
 <ng-include src="partial"></ng-include>
 </div>
 
 <ng-include src="partial_footer"></ng-include>
 
 </body>
 </html>

Here we use Bootstrap as the CSS framework and the spin plugin spin.js for page-loading indicator.

Here is init.js that defines a global variable called GOTO:

var GOTO = {
script: Your API_SCRIPT_NAME,
role: Default ROLE_NAME if not in URL,
component: Default COMPONENT_NAME if not in URL,
action: Default ACTION_NAME if not in URL,
type: "html",
json: "json",
header: "header",
footer: "footer",
login: "login",
modals: [MODAL_NAME1, MODAL_NAME2, ...]
}

The program genelet.js (download here) will call the serve API in (1) and retrieve data to fill in the Angular template, at every time when the URL is refreshed.  The JSON data are saved in variable called names. Since verbs edit, insert and update usually contain only one item in names‘ array, we copy it to a separately variable called single. Developer can use names and single to display any dynamical content according to the HTML5 templates.

For each role, you can attach its own header and footer. For testing purpose you may leave them as two empty files.

In the above example,  we assume role1 is a public role so there is no login file associated. And role2 is a protected role whose visitors have to login first using a login form. Here is example login2.html:

<h3>{{ names.errorstr }}</h3>
<FORM name=admin_login ng-init="data.role='admin';data.tag='json';data.direct=1" ng-submit="$parent.login('admin','db',data,{role:'admin', component:'site',action:'topics'})">
<pre>
Username: <INPUT TYPE="TEXT" ng-model="data.login" />
Password: <INPUT TYPE="PASSWORD" ng-model="data.passwd" />
<INPUT TYPE="SUBMIT" value=" Log In " />
</pre>
</FORM>

 

Anchor Links

Anchor link uses the format:

<a href=”” ng-click=”go(role, component, action, query, landing)”></a>     (3)

Clicking on the link will result in the browser to navigate, depending on how landing is passed in:

  • landing is null, it simulates the traditional anchor, i.e. jump to new page:
    http://WEBSITE/#/role/component?action=string&query
  • landing is string, it retrieves the API data only. No anchor jump nor page refresh. The returned data are saved in object string, instead of overriding the existing data array names. A variety of the function called optional_go is also available. If the name object string is already existing, the API call will simply be ignored. The use case of this landing is when you want two or more API data on one page.
  • landing == {operator: stringid_name: string} where operator string is one of insert, update or delete. No anchor jump. This landing is used to change the existing lists on spot, without refreshing the page. The optional variable  id_name defines the primary key in delete or update. The use case is when you want to insert, delete or update dynamic data without refreshing the current page.
  • landing == {role: stringcomponent: string, action: string, query: object}. After running the original API, it will redirect to the new URL while running the following, second API:
    /#/landing{role}/landing{component}?action=string&landing{query}
    For example, after a user updates his credit card, you lead her back to the original payment page. You need two API calls for this click: (1) update her credit card and (2) refresh the payment page, presumably with the updated card information on it.

 

POST a Form

To make a POST request, e.g. to submit a form, we use:

send(role, component, action, query, landing)

All the parameters and use cases are the same as the above GET anchor.

 

Login

While the login process is also a POST, we’d like an easier API:

login(role, provider, query,  landing)

where provider is the name of the authentication agent. landing is {role: string, component: string, action: string, query: object}. After the successful login to role, the URL will be redirected to what defined in landing.

 

Leave a Reply

Your email address will not be published.