IBM Connect 2014
XPages: Still No Experience Necessary
Step by Step see how to create an XPages application. Create a help desk ticket app, including CRUD (Create, Read, Update, Delete)
3. Agenda
âȘ Who We Are
âȘ What We Are Building
âȘ What Are XPages?
âȘ Creating the Application
âȘ Refining the Application
4. Who We Are
âȘ Kathy Brown
â Consultant at PSC Group, LLC
âȘ Blogger at www.runningnotes.net
âȘ IBM Champion
âȘ Author
â SocialBizUg.orgâs Notes Dev Tips newsletter
â The View
âȘ Speaker at Lotusphere and user group events around the world
âȘ Twitter addict
â @RunningKathy and 14 other accounts
âȘ Geek, Nerd Girl, and Loud Laugher
5. Who We Are
âȘ Paul T. Calhoun
â Senior Software Engineer â Panagenda (paul.calhoun@panagenda.com)
â Owner â NetNotes Solutions Unlimited, Inc. (pcalhoun@nnsu.com)
âȘ IBM Champion
â 2013
â 2014
âȘ Certified
â Administrator
â Developer
âȘ Speaker, Mentor, Trainer
â Connect, LUGS
âȘ Grandfather
â Ask to see my pictures !!!
6. Agenda
âȘ Who We Are
âȘ What We Are Building
âȘ What Are XPages?
âȘ Creating the Application
âȘ Refining the Application
7. What We Are Building
âȘ An XPages Help Desk Application
â User can enter tickets
â Resources can be assigned
â Comments can be added
âȘ What we will need
â Basic CRUD
âą Create, Read, Update, Delete
âȘ What we will use
â XPages components
âą OneUI
âą Core Controls
âą Extension Library
âą Custom Controls
âą and more!
8. Agenda
âȘ Who We Are
âȘ What We Are Building
âȘ What Are XPages?
âȘ Creating the Application
âȘ Refining the Application
9. What are XPages?
âȘ Design Elements and tools for creating Web applications
âȘ Embraces standard languages
â HTML, XML, CSS, JavaScript, Java
âȘ Built on top of Java Server Faces (JSF)
â XPages is a front-end that Domino Developers can understand
âȘ Everything you code gets placed inside of Java Objects
â You never need to deal with those Java Objects though!
âȘ You do not NEED to know Java to build XPages apps
â But it will help and should be something to strive for
â Java in XPages is somewhat similar to LotusScript Custom Classes
10. What Does XPages Fix?
âȘ Separates UI from Data
â Allows multiple Data sources per Page
âą Data from ânâ views from different .nsfâs
â Easy access to data from other databases
âȘ Improves Data capabilities
â Allows @DbLookup from inside a view
âą Similar to a JOIN in relational DBâs.
â Can use Java Objects (Beans) as data sources
â Iterate your data anyway you want via âRepeat Controlâ
âȘ Runs inside Notes Client (XPiNC - XPages in Notes Client)
â Replicate your web applications
â Allows for consistent experience between Notes and Web Clients
11. âNewâ Design Elements
âȘ XPage
â Blank âcanvasâ to create presentation layer for data
â Similar to Notes Form
âą But not really as you can have none or multiple datasources
âȘ Custom Control
â Similar to Subform
âą But not really as you can have none or multiple datasources
âą Can be used more then once on a page
âą Can accept Parameters that you define later
âȘ Sever Side JavaScript
â Language of choice for the beginner
âȘ Themes
â Allow consistent look and feel across appliations
â oneUI and WebStandard are built in
â Create your own by extending oneUI and WebStandard
â Themes can be used to push CSS files to every page of your app
â Like a Global âUseâ statement
12. XPages: Scoped Variables
âȘ Scoped Variables
â In memory variables to store data
â No need to rely on cookies / URL parsing
âą but you still can if you want (but you wonât want to)
âȘ applicationScope
â Like a database profile document
â Available to all users
âȘ sessionScope
â Life of the user session
â Limited to the application it was declared in
âȘ viewScope
â Life of the current Page
âȘ requestScope
â Life of a single request
â Very short
13. Getting Started Building the App
âȘ The most recent version of the starter files will be available at http://runningnotes.net
âȘ Weâre using Domino and Designer 9.0.1
â Starting with version 9.0 the core Extension Library is included
âȘ Everything you see here should work on:
â Domino/Designer 8.5.x with Extension Library
â Domino/Designer 9.0.x
âą No update pack or Extension Library needed as itâs built in
14. Starter Files
âȘ We have a downloadable kit available to start
âȘ This kit contains :
â Starter database
â Finished Database
â Slides
â Script Snippets
âȘ Starter Database contains several forms and views, but no XPages code
âȘ Download the kit to your machine and extract the files
âȘ Copy the starter application to your Notes Data Directory
â usually something like c:program fileslotusnotesdata
15. Starter Database
âȘ Non-Xpage elements already added:
âȘ Forms
â form_comment
â form_resource
â form_ticket
â keywords
âȘ Views
â vwComments
â vwCommentsByKey
â vwKeywords
â vwTickets
â vwTicketsByStatus
âȘ Example Documents
â Some keyword documents
â Some ticket documents
16. Development Process Does Not Change with XPages
âȘ Itâs still a best practice to âdevelop locallyâ and âtest globallyâ using an .ntf design template.
âȘ For the purposes of this demo we will not use a template and weâll work directly on our local
server.
âȘ This is convenient when starting a database as weâll be doing a lot of testing as we go. So
this eliminates a lot of âRefresh Designâ steps.
âȘ Typically when an application reaches a certain stage of development it can be copied to
an .ntf file to become a true template.
17. Configuring Domino Designer for XPages Development
âȘ There are several things that can be configured that will make your XPage development
experience easier
âȘ The following are recommendations for setting properties in the Domino Designer BEFORE
you start developing
18
18. Configuring Domino Designer for XPages Development
âȘ Change your memory allocation
â Edit the jvm.properties file located in the client installation directory under
âą framework/rcp/deploy
19. Configuring Domino Designer for XPages Development
âȘ Edit with any text editor
â Xmx â Total amount of RAM for Designer AND Client
âą Set to at least 512m
âą Donât set equal to the amount of system RAM
â Xms â Starting Heap size
âą Set to at least 128m
âą Donât set equal to Xmx value
â Xmca â Memory block size
âą Set to at least 512k
âą Thanks a âkâ NOT A âmâ
âȘ Always set in multiple of â4â
âȘ Will not take effect until client is âš
restarted if it is running when edited
20. Configuring Domino Designer for XPages Development
âȘ Monitor Memory Used
âȘ In Designer Preferences
â Select General
â Check âShow heap statusâ
âȘ Even though this is a checkbox, it does not âš
ârememberâ the setting.
â It has to be checked each time you start âš
designer.
âȘ Heap status is displayed in the lower left hand âš
corner of the designer client.
â Monitor the amount of memory being used
â Click the trash can icon to trigger garbageâš
collection
21
21. Configuring Domino Designer for XPages Development
âȘ Set XML Editor formatting for viewing XPage source
âȘ In Designer preferences
â Select XML | XML Files | Editor
â Change Line width
â Check âSplit multiple attributes each on a new lineâ
â Check âClear all blank linesâ
âȘ Any new XPages source will adhere to these settings
âȘ Existing XPages can be âreformattedâ to adhere to theseâš
settings by using the keyboard shortcut
â <shift><ctrl><f>
22
24. Open the Starter application from Domino Designer
âȘ Make sure to choose Local - then find on your hard drive
â It should have been first copied to your Notes Data Directory
25. Working Sets
âȘ Working sets are ways in Designer to group and organize your applications.
â If using a working set you might see this screen. Choose Yes to add it.
â If youâre not using a working set it will just be added to your application list
âą Using Working Sets is a BEST PRACTICE !!!
26. Copying to Server
âȘ Right click on the starter file and copy it to your server if youâre using one
28. Results
âȘ You end up with 2 applications. The local and a COPY on the server.
â Since we did a file copy these will not replicate
â We will focus on the server for this demo - you can right-click and âRemoveâ local if you
want.
â Using the server is more convenient for rapid testing and allows security to work
29. Agenda
âȘ Who We Are
âȘ XPages
âȘ What We Are Building
âȘ What Are XPages?
âȘ Creating the Application
âȘ Refining the Application
30. Beginning to Code
âȘ Goals
â Set some application properties
â Create an overall layout for the web application
âą Will be reusable so any pages we add get the same look and feel
âą Add the ability to Login / Logout to the app
â Create a home page
â Test
31. Set the Theme and Default Error Handling
âȘ Application Configuration | Xsp Properties - General Tab - Set Application theme to:
â Choose Oneuiv2.1
â This makes base css and dojo JavaScript resources available
â Oneuiv2.1 is a theme provided by Domino and gives our application the âlook and feelâ
similar to mail, the teamroom, etc.
â Using Oneuiv2.1 means we do not have to individually style anything, although we can if
we want to (more on this later)
âȘ Select the âDisplay XPage runtime error pageâ
â This will provide more meaningfulâš
information is the XPage throws an error
32. Create the Layout for the Application
âȘ 2 Custom Controls
â 1 for the Main Layout
â 1 to hold a Navigation Bar on the left side
âȘ Extension Library controls required for this
â Many controls are added to the core product
â App Layout Control provides the overall look and feel
âą The App Layout Control can be added to each XPage for consistent navigation and
layout throughout the application
â Form Tables and Form Rows allow us to easily layout fields
â Tool Tips and Dialogboxes are available
â Many many more tools available
33. Create layout_Main
âȘ Create a custom control to become the main layout of the application
âȘ Custom controls - New Custom Control - âlayout_Mainâ
35. Should Look Like This
âȘ Green dots are areas for future custom controls
âȘ You can drag controls onto the green dots (targets)
âȘ Placing a control onto a target on the layout means the control will be used whenever the
layout is used
âȘ Leaving a target as a green dot means different controls may be used on different instances
of the layout
36. Enable Green Dot for Middle Column
âȘ Select the layout control by clicking on it. Then use properties tab to select.
37. Embrace the Source tab
âȘ Note by clicking the Middle Column that the
source has updated.
â This âcallbackâ allows Custom âš
Controls to be added later
â We click the Middle column âš
as that will be the placeholder for the pageâs
main content
â We do not click the left column âš
as weâll add the navigation menu âš
to the layout custom control itself. âš
This way it will be available to every page.
38. Create Ability to Login / Logout
âȘ Select the App layout control that you dropped on the page
âȘ Add Login and Logout Node
39. Remove the Label
âȘ This SHOULD make an Automatic Login AND Logout node
â But there is a bug, just the login gets created
â Workaround will be to create a manual logout node
âą Weâll do this in just a bit
â For now, just clear the label field
41. Login/Logout Workaround
âȘ In the Label field
â Click on the blue diamond and select âCompute ValueâŠâ
â Include the server-side javascript that will return the user name or anonymous
42. Display Current User
âȘ Server Side JavaScipt is used to create a NotesName object
âȘ If the current user is not âAnonymousâ we display a little welcome message
// Create Notes Name Object from the current effective user
var userName:NotesName = session.createName(session.getEffectiveUserName());
// If the user is not Anonymous then return a welcome message
if (userName.getCommon()!="Anonymous") {
return "Welcome, "+userName.getCommon()+"!";
}
43. Server Side JavaScript
âȘ If that was your first real exposure to Server Side JavaScript (SSJS), congratulations!
â That wasnât so bad, right?
âȘ A few things to note:
â Syntax is similar, but not the same as LotusScript
â Semicolons, you need them
â // is a comment, not â
â Assume EVERYTHING is case sensitive
âą Proper Capitalization is important
âą @Unique() will work, while @unique will not
â Oh! And you can use some @Formula (not all, but quite a lot)
âą Parentheses are important
44. Adding Logout Fix
âȘ Add a Basic Node and set the label to âLogoutâ
âȘ Add the SSJS code to the computed value with the following:
rendered property var uName = session.getEffectiveUserName();
if (uName == "Anonymous") {
return false;
} else {
return true;
}
href property return facesContext.getExternalContext().getRequest().getContextPath() +
"?Logout&redirectTo=" +
facesContext.getExternalContext().getRequest().getContextPath()
45. Home Page
âȘ Create a new XPage called âhome.xspâ
â Custom controls are never rendered directly to the browser. They must be placed on an
XPage.
46. Drag layout_Main Onto Page
âȘ Note the green dot is back. This is because we enabled the middle column earlier.
âȘ We will use this to add different controls to different pages.
47. Check the Source
âȘ Note: all that does is create a tag to represent the custom control
48. Drag a Panel onto the Green Dot
âȘ In Source mode this creates a facet tag. You can easily add content in here. This is the
âbodyâ of your web page
âȘ A panel is a container for other controls
49. Check the Source
âȘ In Source mode this creates a facet tag. You can easily add content in here. This is the
âbodyâ of your web page.
âȘ Content goes between the <xp:panel> tags
50. Add Some Text to Your Home Page
âȘ Gives us a place holder for later
âȘ You can use source or design - Save this page and close
51. Set the Launch - Go Back to Application Properties
On the launch tab, set Launch to âOpen
designated Xpageâ, XPage âhomeâ.
Donât forget to save and close this.
52. Testing Locally
âȘ If developing with a local application, then the XPage can be tested by launching the XPage
from the âPreview in Browserâ action
53
53. Testing on the Server
âȘ If developing with a server based application, then ensure the âSign agents or XPages to run
on behalf of the invokerâ has a GROUP name that includes the developer ID that saved/
signed the XPage and Custom Control design elements
â This setting not being configured properly is one of the top reasons XPages do not render
from a server !
54
54. Testing on a Server
âȘ If the signer of the XPage is configured properly in the Server Document, then the XPage can
be tested by launching the XPage from the âPreview in Browserâ action as well.
55
55. Configuring Additional Test Browsers
âȘ Additional test browsers can be configured in the Designer Preferences
56. Initial Home Page
âȘ Should look similar to this
âȘ Note the blue and black âš
banner bars on the top
â That styling is thanks âš
to our theme
âȘ Note the âLoginâ and âš
links on the bottom of âš
the page
â Those elements are âš
from the layout control
57. Summary
âȘ We have an Application in progress
âȘ We inherited some forms and views from the starter database
âȘ We setup our application properties
â We added a theme and set the default home page
âȘ Created a custom control for our application layout
âȘ Created a home page and added the layout control
âȘ Added a panel - which will render as an html <div> to the main body and added some content
âȘ Tested in the browser
58. Next Up
âȘ Create Custom Control for the Help Ticket
âȘ Create Custom Control to View tickets
âȘ Create a Custom Control for the Navigation menu list
59. Create Custom Control for Ticket
âȘ New Custom Control - Name it cc_Ticket
âȘ Note weâre using a prefix to separate controls for layout from other custom controls
60. Create Data Bindings
âȘ We want to bind this control to a document
â As mentioned earlier, data and UI have been separated
âą Data in the document, UI on the XPage
â Binding allows us to put them back together however we want
âą i.e. we can have multiple data sources on a single XPage
âȘ In properties Data Tab - Add - Domino Document
61. Create Data Binding ...
âȘ Select form_ticket and name the data source ticketDoc
â Unless there will be multiple data sources it is a BEST PRACTICE to leave the document
data source name as âdocument1â
62. Add Code to the beforePageLoad Event
âȘ This will allow us to pre-populate fields and scoped variables
â Click anywhere in the editor white space in the Design tab
â Click on the âEventsâ tab
â Select the beforePageLoad event in the left navigator
63. Add Code from Script Snippets
âȘ This code creates a unique key and Date for a new document
âȘ It also puts the key field into viewScope memory for later use
64. Hereâs How this Code Looks in Source
âȘ Note the tag and use of JavaScript inside the curly braces
â Comments describe the code
<xp:this.beforePageLoad><![CDATA[#{javascript:if (ticketDoc.isNewNote()) {
// If this is a new document - generate a unique key
var tempKey = session.evaluate("@Unique");
// Add the unique key to the document itself
ticketDoc.replaceItemValue("ticketKey", tempKey );
// Add the key to viewScope so we can use it later as needed
viewScope.put("vsTicketKey", tempKey);
// Set the ticket Date to current Date/Time
ticketDoc.setValue("ticketDate", @Now());
} else {
// This is not a new document so retrieve the key and put in viewScope
viewScope.put("vsTicketKey", ticketDoc.getItemValueString("ticketKey"))
}}]]></xp:this.beforePageLoad>
65. Populating Fields the Quick Way
âȘ We could go to the Data tab and drag the fields in. This would create a table (weâll see an
example of this later). But for a better UI we will use more controls from Extension Library.
66. Adding Fields to Your Page
âȘ Drag the FormTable control to your control
âȘ FormTable contains formRow and can also optionally contain formColumn tags
âȘ This gives you a nice CSS styled layout of your labels and fields
â Without needing to know or change CSS (although you can change it if you want to)
67. Update Label Position
âȘ From the Form Tableâs All Properties panel, change the labelPosition to âleftâ
âȘ This will allow you to move all labels later if desired with one click (rather than one for each
label)
â Note other properties like formTitle
68. Add Title to Form Table
âȘ Select the Form Table tab
âȘ Add the formDescription and formTitle
69. Drag Form Layout Row onto Form Table Bodyâs Green Dot
âȘ This creates one row that will contain a label and a field, automatically
70. Adjust Label Placement on the Row
âȘ From the Form Layout Row, change the labelPosition to âinheritâ
âȘ Changing the label position will now be one click on the Form Table (the one we just set to
âleftâ)
74. Check the Source
âȘ Note: This is a formRow inside a formTable tag. We are about to add multiple rows
âȘ To get multiple fields on a row there is also a formColumn tag which allows you to add more
columns. This app does not use Columns.
<xe:formTable
id="formTable1"
labelPosition="left">
<xe:formRow
id="formRow1"
labelPosition="inherit" label="Ticket ID">
<xp:text
escape="true"
id="computedField1"
value="#{ticketDoc.ticketKey}">
</xp:text>
</xe:formRow>
</xe:formTable>
75. Add the Ticket Date Field
âȘ We will continue filling out the fields for the ticket form. Same principle but not all will use the
computed field control. Most we want editable.
âȘ Next add the date field by starting to paste this under the last </xe:formRow> tag in source
âȘ This is the row for âticketDateâ
<xe:formRow
id="formRow2â label="Date"
labelPosition="inherit">
<xp:text escape="true"
id="computedField2"
value="#{ticketDoc.ticketDate}">
<xp:this.converter>
<xp:convertDateTime
type="date"
dateStyle="short">
</xp:convertDateTime>
</xp:this.converter>
</xp:text>
</xe:formRow>
76. Changing the Display Properties
âȘ The source code on the previous slide contains a converter. This is represented in the GUI
design on the value tab and the display type
77. Add the Caller Name Field
âȘ Note the use of the Name Picker <xe:namePicker> control
â The âforâ of the namePicker needs to match the ID of your Target control
â Typically NamePickers require you to be logged in to work since your address book likely
has higher security
<xe:formRow
id="formRow3â label="Callerâ labelPosition="inherit">
<xp:inputText id="inputText1"
value="#{ticketDoc.ticketCaller}">
</xp:inputText>
<xe:namePicker id="namePicker1"
for="inputText1"
dialogTitle="Select the caller">
<xe:this.dataProvider>
<xe:dominoNABNamePicker>
</xe:dominoNABNamePicker>
</xe:this.dataProvider>
</xe:namePicker>
</xe:formRow>
78. Combo Boxes
âȘ Weâre about to add several Combo boxes
âȘ You can hard code values, compute values, or do a combination
âȘ If you use @DbColumns() or @DbLookups() to get the values watch out for the 64k limitation
that they still have
79. Add Ticket Category
âȘ This is a combo box. Note there is Server Side JavaScript Code for looking up the values
<xe:formRow id="formRow6â label="Categoryâ labelPosition="inherit"
for="category1">
<xp:comboBox id="category1"
value="#{ticketDoc.ticketCategory}">
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript://We start with a
blank array and concat choices, so the first item in the list is blank.
//that way, we can validate whether or not the user made a selection
var mychoices = new Array("");
var mydb = new Array(database.getServer(),database.getFilePath());
var myotherchoices = @DbLookup(mydb, "vwKeywords", "category", 2);
var mytotalchoices = mychoices.concat(myotherchoices);
return mytotalchoices;
}]]></xp:this.value>
</xp:selectItems>
</xp:comboBox>
</xe:formRow>
81. More Combo Boxes
âȘ Weâre going to do three more combo boxes for Platform, Priority, and Status
â They will work exactly the same. The only difference is the field weâre binding to and the
keyword that we pass into the view
82. Now Add the Row for Platform
âȘ Note the change in value for each field, and different keyword in the DbLookup
<xe:formRow
id="formRow7"
label="Platform:"
labelPosition="inherit"
for="platform1">
<xp:comboBox
id="platform1"
value="#{ticketDoc.ticketPlatform}">
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript://We start with a blank array and concat
choices, so the first item in the list is blank.
//that way, we can validate whether or not the user made a selection
var mychoices = new Array("");
var mydb = new Array(database.getServer(),database.getFilePath());
var myotherchoices = @DbLookup(mydb, "vwKeywords", "platform", 2);
var mytotalchoices = mychoices.concat(myotherchoices);
return mytotalchoices;}]]></xp:this.value>
</xp:selectItems>
</xp:comboBox>
</xe:formRow>
83
83. Now Add the Row for Priority
âȘ Note the change in value for each field, and different keyword in the DbLookup
<xe:formRow
id="formRow8"
label=âPriority:"
labelPosition="inherit"
for=âpriority1">
<xp:comboBox
id="platform1"
value="#{ticketDoc.ticketPriority}">
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript://We start with a blank array and
concat choices, so the first item in the list is blank.
//that way, we can validate whether or not the user made a selection
var mychoices = new Array("");
var mydb = new Array(database.getServer(),database.getFilePath());
var myotherchoices = @DbLookup(mydb, "vwKeywords", "priority", 2);
var mytotalchoices = mychoices.concat(myotherchoices);
return mytotalchoices;}]]></xp:this.value>
</xp:selectItems>
</xp:comboBox>
</xe:formRow>
84
84. Now Add the Row for Status
âȘ Note the change in value for each field, and different keyword in the DbLookup
<xe:formRow
id="formRow9"
label=âStatus:"
labelPosition="inherit"
for=âstatus1">
<xp:comboBox
id="platform1"
value="#{ticketDoc.ticketStatus}">
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript://We start with a blank array and
concat choices, so the first item in the list is blank.
//that way, we can validate whether or not the user made a selection
var mychoices = new Array("");
var mydb = new Array(database.getServer(),database.getFilePath());
var myotherchoices = @DbLookup(mydb, "vwKeywords", "status", 2);
var mytotalchoices = mychoices.concat(myotherchoices);
return mytotalchoices;}]]></xp:this.value>
</xp:selectItems>
</xp:comboBox>
</xe:formRow>
85. Add A Default Value for the Status ComboBox
âȘ Select the status field
âȘ On the Data tab, enter âOpenâ for the default value
86. Add the Description Row
âȘ Note the âstyleâ line - this is to make the size of the field wider
â Any style markup on the control overrides the theme
<xe:formRow
id="formRow10"
label="Description"
labelPosition="inherit">
<xp:inputTextarea
id="ticketDescID"
value="#{ticketDoc.ticketDescription}"
style="width:60%;height:3em">
</xp:inputTextarea>
</xe:formRow>
87. When all that is done your design screen looks like:
88. Add a Tool Tip
âȘ This is a common Dojo element made easy with the Extension Library
â Drag a Tooltip below your form table layout
89. Configure ToolTip
âȘ Enter the Label of the Tooltip
âȘ Enter the âforâ value. This is the ID of your control for the field âticketDescriptionâ
â Note - itâs the ID of the control - not the name of the field
90. Adding Buttons to the Form Table
âȘ The formTable contains a footer facet. Drag a Panel onto the green dot.
Note what the change looks like in
source. Weâll be working here for the
buttons by adding code inside the
<xp:panel> tags
91. Adding the Save Button
âȘ Inside the new Panel drag a button to the panel
We only want to show this button if in edit mode. Click the blue diamond to compute the
rendered property. Then add the code.
// Hide button if it's in
save mode
return
ticketDoc.isEditable();
92. Save Button Properties
âȘ We can compute whether or not the button is visible
âȘ Either enter the code in the source pane, or click the blue diamond next to âVisibleâ on the
Button tab, or click the blue diamond next to ârenderedâ on the All Properties tab
â The âPretty Panesâ contain common properties. All Properties contain everything
93. Save Button Properties ...
âȘ In order to make the button *do* something, click on the Events tab of the button
âȘ Click âAdd Action...â, change the Action to âSave Documentâ and the Data source name to
âticketDocâ
94. Adding the Close Button from Source
âȘ Next, inside the same panel under the </xp:button> add the code below
â Or you could drag another button, set the label to âCloseâ and do the Open Page Simple
Action
<xp:button
value="Close"
id="button2">
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="complete">
<xp:this.action>
<xp:openPage
name="$$PreviousPage"></xp:openPage>
</xp:this.action>
</xp:eventHandler>
</xp:button>
95. Adding the Edit Button via Source
âȘ Note as weâve seen before weâre computing when to render this button
â the â!â in the beginning reverses the True/False value
â We want a false if the ticketDoc is editable
<xp:button value="Editâ id="button3">
<xp:this.rendered>
<![CDATA[#{javascript:// Hide button if it's in edit mode
!ticketDoc.isEditable()}]]></xp:this.rendered>
<xp:eventHandler
event="onclickâ submit="trueâ refreshMode="complete">
<xp:this.action>
<xp:changeDocumentMode mode="edit"
var="ticketDoc">
</xp:changeDocumentMode>
</xp:this.action>
</xp:eventHandler>
</xp:button>
96. Forcing a Space
âȘ In the source pane, after each button tag, add  
âȘ This forces a space
âȘ Alternately in the design pane add the space using <ctrl><space> keyboard combination
</xp:button>
 
98. Summary
âȘ Created Ticket Custom control
â Used computed Fields, Edit Box, ComboBox, and Multi-line Edit box
âą Created Lookups for our comboboxes
âą Added some basic CSS to style a field
â Used Form Rows to give us a nice layout
âȘ Created Save, Close and Edit buttons
â Added appropriate rendering
99. Create a Custom Control to View Tickets
âȘ Create a new custom control as before.
âȘ Call it cc_Tickets and go to the beforePageLoad event
âȘ Add via Script Editor:
âȘ viewScope.put(âvsStatusâ, âOpenâ)
â This is an in memory scoped Variable that will live for the life of the page. Weâre setting
the default status we want to see to âOpenâ.
99
100. Add A Panel To Select Type of Tickets
âȘ Drag a Panel onto the page.
â Give it the ID of âstatusPanelâ
â Could also be added directly in source after the beforePageLoad tag
<xp:panel id="statusPanel">
</xp:panel>
100
101. Inside the Panel add a Combobox
âȘ This gets all the ticketsâ status values and returns them as options for the user to select from
âȘ We will bind the value of the Combo Box to the viewScope var we set earlier
âȘ Once a value is selected (âonchangeâ) the panel containing the view (âstatusPanelâ) will get
refreshed
âȘ This time weâre mixing a hard coded option of âChoose Statusâ which is the default value with
@DbColumn code
â To get our status weâll lookup from existing tickets and using @Unique() to return one
value for each status
â The reason for this is to only show statuses where we have actual data
âȘ Every time the Combo Box is changed a partial refresh is triggered on the panel
101
102. Inside the Panel add a Combobox
<xp:comboBox id="comboBox1â value="#{viewScope.vsStatus}">
<xp:selectItem
itemLabel="<<Choose Status>>"></xp:selectItem>
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript:// Not the most robust solution.
Has a 64K limit and some other issues
// But @Formulas still work in XPages
@Unique(@DbColumn("","vwTicketsByStatus",1));}]]></xp:this.value>
</xp:selectItems>
<xp:eventHandler event="onchangeâ submit="trueâ refreshMode="partial"
refreshId="statusPanel">
</xp:eventHandler>
</xp:comboBox>
102
103. Add the View
âȘ Drag the Container Control âViewâ onto the Design pane inside Panel
âȘ The âSelect Data Source for Viewâ dialog appears
âȘ Set the view to be: vwTicketsByStatus
âȘ Deselect $5 UNID - we donât want to display it
103
104. View Control on Your Page
âȘ The view is automagically created, including a pager
104
105. Add a Checkbox to the First Column
âȘ Select the first column
âȘ Display Tab - select âCheck boxâ - then Save the custom control
105
106. Customize the CSS on the View
âȘ From Resources, Style Sheets, click New Style Sheet Called âapplication.cssâ
âȘ Click OK
106
107. Adding CSS
âȘ Add the following code
âȘ Save and close
âȘ These classes will add shading to the odd rows
âȘ The âHOVERâ classes add different shading (and font color and weight) when the mouse
hovers over the rows
.oddRow {
BACKGROUND-COLOR: RGB(248, 248, 248);
}
.oddRow:HOVER {
BACKGROUND-COLOR: RGB(98, 120, 150);
color: #FFFFFF;
font-weight:bold;
}
.evenRow:HOVER {
107
108. Add the New CSS Resource to Your Custom Control
âȘ Include the style sheet as a resource on your custom control
âȘ Note: Since this CC will always be shown inside of âlayout_Mainâ you could also add it there.
Then it would be available for any future Custom Controls or XPages
108
109. Customize the CSS on the View
âȘ On the cc_Tickets custom control, select the View Panel
âȘ On the All Properties tab, enter âoddRow, evenRowâ to rowClasses
âȘ Thatâs it! Just like the styling markup directly on our description field overrides the theme, our
CSS resource applied to the control also overrides or âextendsâ the theme
109
110. Adding Buttons to Work against Selected Documents
âȘ Weâre going to add buttons for:
â Delete
â Close
â Waiting
â ReOpen
âȘ Weâre going to create a single custom control for the buttons and keep all our code in one
place
â We will create a script library to hold this code.
âȘ Weâre going to pass in properties at runtime to control the buttons
110
111. Create a SSJS Script Library
âȘ Code - Script Library - New Script Library
â Make sure to choose Server JavaScript
â Weâre going to add functions that weâll use shortly
111
112. Add Function for getSelected
âȘ This function will return an array with the selected documentsâ IDs
function getSelected(viewName:string) {
// Pass in the name of a viewPanel and return the selected ID's
as an array
print("Running Array")
var viewPanel=getComponent(viewName); // this gets a hold of the
viewPanel
var docArray = viewPanel.getSelectedIds(); // This gets the
array of selected documents
return docArray
112
113. Add Function for processDocuments
function processDocuments(action:string, array) {
//Based on the Action that's passed in, update the documents
// Loop through all the documents
var doc:NotesDocument
print("Length: " + array.length)
for(i=0; i < array.length; i++) {
var docId=array[i];
doc = database.getDocumentByID(docId);
// Switch is like a "Select Case" in LotusScript
switch(action) {
case "Delete":
doc.removePermanently(true);
break;
case "Close":
doc.replaceItemValue("ticketStatus", "Closed");
doc.save();
break;
113
case "Waiting":
doc.replaceItemValue("ticketStatus", "Waiting on User")
114. Add Function for getTicketCounts
function getTicketCounts() {
// Return a Map of the ticket types and counts
// TreeMap is different then HashMap as it's Sorted by the key value
var ticketMap:java.util.TreeMap = new
java.util.TreeMap(java.lang.String.CASE_INSENSITIVE_ORDER);
var myView:NotesView = database.getView("vwticketsByStatus");
var vec:NotesViewEntryCollection = myView.getAllEntries();
var entry:NotesViewEntry = vec.getFirstEntry();
var tmpEntry:NotesViewEntry = null;
// We need some temp. variables
var tmpStatus:string = "";
var tmpCount:integer = 0;
while (entry != null) {
tmpEntry = vec.getNextEntry();
// Get the current Ticket Status - Using first column value of the view.
// This is faster then getting the actual NotesDocument
114
tmpStatus = entry.getColumnValues()[0]
115. Looking at the SSJS Library
âȘ The first 2 functions should look like this:
115
116. Save Script Library and Exit
âȘ XPages and Custom Controls can access Script Libraries as resources. We will add it to the
control later.
116
117. Create Button Custom Control
âȘ Create a New Custom Control
âȘ call it btn_ProcessDocuments
117
118. Add the Property Definitions
âȘ Find Property Definition under the Properties Tab.
â Add a âNew Propertyâ for viewPanelName, action, and buttonName
â Each type should be string
âȘ Property definitions are items for passing in information to a custom control
â We will pass in information like âactionâ and our script will take that information and
determine what will happen when the button is clicked
â This is what allows the same custom control to be used for our different buttons
118
119. Adding a Script Library
âȘ In the Resources tab, click âAddâ and select âJavascript Libraryâ
âȘ Then select the SSJS Utilities JavaScript library
<xp:this.resources>
<xp:script
src="/SSJS Utilities.jss"
119
clientSide="false">
120. Add a Button to the Control
âȘ compositeData is an object available to SSJS of all the properties and values
âȘ Use âcompositeDataâ from the property definitions created earlier, to get the name of the
button
<xp:button
id="button2"
value="#{javascript:return compositeData.buttonName}">
120
</xp:button>
121. Finishing the Button
âȘ In the âonclickâ event call code in the script library to process documents
âȘ Save and Close
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="complete">
<xp:this.action>
121
<![CDATA[#{javascript:var array = getSelected(compositeData.viewPanelName);
122. What Does that Code Do?
âȘ compositeData is an object that lets you access the custom properties
â These properties will be set later when the custom control is added to an XPage or other
custom control
âȘ We will compute the label for the button at run time.
â Example we might want the buttons to show different languages
âȘ We will use the viewPanel name to determine the selected documents
âȘ We then use the action parameter to pass in the selected documents and desired action to
our script library
122
123. Add the Button Custom Control to cc_Tickets
âȘ Open the cc_Tickets Custom Control that was created earlier
âȘ Above the view panel add button custom control
123
124. Updating the Custom Properties
âȘ Adding values to the Custom Properties allows the control to be customized for each instance
â Remember we created the Property Definitions earlier, this is where we input the values
for this specific instance
124
125. Use The Source, Luke
âȘ Use Source to quickly Add Buttons for setting the ticket status to: close, Waiting, and Open
â Note forced spaces in between for niceness
 
<xc:btn_ProcessDocuments action="Closeâ buttonName="Close Tickets"
viewPanelName="viewPanel1">
</xc:btn_ProcessDocuments>
 
<xc:btn_ProcessDocuments action="Waitingâ buttonName="Set to Waiting"
viewPanelName="viewPanel1">
</xc:btn_ProcessDocuments>
 
<xc:btn_ProcessDocuments action="Openâ buttonName="ReOpen">
125
<xc:this.viewPanelName><![CDATA[#{javascript:"viewPanel1"}]]>
126. Status Check: cc_Tickets Should Now Look Like This:
âȘ Since the labels are computed they donât show at design time but will render correctly
126
127. Summary
âȘ Created a custom control to show/edit Tickets
â Used a viewScope variable to set some defaults
â Used formTable and formRow to display the fields and labels
â Added a tool tip
â Added buttons to save and edit and close the ticket
âȘ Created a custom control to view tickets
â Used the View control
âȘ Created a Script Library to hold three SSJS functions
âȘ Created a custom control for a button
â Allows passing parameters in at runtime via properties
â compositeData object
127
128. Next
âȘ Add the Ticket and Tickets custom controls to XPages
âȘ Add to Navigation
âȘ Create additional supporting Pages
128
130. Drag In the Controls for the Ticket XPage
âȘ Drag the layout_Main custom control onto the blank page
âȘ Drag the cc_ticket control into the middle facet target
130
131. The Controls for the Ticket Xpage - Source
âȘ The Source Pane will look like this. Save and Close.
131
132. Create the Tickets View XPage
âȘ Just like creating the âticketâ XPage, create
one for âticketsâ
âȘ XPages - New XPage
âȘ Title the XPage âticketsâ
âȘ Drag the layout_Main onto the page
âȘ Drag the cc_tickets custom control onto the
middle facet target
âȘ Save and Close
132
133. Test
âȘ Open the tickets XPage
âȘ Open the ticket XPage
âȘ Preview both in browser
133
134. Create a New Ticket via a Button on Placebar
âȘ Open the âlayout_Mainâ custom control to edit
âȘ Click on the Application Layout to select it in the Properties panel
âȘ Click on the Place Bar tab, click Add Item, and select âPage Link Nodeâ
134
135. Create a New Ticket via a Button on Placebar...
âȘ Fill in the label field and select the âticketâ page to open
135
136. Create a New Ticket via a Button on Placebar...
âȘ Hide the button when the user is on the Ticket page
âȘ Click the empty blue diamond next to ârenderedâ and select âCompute value...â
136
137. Create a New Ticket via a Button on Placebar...
âȘ Enter the following Server Side Javascript and click OK
â This will display the button only if the user is on the ticket.xsp XPage
var url = context.getUrl();
if(@Contains(url, "ticket.xsp") == true) {
return false;
137
138. Nav Bar...
âȘ Create a new CC called layout_Nav to hold the applications navigation menu
138
140. Adding Home to the Nav Bar
âȘ Go to properties for the navigator
âȘ Navigation Items - Click Add Item - Choose Page Link Node
âȘ Set Label to Home and chose home in the page dropdown
140
141. Adding Tickets to the Nav Bar
âȘ Go to properties for the navigator
âȘ Navigation Items - Click Add Item - Choose Page Link Node
âȘ Set Label to Tickets and chose tickets in the page dropdown
141
142. Add the Nav Bar to the Layout
âȘ Open the custom control created earlier, âlayout_Mainâ
âȘ Drag the custom control just created (âlayout_Navâ) and drag it into the left-hand target of the
main layout
142
143. Create a Keywords XPage for Form and View Together
âȘ Setting the viewScope on the âviewâ when the user clicks a row allows the âformâ to know
which document to open for editing on the page
â Set the viewScope with the doc ID of the selected row
â Get the doc ID from the viewScope
â Have the form use the doc ID to know which doc to edit
143
144. Create a Keywords âFormâ
âȘ Create the custom control for the âformâ
âȘ Custom control - New Custom Control - Name it âcc_keyword_formâ
âȘ Click on the âDataâ tab
âȘ Add the keyword form as the data source
144
145. Create a Keywords âFormâ...
âȘ Select the two fields and drag them onto the control
âȘ Select the âAdd Submit button to generated codeâ option
145
146. Get the viewScope to Know Which Document to Open
âȘ Click on the data tab
âȘ Change the default action to âEdit documentâ
âȘ Input viewScope.get(âselectedKeywordâ) into the editor
146
147. Make It Multi-Value
âȘ Since a keyword field can (and likely will) contain more than one value, i.e. category 1,
category 2, etc., we need to make the field on the XPage accept multi-values
âȘ Select the keyword_values field
âȘ Go to the All Properties tab
âȘ Enter â,â for the multipleSeparator property
148. Create a Keywords âViewâ
âȘ Create the custom control for the âviewâ
âȘ Custom controls - New Custom Control âcc_keyword_viewâ
âȘ Drag the Container Control âViewâ onto the
Design pane
âȘ The Select Data Source for View dialog
appears, use the âvwKeywordsâ view for the
source
148
149. Add the row data variable
âȘ Adding the row data variable gives you a handle on each row of the displayed view
âȘ With the view control selected, go to the All Properties tab
âȘ Enter ârowDataâ in the data ! var property
150. Create a Keywords âViewâ...
âȘ Click on the first column to select it
âȘ Click on the events tab
âȘ In the server side script editor for the on click event, enter
â viewScope.put("selectedKeyword",rowData.getUniversalID());
â This sets the viewScope used by the âformâ
150
151. Create a Keywords XPage for Form and View Together...
âȘ Create the keywords XPage
âȘ XPages - New XPage - named âadminâ
151
152. Create a Keywords XPage for Form and View Together...
âȘ Drag the âlayout_Mainâ control onto the page
âȘ Drag a panel container control into the middle facet
152
153. Create a Keywords XPage for Form and View Together...
âȘ Drag the âcc_keywords_formâ and âcc_keywords_viewâ controls into the panel
153
154. Create a Keywords XPage for Form and View Together...
âȘ Use the Outline to organize elements
154
155. Adding the Keywords Tab for Navigation
âȘ Open the âlayout_Mainâ custom control
âȘ Click on the Title Bar tab
âȘ Click Add Item, choose a Page Link node
âȘ Change the label to âHomeâ and select the home page from the dropdown for page
155
156. Adding the Keywords Tab
âȘ Repeat those steps to add another page link node
âȘ Call it âAdminâ and select the admin page for the page
âȘ You now have a different way of navigating the application
âȘ You can set the ârenderâ property to hide the Admin tab if appropriate
156
157. CRUD
âȘ At this point, we can:
â Create tickets (placebar button)
â Read tickets (tickets view)
â Update tickets (ticket custom control)
â Delete (custom control button)
157
158. Agenda
âȘ Who We Are
âȘ What We Are Building
âȘ What Are XPages?
âȘ Creating the Application
âȘ Refining the Application
158
160. Adding a Repeat Control
âȘ Create a new Custom Control
â Name: âcc_CommentViewâ
â Data source: Domino View, âvwCommentsByKeyâ
âȘ Add a panel to the control
âȘ Drag a Repeat Control into the panel
160
161. Binding the Repeat Control
âȘ Give the collection a name: âcommentDataâ
â This is allows us to âcallâ the data and do something with it
âȘ Bind the repeat control:
!
!
!
!
!
var cView:NotesView = database.getView("vwCommentsByKey");
var vec:ViewEntryCollection =
cView.getAllEntriesByKey(compositeData.ticketKey, true)
return vec
âȘ This creates the collection of entries that our repeat control will use
161
162. Displaying the Repeat Control
âȘ Drag a table into the Repeat Control
â 1 row, 4 columns: 3 computed fields in the 2nd, 3rd, and 4th cell
âȘ Into the first cell, drag another table
â 2 rows, 2 columns: 2 labels in top row, âHoursâ & âMinutesâ; 2 computed fields in bottom
row
<xp:table>
<xp:tr><xp:td><xp:table><xp:tr>
<xp:td>
<xp:label value="Hours" id="label1"></xp:label>
</xp:td><xp:td>
<xp:label value="Minutes" id="label2"></xp:label>
</xp:td>
</xp:tr><xp:tr>
162
<xp:td></xp:td><xp:td></xp:td></xp:tr></xp:table></xp:td>
163. Adding Fields to the Repeat Control
âȘ Now the cool part!
âȘ Add a computed field to the cell below âHoursâ
âȘ Bind the data:
â commentData.getColumnValues()[4]
âȘ This uses the collection created when we bound the repeat control as our âviewâ, binding this
computed field to the column value and displaying it inside the repeat control will
automagically display each ârecordâ once in a panel, repeated on the page
âȘ Add the rest of the computed fields and bind them per the script snippet
163
164. Looking at the Repeat Control (via the Magic of Television)
This
Becomes this
164
166. Validation
âȘ Click on the Ticket Caller edit box.
âȘ Simple validation can be added on the Validation tab.
âȘ Select the check box next to âRequired fieldâ.
âȘ Enter âEnter a ticket callerâ for the error message.
166
167. Validation
âȘ Select the Ticket Priority field
âȘ On the All Properties tab, click the plus sign next to âvalidatorsâ
âȘ Select âxp:validateRequiredâ
167
168. Validation
âȘ Click the dropdown next to âloadedâ and select âtrueâ
âȘ Enter the message âSelect a ticket priorityâ in the message field
168
169. Validation
âȘ The previous steps are all that is needed for validation
âȘ However, we can improve validation by adding nicer error messages
âȘ Drag the Display Error control to the ticketCaller row
âȘ In the Display Error tab select the ticketCaller field to âShow error messages forâ
âȘ Repeat for other rows with field validation
169
170. Validation
âȘ In order for the Display Error controls to work, client side validation needs to be disabled
âȘ Go to Application Properties, XPages tab
âȘ Select âOffâ for Client Validation
170
171. Validation
âȘ By default this will create table errors and row errors, in addition to the error message control
âȘ Click on the Form Table control, go to All Properties and set âdisableErrorSummaryâ and
âdisableRowErrorâ to âtrueâ
171
172. File Upload
âȘ Add another Form Layout Row, label it âFile Uploadâ
âȘ Drag the âFile Uploadâ control onto the custom control and bind the field to the âticketFilesâ
field
172
174. File Upload - FYI
âȘ Prior to 9.0.1 the page would require a full refresh on save in order to save and retain the
attachment
âȘ 9.0.1 includes a bug fix that allows partial refresh to save attachments
175. File Download
âȘ Create another form row
âȘ Drag the File Download control onto the row
âȘ Make the following selections
175
176. Reference
âȘ Suggested sessions
â AD201 : IBM Domino Application Development: Today and Tomorrow
â JMP101 : Java for XPages Development
â BP202 : Rapid XPages Development Using the Application Layout Control
â Many Many more....
âȘ Useful links
â XPages.info
â OpenNTF.org
âą http://openntf.org/XSnippets.nsf
â notesin9.com
â XPagesWiki.com
â http://www-10.lotus.com/ldd/xpagesforum.nsf
â http://stackoverflow.com/questions/tagged/xpages
176
177. âȘ Access Connect Online to complete your session surveys using any:
â Web or mobile browser
â Connect Online kiosk onsite
8