This guide helps you through writing a multi-page custom Hubitat Elevation app. Some familiarity with the Hubitat app development environment is assumed, and therefore it is recommended that you have read and understand at least the following guide (and its suggested prior readings):
In this guide, we build on this foundation to demonstrate a more complex app interface, one with multiple pages. We demonstrate two techniques that allow users to reach multiple pages within your app:
nextPage
parameter on the page); orhref()
).We will start with a basic app template as one might take from the App Overview guide:
definition(
name: "My Multi-Page App",
namespace: "MyNamespace",
author: "My Name",
description: "A simple example app with multiple pages",
category: "Convenience",
iconUrl: "",
iconX2Url: ""
)
preferences {
page(name: "mainPage", title: "My First Page", install: true, uninstall: true) {
section {
paragraph "This is my first page."
}
}
}
def installed() {
log.trace "installed()"
}
def updated() {
log.trace "updated()"
}
def uninstalled() {}
Let's say that we want setup for this app to flow through a series of pages, with the user selecting Next at the bottom of each page until setup is complete, at which point they can select Done. Recall from App Overview that we can use the nextPage
parameter on a page
. This replaces the Done button (which otherwise appears by default at the bottom of the app page) with a Next button, and selecting Next will take the user to the specified page.
So, to add a second page (and make sure the user can actually get there), we can make two changes inside our preferences
block:
page()
, including all required parametersnextPage
parameter on the first page to our new page (and remove install: true
or set it to false
; every page should have one or the other specified, but the Done button displayed as a result of install: true
would take precedence)Step 1, defining a second page, is easy and can be done similarly to our first page (just be sure to give each page a unique name — and take note of what the name is for your new page):
page(name: "secondPage", title: "My Second Page", install: true, uninstall: true) {
section {
paragraph "This is my second page."
}
}
Then, we can modify the parameters of our first page to add nextPage
, setting its value to the name of the new page. Above, we named this new page "secondPage"
(but could have used any valid name):
page(name: "mainPage", title: "My First Page", uninstall: true, nextPage: "secondPage") {
// ...
We could make additional modifications if needed. For example, leaving uninstall: true
on both of these pages shows the Remove button (to uninstall the app) on both pages. This may be desirable in some cases; in others, you may wish to allow uninstallation from only one specific page in your app (e.g., to avoid accidents or to provide additional warning to the user first).
Putting all of this together, such an app might look like this:
definition(
name: "My Multi-Page App",
namespace: "MyNamespace",
author: "My Name",
description: "A simple example app with multiple pages",
category: "Convenience",
iconUrl: "",
iconX2Url: ""
)
preferences {
page(name: "mainPage", title: "My First Page", nextPage: "secondPage", uninstall: true) {
section {
paragraph 'This is my first page. Selecting "Next" will navigate to the second page."
}
}
page(name: "secondPage", title: "My Second Page", install: true, uninstall: true) {
section {
paragraph 'This is my second page. You can install the app by selecting "Done" below.'
}
}
}
def installed() {
log.trace "installed()"
}
def updated() {
log.trace "updated()"
}
def uninstalled() {}
The above setup works well for some types of apps. (For built-in app examples, consider the Hue Bridge integration app that steps users through the setup process the first time the app is opened.)
For other apps, you may wish to incorporate multiple pages by linking to other pages from any page in your app. Recall from App Overview that we can do this with href()
. (Returning to our Hue Bridge Integration example above, the app uses href
links on the main page after initial setup to allow the user to select bulbs or groups to add, among other options. You can combine both ways of navigating between pages in your apps as needed.)
Like input()
, href()
is used inside a section()
where the interface for your app is defined.
It possible to link to other app pages using href()
, and it is possible to pass parameters to those other pages. Parameters for href()
include:
name
: String
, name of this href
(should be unique)page
: String
, the name
of the page
to link toparams
: Map
, optional; a Map
of values that can be passed to the other pagetitle
: String
, title/heading for this href
description
: String
; additional text to display under the title on this href
state
: String
, set to "complete"
to show in blue text, often indicating completion; omit or set to null
to show in gray (default)Example href
:
href name: "myHref", page: "myOtherPage", title: "Go to other page!"
Or for a full app demonstrating this basic usage (and also the use of nextPage
-- we use this to easily return to the main page from the other page):
definition(
name: "My Multi-Page App 2",
namespace: "MyNamespace",
author: "My Name",
description: "A simple example app with multiple pages",
category: "Convenience",
iconUrl: "",
iconX2Url: ""
)
preferences {
page(name: "mainPage", title: "My First Page", install: true, uninstall: true) {
section {
paragraph "This is my first page."
href name: "myHref", page: "otherPage", title: "Go to other page"
}
}
page(name: "otherPage", title: "My Other Page", nextPage: "mainPage", uninstall: true) {
section {
paragraph 'This is my second page. Select "Next" to return to the main page.'
}
}
}
def installed() {
log.trace "installed()"
}
def updated() {
log.trace "updated()"
}
def uninstalled() {}
More complicated apps may also need to pass parameters to the other page. This can be done with the params
option, which accepts a map that can be read inside the other page. You will need to use dynamicPage
instead of page
to access these parameters. This use is demonstrated below:
definition(
name: "My Multi-Page App 2",
namespace: "MyNamespace",
author: "My Name",
description: "A simple example app with multiple pages",
category: "Convenience",
iconUrl: "",
iconX2Url: ""
)
preferences {
page(name: "mainPage", title: "My First Page", install: true, uninstall: true) {
section {
paragraph "This is my first page."
href name: "myHref", page: "otherPage", title: "Go to other page", params: [myKey: "My value"]
}
}
page(name: "otherPage", title: "My Other Page", nextPage: "mainPage", uninstall: true)
}
def otherPage(params) { // <-- must have parameter here to access values passed in as href params
dynamicPage(name: "otherPage") {
section {
paragraph "This is my second page. myKey = ${params.myKey}"
paragraph 'Select "Next" to return to the main page.'
}
}
}
def installed() {
log.trace "installed()"
}
def updated() {
log.trace "updated()"
}
def uninstalled() {}
To make this work, we have:
params
parameter with the href
; andpage
to a dynamicPage
, which entailed:
dynamicPage
out of preferences
and into its own method (but still keeping a reference to this page in preferences
, where we are also setting some options on it)otherPage()
(we have called this parameter params
for ease of remembering that it corresponds to params
from the href
, though in your method you could actually call it any valid name)NOTE: In the above example, we specified options for the dynamic page on
page
insidepreferences
. However, these could also be moved todynamicPage()
, i.e., replacing:page(name: "otherPage", title: "My Other Page", nextPage: "mainPage", uninstall: true) // ... dynamicPage(name: "otherPage") {
with:
page(name: "otherPage") // ... dynamicPage(name: "otherPage", title: "My Other Page", nextPage: "mainPage", uninstall: true) {
The latter may be more flexible for some use cases (e.g., allowing you to use parameters as values for any of these options).
In the simple example app, we use an "implicit" page. As mentioned there, an explicit page()
is optional for single-page apps. Pages must be explicitly defined for multi-page apps. However, even for a single-page app, there are differences:
page()
, an implicit page app will add UI elements for you:
You have now seen how to incorporate multiple pages into your apps and two ways to allow users to navigate to and from other pages. You have also learned how to use "dynamic pages," whose contents are generated by methods rather than fully defined in preferences
(dynamic pages being a technique necessary for use of some features, including accessing parameters passed in as part of an href
).
The remaining developer docs, in particular those related to apps, may be helpful to continue reading as you develop more on the platform.