This chapter will guide you through the process of implementing basic functionality using the Genie JavaScript SDK. You will implement a login page, show an application menu driven by the process map in the server application, and hook up a data entry form to an activity and its associated fields and methods.
Creating the Client Configuration JavaScript File
To configure some of the functionality of the SDK, you're target project will need to define a config object in JavaScript, which we’ll detail here:
- Add a new JavaScript file to the project under the Scripts folder, named config.js.
- Add the following code to the file, which includes the various options you can configure (and some example values):
window.genie = window.genie || {}; genie.config = { appendColonToLabels: false, appSite: 'MySite', authenticationMode: 'Alternate', backButton: false, formmappingFormat: '[p]', homePage: 'Home', implementationId: '', keepActivitiesOpenForSession: true, loginPage: 'Login', maintenancePage: 'Maintenance', messageBundlePath: 'assets/', onMaintenance: false, showAllMessages: false, timeFormat: 12, urlBlobs: 'http://xxx.com/downloads/blobs/', urlPrefix: 'https://localhost/GenieService/GenieService.svc/restishssl/', urlProxy: '/ESAProxy.ashx', useBundle: true, xmlNamespace: 'http://www.saasplications.com/GenieService' };
- Replace the values of the options marked in bold with the correct values for the server application that you are connecting to. Be sure to point the urlPrefix to the restishssl binding on the ESA web service.
- Add a script reference pointing to this new config.js file, along with the other references that you added to the _Layout.cshtml file (it should be before all the Genie JavaScript SDK references):
<script type="text/javascript" src="~/Scripts/config.js"></script>
Creating the Form Mapping File
Form mapping files are used to map activities on the server to pages on the client. Therefore, if the server issues an activity request, the Genie JavaScript SDK will know which page to navigate to in response. Let’s create a form mapping file now:
- Add a new XML file to your project, named FormMapping.xml.
- Add the following XML to the file. Note that you will need to replace the attribute values in square brackets with an activity name and style that will map to an existing activity/style combination in your server application.
<activities> <activity form="Home" default="true"/> <activity form="DataEntry" name="[activityname]" style="[activitystyle]" /> <activity form="SummaryList" name="[activityname]" style="[activitystyle]" /> </activities>
As you add new pages to your application, you will need to ensure that you add a corresponding activity element for it in this file.
Note: Adding a default="true" attribute to an activity element will result in that activity automatically being navigated to after a successful login.
Creating a Login Page
Now we can finally start building out application. Let’s implement a simple login page, which will contain User Name and Password fields (with corresponding labels obtained from the server), a Log In button, and a message control.
- Open the Login.cshtml view that you created earlier under the Views folder.
- Add the following HTML to the bottom of the existing HTML in the view:
<div bind="login"> <div id="username"> <label>User Name:</label> <input /> </div> <div id="password"> <label>Password:</label> <input type="password" /> </div> <div> <button type='submit'>Log In</button> </div> <div bind="messages"></div> </div>
- Now run your project. Enter a random user name and password into the fields, and click the Log In button. A message should appear below the login form, indicating that access was denied.
- Now try entering a valid user name and password combination to access your server application, and click the Log In button. The server should validate the credentials, and the browser will navigate to the Home page (because it has the default="true" attribute assigned to its corresponding activity element in the form mapping file).
The way that this works is that the SDK looks for elements in the page with the bind="login" attribute. If it finds one, then it will look for the username, password, and submit elements, and handle them accordingly. You’ll note this bind attribute pops up regularly (it also appeared in this example for the message control). This is how the SDK knows what elements it should watch and interact with.
Note: After the user has logged in and is using the application, if the user’s session is lost (cleaned up, etc), then a pop up window will appear (invoked by the SDK) asking them to log in again.
Displaying the Process Map as a Menu Bar
Let’s display a menu at the top of the page, based upon the contents of the process map sent by the server, and the form mapping file.
- Open the _Layout.cshtml view, and add the following HTML directly after the opening body tag:
<div id='menuMainContainer'> <ul id='menuContainer' bind='menu'></ul> </div>
- Now run your project. After you log in, you should see a set of bullet point hyperlinks at the top of the page. The menu is rendered as an unordered list, which you can style to suit your needs. Note how the hyperlinks point to the pages we defined earlier, allowing you to navigate through the application.
Note: You’ll find that the process map now renders on the login screen. To prevent this behaviour, usually your login page will use a different master layout to that of all other pages, which doesn’t include this control.
Creating a Summary List
Let’s implement a view that displays a list of items. Once we have that, we’ll customise it to allow you to drill down upon an item in the list.
Displaying Tabular Data
- Open the SummaryList.cshtml view that we previously created.
- The first thing we need to do is to define an activity container. This will be a div that has attributes that the SDK will look for. Add the following HTML to the end of the view:
<div bind="activity" activityname="[activityname]" activitystyle=" [activitystyle] "> </div>
- Replace the attribute values in square brackets with the values corresponding to an activity in your server application.
- Now that we have an activity container, you can add a “data control” to it. This is a table which has the bind="data" attribute on it, like so:
<div bind="activity" activityname="[activityname]" activitystyle="[activitystyle]">
<table id="mySummaryList" bind="data" populatemethod="[methodname]"></table>
</div>
The SDK will see this, call the method on the activity specified by the populatemethod attribute, and populate the table with data retrieved from the server.
- Run the project, log in, and navigate to this view using the menu on the Home page. Data from the server should appear in a tabular form.
Customising the List Using Templates
You can customise the rendering of the list using underscore templates. Detailing the use of underscore templates is beyond the scope of this document, but some good sources of information include:
Using this templating approach, you can completely change how the list is rendered. This may include customising what columns are displayed in a table, or completely restructuring how the data is laid out. Let’s implement a template now.
- When you implement templating, you will first need to decide whether the data will be rendered in a tabular format (using an HTML table), or in a “freeform” format. If you decide to render it in a tabular format, you will need to create a table element for your data control. Otherwise, to take complete control over how the data is rendered, create the element as a div. For the purpose of this example, we’ll create a table:
<table id="mySummaryList" populatemethod="listMyCookingClasses" bind="data"></table>
- The next step is to define your templates. There are two templates you can define – a header template, and an item template. Let’s define the header template first. This template will be defined using a script tag (as per the requirements of Underscore’s templating engine). You can tell the data control what the id of the template is by setting its headertemplatename attribute. Alternatively, without this attribute, the SDK will look for a template with an id consisting of the dataid that you gave the “data control” element, suffixed with “HeaderTemplate”. For example:
<script type="text/template" id="mySummaryListHeaderTemplate">
<thead>
<tr>
<th>Title</th>
<th>Date</th>
<th>Venue</th>
<th>Avail.</th>
<th>Status</th>
</tr>
</thead>
</script>
- Let’s now define the item template. This template will be defined using another script tag. You can tell the data control what the id of the template is by setting its itemtemplatename attribute. Alternatively, without this attribute, the SDK will look for a template with an id consisting of the dataid that you gave the “data control” element, suffixed with “ItemTemplate”. For example:
<script type="text/template" id="mySummaryListItemTemplate">
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</script>
- We now need to specify what data will be populated in the item template and where. An object named data containing the data retrieved from the server is passed to the templating engine, whose properties you can use to populate the template, like so:
<script type="text/template" id="mySummaryListItemTemplate">
<tr>
<td><%=data.Name%></td>
<td><%=data.EventDate%></td>
<td><%=data.Venue_Address%></td>
<td><%=data.AvailableSpaces%></td>
<td><%=data.Status%></td>
</tr>
</script>
You can access data deeper than just the top level, but you will need to use underscores in place of dot notation. Note how data.Venue_Address returns the value of the Address field on the Venue object.
- Run your project and navigate to the view. It should now be using the templates you created to render the list.
Enabling Drilling Down on an Item
You can turn on the ability to drill down on an item in a data control by setting the candrilldown attribute to true on the data control element. The first cell of each row will be turned into a hyperlink, which the user can click on to drill down on that row.
<table id="mySummaryList" populatemethod="listMyCookingClasses" bind="data" candrilldown="true"></table>
Note: The hyperlink will only be created for data controls that are rendered as a table, with no item templating applied. However, any anchor tags defined in item templates will be treated as drill down links automatically. You simply need to set the url of the anchor tag to be of the format pagename#id=x.
Setting the candrilldown attribute to true will create the hyperlink, but by default the drill down will remain on the same page. If, for example, you want the user to be able to drill down on an item to view more details about that item in a different page, you can set the drilldownpage attribute on the data control element to point to the page to be navigated to.
<table id="mySummaryList" populatemethod="listMyCookingClasses" bind="data" candrilldown="true" drilldownpage="details.html"></table>
Adding Support for Row Actions
A row action typically appears as a button or a hyperlink on each row of the data publication, which performs an action on that row. For example row actions may be things such as Edit, Delete, Add to Cart, and so on. These actions will map to methods on the server.
- The first step to implementing a row action is to template the rows in the data publication using item templates, as described in the section titled Customising the List Using Templates. Include a button in the template whose actionid attribute is set to “MyAction”.
<script type="text/template" id="mySummaryListItemTemplate">
<tr>
<td><%=data.Name%></td>
<td><%=data.EventDate%></td>
<td><%=data.Venue_Address%></td>
<td><%=data.AvailableSpaces%></td>
<td><%=data.Status%></td>
<td><button actionid="MyAction">Test Action</button></td>
</tr>
</script>
- The SDK now needs to know what to do when that button is clicked. This is actually configured in the form mapping file, within the form mapping for this activity/style combination. Add a gridview element, and give it an id attribute that maps directly to the attribute on the data publication that you’re configuring the row action on. Under this gridview element, add an actions element.
<activity form="SummaryList" name="[activityname]" style="[activitystyle]">
<gridview id="mySummaryList">
<actions>
</actions>
</gridview>
</activity>
- Within this actions element, you can now define the action. This will be an element named action, which has an id attribute that maps to the actionid attribute on the button in the item template. It also requires a methodName attribute, specifying the method to be called on the server when the button is clicked.
<activity form="SummaryList" name="[activityname]" style="[activitystyle]">
<gridview id="mySummaryList">
<actions>
<action id="MyAction" methodName="TestActionMethod" />
</actions>
</gridview>
</activity>
- Typically, you will need to also pass parameters to the method. For example, the ID of the row (i.e. the context for the action) will almost always need to be passed to the method, along with the context object. You can specify these parameters using param elements, like so:
<activity form="SummaryList" name="[activityname]" style="[activitystyle]">
<gridview id="mySummaryList">
<actions>
<action id="MyAction" methodName="TestActionMethod">
<param name="itemId" value="@contextId" />
<param name="contextObject" value="Item" />
</action>
</actions>
</gridview>
</activity>
These param elements are essentially just key/value pairs. The keys can be any value that the server method expects as its parameters. Note how the value of the itemId parameter is @contextId. This is a special replacement variable. When the method call is made to the server, this value will be replaced with the row ID.
- Now when you click the button against a row, the method defined for the action will be called on the server, and the parameters you’ve defined for the action will be passed to the method.
Note: If you want to pass the value of an input element to the method as a parameter, you can use the @userInput special replacement variable as the value of a parameter. When the action is invoked, the SDK will look for an input in the item/row whose name is of the format <rowid>_userinput_<paramname>.
Adding Support for Context Menus
Rather than invoking a method on the server when a button is clicked (as per actions), you may wish to get and display a context menu instead. To do so, follow the same method outlined in the section titled Adding Support for Row Actions, but instead of specifying a methodName attribute, specify a contextMenu attribute instead. For example:
<activity form="SummaryList" name="[activityname]" style="[activitystyle]">
<gridview id="mySummaryList">
<actions>
<action id="MyAction" contextMenu="xxx.Item">
<param name="itemId" value="@contextId" />
<param name="contextObject" value="Item" />
</action>
</actions>
</gridview>
</activity>
Enabling Editable Data Grids
Nothing needs to be done to enable editable data grids. When a data publication is received from the server that is marked as being editable, the default template will automatically insert input boxes in editable cells.
Note: If you are templating the data publication control, it’s essential that your input elements have a data-columnid attribute with the column ID that the input element corresponds to as its value in order for any value changes to be sent back to the server. <- Does not work properly currently. Should be by column name.
Creating a Data Entry Form
Let’s create a data entry form that displays data from the server, allows you to edit it, and saves those changes back to the server.
Configuring the Activity Container
You learnt how to configure an activity container in the previous section. Do the same again here for the data entry form, mapping it to an activity/style combination in the server application:
<div bind="activity" activityname="[activityname]" activitystyle="[activitystyle]">
</div>
Implementing a Message Control
You learnt how to configure message control back when implementing the login view. Do the same again here for the data entry form.
Note: You can put the message control either inside the activity container div, or outside of it. If it’s within the activity container div, then it will only display messages from that activity. When placed outside, it will show messages from all the activities on the page (including popup windows, etc).
<div bind="messages"></div>
You’ll note that the message control renders as an unordered list. You can use CSS styles to render it according to your needs.
Binding a Data Entry Field to a Field on the Server
There are a number of ways of binding an input field to a field on the server. One way is as follows:
<div bind="activity" activityname="[activityname]" activitystyle="[activitystyle]">
<input bind="field" fieldid="LastName" />
</div>
Note how we’re setting the bind attribute to a value of “field” (so the SDK will know that it’s an element to be mapped to a field on the server), and setting the fieldid attribute to the name of the field to map to. The SDK will display the value of that field in the input box.
Normally, however, you will also have a label associated with the field. The following HTML demonstrates binding both a field plus a label to a field on the server:
<div bind="activity" activityname="[activityname]" activitystyle="[activitystyle]">
<div bind="field" fieldid="FirstName">
<label></label>
<input />
</div>
</div>
As you can see, we’ve bound the parent div to the field on the server, and simply created label and input elements within the div. The SDK will automatically map the label of the field sent from the server to the label element, and map the value of the field to the input element.
It’s a similar story when you have a field that will display a number of values that the user can select from (such as a dropdown list), however you bind it as a datafield (instead of just a field), and you also need to specify the populate method or query:
<div bind="datafield" fieldid="Title" populatemethod="listTitles">
<select></select>
</div>
Binding a Button to a Method on the Server
To finish this data entry form we need a Save button. Add the following HTML to your view:
<button bind="method" method="Save">Save</button>
When you click this button, a message should appear in the message control you configured earlier stating that the save was successful.