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 hrefdescription: String; additional text to display under the title on this hrefstate: 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
pageinsidepreferences. 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 between an implicit and explicit page:
page(), an implicit single-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.