App inputs don't always persist when navigating backwards

I’m trying to make a simple app where you select multiple devices, then dynamically generate pages based on the list of selected devices. However, I notice when I navigate backwards, previous selections don’t persist even though they’re in the settings object. I originally tried doing this with href’s, but ran into problems getting the pages to render properly, if at all. So now I’m trying the ‘nextPage’ approach. I have something kinda working, but here’s the strange behavior I notice:

  1. Tap on my app to install it
  2. Select Kitchen Fan Light on pageMain
  3. Confirm that it does indeed propagate to the next page, pageSelectLights
  4. Select ZLT: KIT Fan (Catio), ZLT: KIT Fan (Fridge), ZLT: KIT Fan (Table) as the lights controlled by the Kitchen Fan Light switch.
  5. Confirm that it does indeed propagate to the next page, pageCustomizeBehavior
  6. From this last page, I navigate backward where I see the settings object still has ZLT: KIT Fan (Catio), ZLT: KIT Fan (Fridge), ZLT: KIT Fan (Table) in it, but the input doesn’t auto-populate with them. However, if I navigate back to the main page, the Kitchen Fan Light setting does persist.

What’s going on here?

Here are the logs showing the settings object appears to correctly persist user selections, but on the Select Lights page, they don’t persist in the UI:

[41273ff9-7d7b-4025-8fe9-60d0e2785b62](https://graph-na02-useast1.api.smartthings.com/ide/logs#41273ff9-7d7b-4025-8fe9-60d0e2785b62) 5:57:42 PM: info setting: k(varSwitches) v([Kitchen Fan Light])
[41273ff9-7d7b-4025-8fe9-60d0e2785b62](https://graph-na02-useast1.api.smartthings.com/ide/logs#41273ff9-7d7b-4025-8fe9-60d0e2785b62) 5:57:42 PM: info setting: k(varSwitchCustom1531b0f81be2246b7a4d8c6172271a21d) v(true)
[41273ff9-7d7b-4025-8fe9-60d0e2785b62](https://graph-na02-useast1.api.smartthings.com/ide/logs#41273ff9-7d7b-4025-8fe9-60d0e2785b62) 5:57:42 PM: info pageMain: state([:])
[41273ff9-7d7b-4025-8fe9-60d0e2785b62](https://graph-na02-useast1.api.smartthings.com/ide/logs#41273ff9-7d7b-4025-8fe9-60d0e2785b62) 5:57:38 PM: info setting: k(varSwitches) v([Kitchen Fan Light])
[41273ff9-7d7b-4025-8fe9-60d0e2785b62](https://graph-na02-useast1.api.smartthings.com/ide/logs#41273ff9-7d7b-4025-8fe9-60d0e2785b62) 5:57:38 PM: info setting: k(varSwitchCustom1531b0f81be2246b7a4d8c6172271a21d) v(true)
[41273ff9-7d7b-4025-8fe9-60d0e2785b62](https://graph-na02-useast1.api.smartthings.com/ide/logs#41273ff9-7d7b-4025-8fe9-60d0e2785b62) 5:57:38 PM: info setting: k(varSwitchLights531b0f81be2246b7a4d8c6172271a21d) v([ZLT: KIT Fan (Catio), ZLT: KIT Fan (Fridge), ZLT: KIT Fan (Table)])
[41273ff9-7d7b-4025-8fe9-60d0e2785b62](https://graph-na02-useast1.api.smartthings.com/ide/logs#41273ff9-7d7b-4025-8fe9-60d0e2785b62) 5:57:38 PM: info pageSelectLights: state([:])
[41273ff9-7d7b-4025-8fe9-60d0e2785b62](https://graph-na02-useast1.api.smartthings.com/ide/logs#41273ff9-7d7b-4025-8fe9-60d0e2785b62) 5:57:30 PM: info setting: k(varSwitches) v([Kitchen Fan Light])
[41273ff9-7d7b-4025-8fe9-60d0e2785b62](https://graph-na02-useast1.api.smartthings.com/ide/logs#41273ff9-7d7b-4025-8fe9-60d0e2785b62) 5:57:30 PM: info setting: k(varSwitchLights531b0f81be2246b7a4d8c6172271a21d) v([ZLT: KIT Fan (Catio), ZLT: KIT Fan (Fridge), ZLT: KIT Fan (Table)])
[41273ff9-7d7b-4025-8fe9-60d0e2785b62](https://graph-na02-useast1.api.smartthings.com/ide/logs#41273ff9-7d7b-4025-8fe9-60d0e2785b62) 5:57:30 PM: info pageCustomizeBehavior: state([:])
[41273ff9-7d7b-4025-8fe9-60d0e2785b62](https://graph-na02-useast1.api.smartthings.com/ide/logs#41273ff9-7d7b-4025-8fe9-60d0e2785b62) 5:57:23 PM: info setting: k(varSwitches) v([Kitchen Fan Light])
[41273ff9-7d7b-4025-8fe9-60d0e2785b62](https://graph-na02-useast1.api.smartthings.com/ide/logs#41273ff9-7d7b-4025-8fe9-60d0e2785b62) 5:57:23 PM: info pageSelectLights: state([:])
[41273ff9-7d7b-4025-8fe9-60d0e2785b62](https://graph-na02-useast1.api.smartthings.com/ide/logs#41273ff9-7d7b-4025-8fe9-60d0e2785b62) 5:57:12 PM: info pageMain: state([:])

And here’s the code:

preferences {
    page(name: "pageMain")
    page(name: "pageSelectLights")
    page(name: "pageCustomizeBehavior")
}

def pageMain() {
	log.info("pageMain: state(${state})")
	settings.each() { key, value ->
        log.info("setting: k(${key}) v(${value})")
    }
    
    dynamicPage(name: "pageMain", title: "", uninstall: true, nextPage: "pageSelectLights") {
        section("Select switches that control one or more lights") {
            input(
                name: "varSwitches",
                type: "capability.switch",
                title: "Switches",
                description: "",
                multiple: true,
                required: true)
        }
    }
}

def pageSelectLights() {
	log.info("pageSelectLights: state(${state})")
	settings.each() { key, value ->
        log.info("setting: k(${key}) v(${value})")
    }
    
	dynamicPage(name: "pageSelectLights", title: "Switch Settings", nextPage: "pageCustomizeBehavior") {
    	section("Select lights controlled by each switch") {
        	varSwitches.each() {
                def devID = it.getId().replace("-", "")
                def devName = it.getDisplayName()
                input(name: "varSwitchLights${devID}", type: "capability.switch", title: devName, multiple: true, required: true)
            }
        }
    }
}

def pageCustomizeBehavior() {
	log.info("pageCustomizeBehavior: state(${state})")
	settings.each() { key, value ->
        log.info("setting: k(${key}) v(${value})")
    }
    
	dynamicPage(name: "pageCustomizeBehavior", title: "Additional Settings", install: true) {
    	section("Custom behavior 1") {
        	varSwitches.each() {
                def devID = it.getId().replace("-", "")
                def devName = it.getDisplayName()
                input(name: "varSwitchCustom1${devID}", type: "bool", title: devName, defaultValue: true)
            }
        }
    }
}
    
def installed() {
	log.debug "Installed with settings: ${settings}"

	initialize()
}

def updated() {
	log.debug "Updated with settings: ${settings}"

	unsubscribe()
	initialize()
}

def initialize() {
	// TODO: subscribe to attributes, devices, locations, etc.
}

// TODO: implement event handlers

Hi, there! Let me see if I understand the workflow of your application:

  1. Main: Select devices you will use as main switches.
  2. SelectLights
    a. It generates the inputs according to the quantity of the devices you selected in Main
    b. You can select a list of devices that the switch of Main will control.
  3. Behavior: The options to define a behavior for each group of lights (on/off) are generated also based on the selection in Main.

As every time you enter those pages, the inputs are regenerated, the previous options selected are not kept.

BTW, the Groovy SmartApps are part of our legacy platform, so, I suggest you get started with the SmartApp SDK, here’s a tutorial about it:

Hi @nayelyz ,

Thanks for your reply. Your understanding of the workflow is correct. So if a user initially configures the app with 10 switches, each with 3 lights associated with them, the user cannot later change just one of the associated lights without reconfiguring everything in the process? If that is the case, is there another way to setup the preferences so that a user’s settings are preserved in the preference screens when they go to update them?

In the Groovy SmartApp, you can fix the number of “main” switches you can use, so you don’t have to generate dynamically the inputs in the next pages.
Using the SmartApp SDK, I created a single-page SmartApp with the following workflow:

  1. Select the list of main switches.
  2. Click in done and create the new sections to configure the list of switches controlled and their behavior.
  3. Allow the installation only when all required values are filled

Here, if the user wants to update the list of “main” switches, the values remain, not like in the Groovy IDE SmartApp.