78

Click here to load reader

AD102 - Break out of the Box

Embed Size (px)

Citation preview

Page 1: AD102 - Break out of the Box

AD 102 – Break out of the boxIntegrate existing Domino data with modern websites

Karl-Henry MartinssonDeep South Insurance

Page 2: AD102 - Break out of the Box

Swede living in Dallas

Sr. Applications Developer, Deep South Insurance

Life-long geek

Programming since 1982

Ex-Microsoft (1988-90)

Ex-journalist (1993-1997, freelance 1998-2011)

Web developer since 1994

Notes/Domino developer since 1996

IBM Champion 2014 and 2015

http://blog.texasswede.com

I AM…

Page 3: AD102 - Break out of the Box

Old infrastructure

Company unwilling to upgrade

Requesting new web applications

Wanted modern look, mobile

Bootstrap and jQuery to the rescue:

My story

Page 4: AD102 - Break out of the Box

Agenda

“Integrate existing Domino data with modern websites”

Why integrate?

Why jQuery and not XPages?

Separate the workload

Client – Javascript/jQuery, Ajax, JSON

Server – Lotusscript

Improve the UI – Bootstrap

Demos

All sample code will be available for download athttp://blog.texasswede.com/MWLUG

Page 5: AD102 - Break out of the Box

Limited or no migration options

Desire to modernize

Code re-use

Take advantage of the power of Domino

No one will know you are using a Domino backend

Use existing skillset

Learn valuable new skills

Why integrate?

Page 6: AD102 - Break out of the Box

Infrastructure not supporting XPages

No XPages skills

Tight deadline – no time to learn

More control

Plugin availability

Why not use Xpages?

Page 7: AD102 - Break out of the Box

Separate design and code

Focus expertise on their respective areas

Use established front-end technologies

Back-end focus on business logic and data

Collaboration is important!

Separate the workload

Page 8: AD102 - Break out of the Box

Javascript/jQuery

Ajax/JSON

HTML and CSS

Bootstrap

Ajax call

JSON data.NSF

Client – modern web browser

Page 9: AD102 - Break out of the Box

Lotusscript Agents

NSF database

Existing business logic

Can use existing classes/script libraries

Works on Domino since R5

Update highly recommended!

Server – IBM Domino

Page 10: AD102 - Break out of the Box

Where does everything live?

HTML pages, CSS files and Javascript

• Notes page element

• Notes resources

• CDN (.js and .css)

• Server file system – in Data/Domino/HTML

• Another web server

Lotusscript agents

• .NSF on Domino server

Page 11: AD102 - Break out of the Box

Development tools

Domino Designer

Browser with Dev Tools

Firefox with Firebug plugin

Internet Explorer Developer Tools (built-in)

Chrome Developer Tools (built-in)

Online resources

• jsonlint.com

• Stack Overflow

• Google Search

Page 12: AD102 - Break out of the Box

Asynchronous Javascript And XML

Asynchronous = call processed in background

Result is passed back and then processed

XML used first, JSON now more common

Easier to parse JSON in Javascript

Using few lines of jQuery code

Ajax

Page 13: AD102 - Break out of the Box

jQuery

Javascript library

Free

Very popular

Powerful – save development time

Easy access to web page elements (DOM)

Online resources

Page 14: AD102 - Break out of the Box

$.ajax({

url: '/websites/example.nsf/ajax_GetUserDetails?OpenAgent',

data: {name: “Karl-Henry Martinsson”},

cache: false

}).done(function(data) {

// Process returned data here

}).fail(function(e) {

// Process failed call here

});

or

$.ajax({

url: '/websites/example.nsf/ajax_GetUserDetails?OpenAgent',

data: {name: userName},

cache: false

}).success(function(data) {

// Process returned data here

});

Can be more complex – .done(), .fail() and .always()

Arguments passed as JSON

cache: false – “cache buster”

Calling Ajax using jQuery

Page 15: AD102 - Break out of the Box

JavaScript Object Notation

Describe data as Javascript objects

Preferred to XML in web applications

• Less “chatty” (less bandwidth)

• Very easy to access values directly in Javascript

Any data types, including other objects

Array of objects

JSON

Page 16: AD102 - Break out of the Box

?ReadViewEntries&OutputFormat=JSON

• Available in Domino 7.0.2+

• Can be hard to parse

Formula in Notes view

• http://www.eknori.de/2011-07-23/formula-magic/

Lotusscript agent

• Generate your own JSON

• Test at JSONLint.com

• Use JSON classes

o My Class.JSON

o JSON Lotusscript Classes by Troy Reimer (OpenNTF.org)

Generate JSON on Domino

Page 17: AD102 - Break out of the Box

XPages agent (SSJS XAgent)

• Domino 8.5.2 and XPages knowledge

• Better performance than Lotusscript

• http://www.wissel.net/blog/d6plinks/shwl-7mgfbn

REST Services control from Extension Library

• Domino 8.5.2 and ExtLib on server

Generate JSON on Domino – Xpages Style

Page 18: AD102 - Break out of the Box

First button will update specified element with text

• Static text - stored in the Javascript source code

Second button will trigger an Ajax call to server

• Server agent returns plain text

• No parsing of name-value pairs

• No database lookups or other server interaction

• Returned text can contain HTML

• Javascript updates specified element with returned text

Google as CDN for jQuery

jQuery also hosted by Microsoft and others

Demo 1 – Text/HTML response

Page 19: AD102 - Break out of the Box

<!DOCTYPE HTML ><html>

<head>

<title>Demo 1 - MWLUG 2015</title>

<script src='//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js'></script>

</head>

<body>

<div id="content"></div>

<button id="btnDisplayStaticContent">Show content from page</button>

<button id="btnDisplayServerContent">Load content from server</button>

<script>

$(document).ready(function () {

// Update content div with content from this page

$('#btnDisplayStaticContent').click( function() {

var content = "This is some static content from this page";

$('#content').html(content);

});

// Update content div with content from server

$('#btnDisplayServerContent').click( function() {

$.ajax({

url: 'ajax_Demo1?OpenAgent',

cache: false

}).done(function(data) {

$('#content').html(data);

});

});

});

</script>

</body>

</html>

Demo 1 – Web page

Page 20: AD102 - Break out of the Box

Option Public

Option Declare

Sub Initialize

'*** MIME Header to tell browser what kind of data we will return

Print "content-type: text/html"

'*** Content (HTML) to return to calling browser

Print "This is content loaded from the server.<br>"

Print "<em>This</em> text is returned as <strong>HTML</strong>.<br>"

End Sub

Agent settings

Demo 1 – Lotusscript agent

Page 21: AD102 - Break out of the Box
Page 22: AD102 - Break out of the Box

Read text field, pass to server

Return and display computed text

Simple URL class

• http://blog.texasswede.com/free-code-class-to-read-url-name-value-pairs/

Using @URLDecode

Demo 2 – Text/HTML response

Page 23: AD102 - Break out of the Box

<!DOCTYPE HTML ><html>

<head>

<title>Demo 2 - MWLUG 2015</title>

<script src='//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js'></script>

</head>

<body>

Name: <input type="text" id="userName"></input>

<br>

<br>

<button id="btnDisplayServerContent">Load content from server</button>

<br>

<br>

<div id="content"></div>

<script>

$(document).ready(function () {

// Update content div with dynamic content

$('#btnDisplayServerContent').click( function() {

// Get username from input field

var userName = $('#userName').val();

// Make Ajax call to server, passing user name as argument

$.ajax({

url: 'ajax_Demo2?OpenAgent',

data: {name: userName},

cache: false

}).done(function(data) {

$('#content').html(data);

});

});

});

</script>

</body>

</html>

Demo 2 – Web page

Page 24: AD102 - Break out of the Box

Option Public

Option Declare

Use "Class.URL"

Sub Initialize

'--- Local Notes classes used in agent

Dim db As NotesDatabase

Dim view As NotesView

Dim doc As NotesDocument

'--- Custom classes

Dim url As URLData

'*** Create new URLData object

Set url = New URLData()

'*** MIME Header to tell browser what kind of data we will return

Print "content-type: text/html"

'*** Check reqired values for this agent

If url.IsValue("name")=False Then

Print "Missing argument 'name'."

Exit Sub

End If

'*** Process name argument

If url.GetValue("name")="" Then

Print "'Name' is empty."

Else

Print "Hello, " + url.GetValue("name") + "!"

End If

End Sub

Demo 2 – Lotusscript agent

Page 25: AD102 - Break out of the Box

Class URLData

p_urldata List As String

Public Sub New()

Dim session As New NotesSession

Dim webform As NotesDocument

Dim tmp As String

Dim tmparr As Variant

Dim tmparg As Variant

Dim i As Integer

'*** Get document context (in-memory NotesDocument)

Set webform = session.DocumentContext

'*** Get HTTP GET argument(s) after ?OpenAgent

tmp = FullTrim(StrRight(webform.GetItemValue("Query_String")(0),“OpenAgent&"))

If tmp = "" Then

'*** Get HTTP POST argument(s)

tmp = FullTrim(webform.GetItemValue("Request_Content")(0)))

End If

'*** Separate name-value pairs into array

tmparr = Split(tmp,"&")

'*** Loop through array, split each name-value/argument

For i = LBound(tmparr) To UBound(tmparr)

tmparg = Split(tmparr(i),"=")

p_urldata(LCase(tmparg(0))) = Decode(tmparg(1))

Next

End Sub

Demo 2 – URL Class

Page 26: AD102 - Break out of the Box

%REM

Function GetValue

%END REM

Public Function GetValue(argname As String) As String

If IsValue(argname) Then

GetValue = p_urldata(LCase(argname))

Else

GetValue = ""

End If

End Function

%REM

Function IsValue

%END REM

Public Function IsValue(argname As String) As Boolean

IsValue = IsElement(p_urldata(LCase(argname)))

End Function

'*** Private functions for this class

Private Function Decode(txt As String) As String

Dim tmp As Variant

Dim tmptxt As String

tmptxt = Replace(txt,"+"," ")

tmp = Evaluate(|@URLDecode("Domino";"| & tmptxt & |")|)

Decode = tmp(0)

End Function

End Class

Demo 2 – URL Class

Page 27: AD102 - Break out of the Box
Page 28: AD102 - Break out of the Box

Status - success or error

Multiple values

Error message

Case sensitive!

Demo 3 – Return JSON data

Page 29: AD102 - Break out of the Box

Demo 3 – Lotusscript JSON class

Simplify JSON creation

Add values (strings) and fix quotes within value

Add boolean values (true/false)

Set status (success or error)

Send MIME type and JSON string back

Page 30: AD102 - Break out of the Box

Demo 3 – Lotusscript agent

Option Public

Option Declare

Use "Class.JSON"

Sub Initialize

'--- Custom class

Dim json As JSONData

'*** Create new JSONData object

Set json = New JSONData()

'*** Generate JSON to return

Call json.SetValue("PhoneNumber", "817-555-1212")

Call json.SetValue("Email", "[email protected]")

Call json.SetValue("Name", "Karl-Henry Martinsson")

json.success = True

Call json.SendToBrowser()

End Sub

Page 31: AD102 - Break out of the Box

<body>

<br>

<button id="btnDisplayServerContent">Load user info</button>

<br>

<br>

<div id="userInfo">

<div>

User Name: <span id="userName"></span>

</div>

<div>

Phone number: <span id="userPhoneNumber"></span>

</div>

<div>

Email Address: <span id="userEmail"></span>

</div>

</div>

<div id="errorInfo"></div>

</body>

Use span elements to hold values

id attribute used to identify element

Must be unique on page

Demo 3 – Return JSON data

Page 32: AD102 - Break out of the Box

$.ajax({

url: 'ajax_Demo3?OpenAgent',

cache: false

}).success(function(data) {

if(data.status=="success") {

// Populate the different fields and display the section

$('#userPhoneNumber').html(data.PhoneNumber);

$('#userEmail').html(data.Email);

$('#userName').html(data.Name);

$("#userInfo").fadeIn(1500);

} else {

// Display error message passed from server

$("#errorInfo").html(data.errormsg);

$("#errorInfo").fadeIn(1000);

}

});

Very little code needed

Put values into specified elements

Case is important!

Demo 3 – Return JSON data

Page 33: AD102 - Break out of the Box
Page 34: AD102 - Break out of the Box

Open source front-end framework

CSS + some jQuery

Responsive

Themes, color schemes and plugins

CDN or local copy

3rd party resources and plugins

Twitter Bootstrap

Page 35: AD102 - Break out of the Box

Example of web application using Bootstrap

Page 36: AD102 - Break out of the Box

The password reset application pictured above is a free download. You can get it at http://blog.texasswede.com/free-software-password-reset-for-notesdomino/

Another Bootstrap web application

Page 37: AD102 - Break out of the Box

Rapid development

Responsive

Cross-browser

Plenty of resources

Actively being developed

Benefits of using Bootstrap

Page 38: AD102 - Break out of the Box

Only supporting the latest browsers

Major changes between v2 and v3

Version specific plugins

Some plugins not themeable

Potential issues with Bootstrap

Page 39: AD102 - Break out of the Box

Viewport meta tag – control scaling

<meta name="viewport" content="width=device-width, initial-scale=1">

<title>Demo 4 - MWLUG 2015</title>

<script src='//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js'></script>

<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>

<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">

<link href="demo4.css" rel="stylesheet">

Using Bootstrap

Page 40: AD102 - Break out of the Box

Minified Bootstrap from BootstrapCDN.com

// - works with and without SSL

• Will not work on local webpages, page must be on a server

Local CSS located after Bootstrap CSS

Using Bootstrap<meta name="viewport" content="width=device-width, initial-scale=1">

<title>Demo 4 - MWLUG 2015</title>

<script src='//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js'></script>

<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>

<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">

<link href="demo4.css" rel="stylesheet">

Page 41: AD102 - Break out of the Box

Link to Bootstrap and local CSS file

Local CSS used for minor tweaks

Bootstrap markup in HTML

Two columns

• Button in left column

• Result in right column

Responsive - columns will stack

Demo 4 – Adding Bootstrap

Page 42: AD102 - Break out of the Box

HTML <body>

<div class="container">

<div class="row">

<div class="col-md-6">

<button class="btn btn-primary" id="btnDisplayServerContent">Load user info</button>

</div>

<div id="userInfo" class="well col-md-6">

<label>User Name:</label> <div class="jsonData" id="userName"></div>

<label>Phone number:</label> <div class="jsonData" id="userPhoneNumber"></div>

<label>Email Address:</label> <div class="jsonData" id="userEmail"></div>

</div>

</div>

<div class="alert alert-danger" id="errorInfo"></div>

</div>

HTML <head>

<script src='//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js'></script>

<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>

<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">

<link href="demo4.css" rel="stylesheet">

Demo 4 – Adding Bootstrap

Page 43: AD102 - Break out of the Box

demo4.css

container {

margin-top: 20px;

}

label {

font-size: 10pt;

margin-bottom: 0px;

margin-top: 10px;

}

label:first-child {

margin-top: 0px;

}

.jsonData {

font-size: 12pt;

}

Add 20 pixel margin to top of page

Make label text smaller, remove bottom margin and add top margin, except on the first label

Set the text size of JSON data returned to 12pt

Demo 4 – Adding Bootstrap

Page 44: AD102 - Break out of the Box

Demo 4 – Adding BootstrapjQuery

// Hide error section and user info section

$("#errorInfo").hide();

$("#userInfo").hide();

// Update content div with dynamic content

$('#btnDisplayServerContent').click( function() {

// Make Ajax call to server

$.ajax({

url: 'ajax_Demo3?OpenAgent',

cache: false

}).success(function(data) {

if(data.status=="success") {

// Populate the different fields and display the section

$('#userPhoneNumber').html(data.PhoneNumber);

$('#userEmail').html(data.Email);

$('#userName').html(data.Name);

$("#userInfo").fadeIn(1500);

} else {

// Display error message passed from server

$("#errorInfo").html(data.errormsg);

$("#errorInfo").fadeIn(1000);

}

});

});

Page 45: AD102 - Break out of the Box
Page 46: AD102 - Break out of the Box

data-json=”JSON_data_element”

data- prefix is ”standard”

.each()

Read value and get corresponding JSON

• $(this) – current element in jQuery

• data[”Name”] will return the JSON value “Name”

Demo 5 – Process JSON

Page 47: AD102 - Break out of the Box

jQuery

// For each element with class jsonData

$(".jsonData").each( function() {

// Get the field name from the custom attribute data-json

// and set the content of the current element to

// the corresponding JSON value

jsonfield = $(this).attr("data-json");

$(this).html(data[jsonfield]);

});

HTML

<div id="userInfo" class="well col-md-6">

<label>User Name:</label> <div class="jsonData" id=user"Name" data-json="Name"></div>

<label>Phone number:</label> <div class="jsonData" id="userPhoneNumber" data-json="PhoneNumber"></div>

<label>Email Address:</label> <div class="jsonData" id="userEmail" data-json="Email"></div>

</div>

$("div[data-json]").each( function() {

Demo 5 – Process JSON

Page 48: AD102 - Break out of the Box
Page 49: AD102 - Break out of the Box

JSON name = id of element to put data in

Less HTML markup

Still very little code, and very flexible

Add # in front of element name!

jQuery$.each(data, function(id, item) {

elementName = "#" + id;

elementValue = data[id];

$(elementName).html(elementValue);

});

HTML<label>User Name:</label> <div id="Name"></div>

<label>Phone number:</label> <div id="PhoneNumber"></div>

<label>Email Address:</label> <div id="Email"></div>

Demo 6 – Process JSON (another way)

Page 50: AD102 - Break out of the Box
Page 51: AD102 - Break out of the Box

Demo 7 – Bootstrap plugin

Plugin by @wenzhixin

Get it at http://bootstrap-table.wenzhixin.net.cn/

CDN hosted version at CloudFlare.com

Minimal HTML markup

Javascript mainly to define columns and settings

Page 52: AD102 - Break out of the Box

HTML<div id="tableToolbar">

<div class="toolbarText">My Contacts</div>

</div>

<table id="ContactTable"></table>

jQuery (partial)$("#ContactTable").bootstrapTable({

url: 'ajax_Demo7_GetAllContacts?OpenAgent',

search: true,

showRefresh: true,

pagination: true,

pageSize: 25,

classes: "table-condensed table-hover table-striped tableContent",

toolbar: "#tableToolbar",

columns: [{

field: 'FirstName',

title: 'First Name',

width: 80,

sortable: true

}, {

field: 'LastName',

title: 'Last Name',

width: 90,

sortable: true

}, {

Demo 7 – Bootstrap plugin

Page 53: AD102 - Break out of the Box

Demo 7 – Bootstrap Table pluginLotusscript code (partial)

'*** Get all documents in view to process

Set db = session.CurrentDatabase

Set view = db.GetView("(LookupContactsByLastName)")

Set col = view.AllEntries

'*** Start of JSON string

jsonString = “”

'*** Loop through all entries and build JSON to return

Set entry = col.GetFirstEntry

Do Until entry Is Nothing

'*** Build JSON for each entry and add to string

Set json = New JSONData()

Call json.SetValue("LastName", CStr(entry.ColumnValues(0)))

Call json.SetValue("FirstName", CStr(entry.ColumnValues(1)))

Call json.SetValue("Company", CStr(entry.ColumnValues(2)))

Call json.SetValue("Address", CStr(entry.ColumnValues(3)))

Call json.SetValue("City", CStr(entry.ColumnValues(4)))

Call json.SetValue("State", CStr(entry.ColumnValues(5)))

Call json.SetValue("ZIP", CStr(entry.ColumnValues(6)))

Call json.SetValue("DocUNID", CStr(entry.ColumnValues(9)))

'*** Add new JSON to existing JSON string

jsonString = jsonString + json.GetJSON() + "," + Chr$(13)

Set entry = col.GetNextEntry(entry)

Loop

'*** Remove the trailing comma and line break if we have data

If Len(jsonString) > 4 then

jsonString = Left$(jsonString,Len(jsonString)-2)

End If

'*** Add brackets for array

jsonString = "[ " + Chr$(13) + jsonString + Chr$(13) + “ ]“

'*** MIME Header to tell browser what kind of data we will send

Print "content-type: application/json"

'*** Send JSON back to browser

Print jsonString

Page 54: AD102 - Break out of the Box

Demo 7 – Bootstrap Table plugin

Page 55: AD102 - Break out of the Box
Page 56: AD102 - Break out of the Box

Demo 8 – Simple contact database

Table of contacts – use bootstrap-table plugin

Click on user to display more details about them

Buttons

• Edit

• Save

• New

• Delete

Add refresh/reload of table when updated

Page 57: AD102 - Break out of the Box

Demo 8 – Simple contact database

Lotusscript agents needed

• ajax_Demo8_GetAllContacts (reused from Demo 7)

• ajax_Demo8_GetContactDetails

• ajax_Demo8_SaveContact

o If DocUNID is blank, create new contact

o Otherwise update existing contact

• ajax_Demo8_DeleteContact

HTML page changes

• Add section for contact details

• Detect click on row to display details

• Add buttons and jQuery code

Page 58: AD102 - Break out of the Box

Demo 8 – Simple contact database

HTML – buttons<button class="btn btn-sm btn-primary" id="btnNewContact">New</button>

<button class="btn btn-sm btn-primary" id="btnEditContact">Edit</button>

<button class="btn btn-sm btn-success" id="btnSaveContact">Save</button>

<button class="btn btn-sm btn-danger pull-right" id="btnDeleteContact">Delete</button>

jQuery – Edit and New buttons//*** Button actions

$("#btnEditContact").on("click", function(e) {

editContact();

});

$("#btnNewContact").on("click", function() {

editContact();

// Empty all input fields

$('input[data-notesfield]').each( function() {

$(this).val("");

});

// Empty hidden DocUNID field

$("#docUNID").attr("data-UNID","");

// Hide ‘Delete’ button

$("#btnDeleteContact").hide();

});

Page 59: AD102 - Break out of the Box

jQuery – Save button$("#btnSaveContact").on("click", function() {

$("#btnSaveContact").hide();

var json = new Object();

// Store field values in JSON object

var docunid = $("#docUNID").attr("data-UNID");

json["DocUNID"] = docunid;

$('input[data-notesfield]').each( function() {

var id = $(this).attr("id");

var notesfield = $(this).attr("data-notesfield");

json[notesfield] = $(this).val();

});

// Perform a call to the server to save values

$.ajax({

url: "ajax_Demo8_SaveContact?OpenAgent",

type: "POST",

data: json

}).done(function(data) {

if (data.status=="error") {

alert("Failure: " + data.msg);

} else if (data.status=="success") {

setReadMode(); // Convert INPUT back to DIV

$("#contactTable").bootstrapTable("refresh", {silent: true});

}).fail( function(e) {

alert("Failure!","Failed to save contact. Error: " + e.errorThrown);

});

$("#btnEditContact").show();

});

Demo 8 – Simple contact database

Page 60: AD102 - Break out of the Box

jQuery – Delete button$("#btnDeleteContact").on("click", function(e) {

var docunid = $("#docUNID").attr("data-UNID");

$.ajax({

url: "ajax_Demo8_DeleteContact?OpenAgent",

type: "POST",

data: {DocUNID: docunid }

}).done(function(data) {

if (data.status=="error") {

alert("Failure: " + data.msg);

} else if (data.status=="success") {

$("#contactTable").bootstrapTable("refresh", {silent: true});

// Empty all input fields

$('input[data-notesfield]').each( function() {

$(this).val("");

});

// Empty all div with Notes data

$('div[data-notesfield]').each( function() {

$(this).html("");

});

// Empty hidden DocUNID storage

$("#docUNID").attr("data-UNID","")

$("#btnDeleteContact").hide();

$("#btnEditContact").hide();

}

}).fail( function(e) {

alert("Failure!","Failed to delete contact. Error: " + e.errorThrown);

});

});

Demo 8 – Simple contact database

Page 61: AD102 - Break out of the Box

jQuery – Detect click on table row// Detect click on row in table

$("#contactTable").on('click-row.bs.table', function (e, row, $element) {

// Convert INPUT fields back to DIV just in case

setReadMode();

// Hide save button if visible

$("#btnSaveContact").hide();

// Get DocUNID value in table and load corresponding values from server

var unid = row.DocUNID;

displayDetails(unid);

});

Demo 8 – Simple contact database

Page 62: AD102 - Break out of the Box

jQuery – Load contact details from server and display on page// Get contact details from Domino server and populate fields

// using the DocUIND value as lookup key

function displayDetails(docunid) {

$.ajax({

url: 'ajax_Demo8_GetContactDetails?OpenAgent',

data: {DocUNID: docunid},

cache: false

}).success(function(data) {

if(data.status=="success") {

// For each element with data-notesfield attribute

$('div[data-notesfield]').each( function() {

notesfield = $(this).attr("data-notesfield");

if (data[notesfield]!=null) {

fieldvalue = data[notesfield];

$(this).html(fieldvalue);

}

});

// Store DocUNID in enmpty div for later use

$("#docUNID").attr("data-UNID",data.DocUNID);

// Display previously hidden editand delete buttons

$("#btnEditContact").show();

$("#btnDeleteContact").show();

}

});

}

Demo 8 – Simple contact database

Page 63: AD102 - Break out of the Box

jQuery – Change between DIV and INPUT // Put contact details into edit mode by changing DIV to INPUT

function editContact() {

$("#btnEditContact").hide();

// Change all div with Notes data to input

$('div[data-notesfield]').each( function() {

var id = $(this).attr("id");

var notesfield = $(this).attr("data-notesfield");

var input = "<input class='jsonData inputNotesField form-control input-sm' id='" + id

input = input + "' data-notesfield='" + notesfield + "' value='" + $(this).html() + "'></input>";

$(this).replaceWith(input)

});

$("#btnSaveContact").show();

$("#btnEditContact").hide();

}

// Put contact details into read mode by changing INPUT to DIV

function setReadMode() {

$('input[data-notesfield]').each( function() {

var id = $(this).attr("id");

var notesfield = $(this).attr("data-notesfield");

var div = "<div class='jsonData displayNotesField' id='" + id

div = div + "' data-notesfield='" + notesfield + "'>" + $(this).val() + "</div>";

$(this).replaceWith(div)

});

}

Demo 8 – Simple contact database

Page 64: AD102 - Break out of the Box
Page 65: AD102 - Break out of the Box

Similar to Demo 8, but using FullCalendar plugin

Get it at http://fullcalendar.io

Lotusscript agents

• ajax_Demo9_GetAllEvents

• Returning events between specific days

• Calendar automatically sends start and end date

• ajax_Demo8_GetEventDetails

• ajax_Demo8_UpdateEvent

• Triggered when moving event or changing duration

• Arguments: DocUNID, start date and end date

Demo 9 – Calendar using Domino data

Page 66: AD102 - Break out of the Box

Calendar points to JSON of event data

Demo 9 – Calendar using Domino data

jQuery – Display calendar and load JSON of event data from server var eventSource = 'ajax_demo9_GetAllEvents?OpenAgent';

$("#notesCalendar").fullCalendar({

events: eventSource

});

Calendar adds start and end dates to URL

Agent returns events within date range

Page 67: AD102 - Break out of the Box

Demo 9 – Calendar using Domino dataLotusscript agent ajax_Demo9_GetAllEvents (partial code)

'*** Local variables to hold arguments passed from URL

Dim startdate As String

Dim enddate As String

'*** Other local variables

Dim jsontext As String

'*** Create new URLData object

Set url = New URLData()

'*** Create new JSONData object

Set json = New JSONData()

'*** Check start date and convert from ISO to US date format

If url.IsValue("start") Then

startdate = ISOtoUS(url.GetValue("start"))

Else

startdate = "01/01/1980"

End If

'*** Check end date and convert to US date format

If url.IsValue("end") Then

enddate = ISOtoUS(url.GetValue("end"))

Else

enddate = "12/31/2199"

End If

Page 68: AD102 - Break out of the Box

Demo 9 – Calendar using Domino dataLotusscript agent ajax_Demo9_GetAllEvents (partial code)

'*** Send MIME header to browser

Print "content-type: application/json"

jsontext = ""

Set db = session.CurrentDatabase

Set view = db.GetView("Events")

Set col = view.AllEntries

Set entry = col.GetFirstEntry()

Do Until entry Is Nothing

If CDat(entry.ColumnValues(0))>=CDat(startdate) Then

If CDat(entry.ColumnValues(0))<=CDat(enddate) Then

Call json.SetValue("id", CStr(entry.ColumnValues(5)))

Call json.SetValue("title",CStr(entry.ColumnValues(3)))

Call json.SetValue("start", Format$(CDat(entry.ColumnValues(0)),"mm/dd/yyyy hh:nn ampm"))

Call json.SetValue("end", Format$(entry.ColumnValues(1),"mm/dd/yyyy hh:nn ampm"))

'*** Make the entry editable in calendar (allow changing date/time)

Call json.SetBoolean("editable", True)

End If

End If

jsontext = jsontext + json.GetJSON() + "," + Chr$(13)

Set entry = col.GetNextEntry(entry)

Loop

If Len(jsontext)>4 Then

jsontext = Left$(jsontext,Len(jsontext)-2)

End If

Print "[ " + jsontext + " ]"

Page 69: AD102 - Break out of the Box

Demo 9 – Calendar using Domino dataFullCalendar plugin – Trigger code on click, resize and drop (move)…

eventClick: function(calEvent, jsEvent, view) {

var unid = calEvent.id;

displayEventDetails(unid);

},

eventResize: function(event, delta, revertFunc) {

if (!confirm(event.title + " will now end at " + event.end.format("h:mm a") + "\nAre you sure?")) {

revertFunc();

} else {

var unid = event.id;

updateEvent(unid,event.start.format("MM/DD/YYYY hh:mm a"),event.end.format("MM/DD/YYYY hh:mm a"));

displayEventDetails(unid)

}

},

eventDrop: function(event, delta, revertFunc) {

var prompt = event.title + "<br>was moved to " + event.start.format("MM/DD/YYYY")

prompt = prompt + " at " + event.start.format("h:mm a");

bootbox.confirm(prompt + "<br>Are you sure you want to do that?", function(result) {

if(result==true) {

var unid = event.id;

updateEvent(unid,event.start.format("MM/DD/YYYY hh:mm a"),event.end.format("MM/DD/YYYY hh:mm a"));

displayEventDetails(unid)

} else {

revertFunc();

}

});

}

Page 70: AD102 - Break out of the Box

Demo 9 – Calendar using Domino dataJavascript code – Update event on serverfunction updateEvent(docunid,startDT,endDT) {

var json = new Object();

json["DocUNID"] = docunid;

json["EventStart"] = startDT;

json["EventEnd"] = endDT;

// Perform a call to the server to save new event date/time

$.ajax({

url: "ajax_Demo9_UpdateEvent?OpenAgent",

type: "POST",

data: json

}).done(function(data) {

if (data.status=="error") {

bootstrapAlert(data.msg,"danger");

} else if (data.status=="success") {

bootstrapAlert(data.msg,"success");

}

}).fail( function(e) {

bootstrapAlert("Failed to create progress note. Error: " + e.errorThrown,"danger");

});

}

Page 71: AD102 - Break out of the Box

Demo 9 – Calendar using Domino dataLotusscript agent ajax_Demo9_UpdateEvent (partial code)'--- Local variables

Dim startDate As String

Dim endDate As String

'*** Get document

Set db = session.CurrentDatabase

If url.GetValue("DocUNID")<>"" Then

Set doc = db.GetDocumentByUNID(url.GetValue("DocUNID"))

End If

'*** Check that we found a document, otherwise exit

If doc Is Nothing Then

Set json = New JSONData()

json.success = False

json.SetErrorMsg("Failed to locate document '" & url.GetValue("DocUNID"))

Call json.SendToBrowser()

Exit Sub

End If

Call doc.ReplaceItemValue("EventStart",CDat(url.GetValue("EventStart")))

Call doc.ReplaceItemValue("EventEnd",CDat(url.GetValue("EventEnd")))

Call doc.Save(True,False)

Set json = New JSONData()

json.success = True

json.SetMsg("Updated '" & doc.GetItemValue("EventTitle")(0) & "' with new date/time")

Call json.SendToBrowser()

Page 72: AD102 - Break out of the Box
Page 73: AD102 - Break out of the Box

HTML

<label>Axis II</label>

<div class="MagicSuggest" id="DSM4Axis2" name="DSM4Axis2"></div>

jQuery

// Axis II

var DSM4Axis2 = $('#DSM4Axis2').magicSuggest({

name: 'DSM4Axis2',

resultAsString: true,

Width: 630,

MaxDropHeight: 200,

style: 'height: 28px;',

displayField: 'description',

valueField: 'id',

sortOrder: 'description',

emptyText: 'Select value for Axis II (DSM-IV)',

data: '/database.nsf/ajax_GetDSM4Codes?OpenAgent&Axis=2'

});

List of medical codes in Domino• Consumed in a drop-down

• MagicSuggest plugin: http://nicolasbize.com/magicsuggest/

JSON – Real Life Example

Page 74: AD102 - Break out of the Box

JSON generated by agent ajax_GetDSM4Codes[

{"id":"301","description":"Paranoid Personality Disorder"},

{"id":"301.13","description":"Cyclothymic Disorder"},

{"id":"301.2", "description":"Schizoid Personality Disorder"},

{"id":"301.22","description":"Schizotypal Personality Disorder"},

{"id":"301.4","description":"Obsessive-Compulsive Personality Disorder"},

{"id":"301.5","description":"Histrionic Personality Disorder"},

{"id":"301.6","description":"Dependent Personality Disorder"},

{"id":"301.7","description":"Antisocial Personality Disorder"},

{"id":"301.81","description":"Narcissistic Personality Disorder"},

{"id":"301.82","description":"Avoidant Personality Disorder"},

{"id":"301.83","description":"Borderline Personality Disorder"},

{"id":"301.9","description":"Personality Disorder NOS"}

]MagicSuggest rendered in browser:

JSON – Real Life Example

Page 75: AD102 - Break out of the Box

Summary

Ajax/JSON efficient to access Domino data

CRUD using server based agents (Lotusscript)

jQuery and Bootstrap to speed up development

Plugins available for free

Some new easy-to-learn knowledge required

Skills beneficial on other platforms as well

Page 76: AD102 - Break out of the Box

Questions?

Page 77: AD102 - Break out of the Box

Thank you!

Presentation & Sample Code:

http://blog.texasswede.com/MWLUG

Page 78: AD102 - Break out of the Box

http://www.texasswede.com/Demo_MWLUG_2015.nsf/demo1

http://www.texasswede.com/Demo_MWLUG_2015.nsf/demo2

http://www.texasswede.com/Demo_MWLUG_2015.nsf/demo3

http://www.texasswede.com/Demo_MWLUG_2015.nsf/demo4

http://www.texasswede.com/Demo_MWLUG_2015.nsf/demo5

http://www.texasswede.com/Demo_MWLUG_2015.nsf/demo6

http://www.texasswede.com/Demo_MWLUG_2015.nsf/demo7

http://www.texasswede.com/Demo_MWLUG_2015.nsf/demo8

http://www.texasswede.com/Demo_MWLUG_2015.nsf/demo9

Demo Links

Presentation & Sample Databasehttp://blog.texasswede.com/MWLUG