Dynamic containers on page load instead of onchange?

Dynamic containers on page load instead of onchange?

avatar
Product: PowerShell Universal
Version: 5.5.2


New-UDPage -Url '/EditRoomDefaults' -Name 'Edit Room Mailbox Config' -Content {
	New-UDTypography -Text 'Edit Room Mailbox Config' -Variant 'h4' -Id 'pageTitle'
	Import-Module ActiveDirectory
	# Setup basic form
	New-UDForm -Id 'roomConfigForm' -Content {
		New-UDRow -Columns {
			New-UDColumn -Size 2 -Content {
				# create a single textbox with verifcations to AD, update UI 'on the fly'
				New-UDTextbox -Id 'txtMailboxEmailAddress' -Label 'mailbox address' -Placeholder 'yaya@domain.com ' -Value 'toure@domain.com' -FullWidth  -OnValidate {
					$FoundMailbox = $null
					$Mail = (Get-UDElement -Id 'txtMailboxEmailAddress').value

					if (-not [string]::IsNullOrEmpty($Mail))
					{
						try
						{
							# $FoundMailbox = Get-ADUser -LDAPFilter "(mail=$($Mail.ToLower()))" -ErrorAction Stop
							$FoundMailbox = $true
						}
						catch
						{
							Set-UDElement -Id 'errorEmail' -Properties @{ Content = "Error checking email: $($_.Exception.Message)" }
						}

						if ($FoundMailbox)
						{
							Set-UDElement -Id 'txtMailboxEmailAddress' -Properties @{ Value = "$Mail" } # Or $FoundMailbox.mail if you want the AD value
							Set-UDElement -Id 'errorEmail' -Properties @{ Content = '' }
							Set-UDElement -Id 'txtMailboxEmailAddress' -Properties @{ Icon = (New-UDIcon -Icon Check -Style @{ color = 'green' }) }
							New-UDFormValidationResult -Valid # Email is valid
						}
						else
						{
							Set-UDElement -Id 'txtMailboxEmailAddress' -Properties @{ Value = "$Mail" }
							Set-UDElement -Id 'errorEmail' -Properties @{ Content = "Email address '$mail' doesn't exist." }
							Set-UDElement -Id 'txtMailboxEmailAddress' -Properties @{ Icon = (New-UDIcon -Icon Xmark -Style @{ color = 'red' }) }
						}
					}
					elseif ([string]::IsNullOrEmpty($Mail))
					{
						Set-UDElement -Id 'errorEmail' -Properties @{ Content = 'Mail is required.' }
						Set-UDElement -Id 'txtMailboxEmailAddress' -Properties @{ Icon = (New-UDIcon -Icon Xmark -Style @{ color = 'red' }) }
					}
				}
				New-UDElement -Tag 'div' -Id 'errorEmail' -Attributes @{
					style = @{
						color = 'red'
					}
				}
			}
		}
		# Empty container (div) to display errors concerning mailaddress validation.
		New-UDDynamic -Id 'dynamicContent' -Content {
			New-UDElement -Tag 'div' -Id 'errorMailboxEmailAddress' -Attributes @{
				style = @{
					color = 'red'
				}
			}
		}
	} -OnSubmit {
		# Create custom object to create our new UI elements with.
		$Properties = [PSCustomObject]@{
			Capacity               = '1'
			Floor                  = '1'
			IsWheelChairAccessible = $True
			AudioDevice            = $True
			VideoDevice            = $True
			DisplayDevice          = $true
			AllBookInPolicy        = $false
			AllRequestInPolicy     = $true
			AutomateProcessing     = $true
			DeleteSubject          = $true
			BookingWindowInDays    = '428'
			Tags                   = 'wifi'
		}

		# Debug code to console
		$Properties | Write-Host

		# Dynamic section to 're'-create UI form.
		New-UDDynamic -Id 'dynamicSettings' -Content {
       
			New-UDRow -Columns {
				New-UDColumn -Size 6 -Content {
					New-UDTextbox -Id 'txtCapacity' -Label 'Capacity' -Value $properties.Capacity
				}
				New-UDColumn -Size 6 -Content {
					New-UDTextbox -Id 'txtFloor' -Label 'Floor' -Value $Properties.Floor
				}

				New-UDColumn -Size 6 -Content {
					New-UDCheckBox -Id 'checkboxIsWheelChairAccessible' -Label 'Is WheelChair Accessible' -Checked $Properties.IsWheelChairAccessible
				}
				New-UDColumn -Size 6 -Content {
					New-UDCheckBox -Id 'checkboxAudioDevice' -Label 'Audio Device' -Checked $Properties.AudioDevice
				}

				New-UDColumn -Size 6 -Content {
					New-UDCheckBox -Id 'checkboxVideoDevice' -Label 'Video Device' -Checked $Properties.VideoDevice
				}
				New-UDColumn -Size 6 -Content {
					New-UDCheckBox -Id 'checkboxDisplayDevice' -Label 'Display Device' -Checked $Properties.DisplayDevice
				}

				New-UDColumn -Size 6 -Content {
					New-UDTextbox -Id 'txtTags' -Label 'Tags' -Value $Properties.Tags
				}
				New-UDColumn -Size 6 -Content {
					New-UDCheckBox -Id 'checkboxDeleteSubject' -Label 'Delete Subject' -Checked $Properties.DeleteSubject
				}

				New-UDColumn -Size 6 -Content {
					New-UDTextbox -Id 'txtBookingWindowInDay' -Label 'Booking Window In Days' -Value $Properties.BookingWindowInDays
				}
				New-UDColumn -Size 6 -Content {
					New-UDCheckBox -Label 'AllBookInPolicy' -Id 'checkboxAllBookInPolicy'  -Checked $Properties.AllBookInPolicy -OnChange {
						Sync-UDElement -Id 'dynamicAllBookInPolicyCheckboxContainer'
						Sync-UDElement -Id 'dynamicAllRequestInPolicyInputContainer'
					}
				}
			}
		}
		New-UDColumn -Size 6 -Content {

			New-UDDynamic -Id 'dynamicAllBookInPolicyCheckboxContainer' -Content {
				$AllBookInPolicy = (Get-UDElement -Id 'checkboxAllBookInPolicy').checked

				if ($AllBookInPolicy -eq $false)
				{
					New-UDCheckBox -Id 'checkboxAllRequestInPolicy' -Checked $Properties.AllRequestInPolicy -Style @{
						marginRight = '-16px' #For some reason, the checkbox gets a margin of 16px, this is to reverse that undesired margin.
					} -OnChange {
						Sync-UDElement -Id 'dynamicAllRequestInPolicyInputContainer'
					} 
					New-UDTooltip -TooltipContent {
						New-UDTypography -Text 'When you want AllBookinPolicy to be limited this needs to be set to $false. Otherwise the booking will go to a ''tentative'' state. Waiting for approval by a delegate.'
					} -Content {
						New-UDTypography -Text 'Disable AllRequestInPolicy' 
					}
				}
				else
				{
					#If AllBookingPolicy is true, we don't want AllRequestInPolicy to be available or selected.
					Set-UDElement -Id 'AllRequestInPolicy' -Properties @{ Checked = $false } #Clear upon deselect, just to be sure.
				}
			}# end dynamic

			New-UDDynamic -Id 'dynamicAllRequestInPolicyInputContainer' -Content {
				$AllBookInPolicy = (Get-UDElement -Id 'checkboxAllBookInPolicy').checked #Remember to re-add, with dynamic, the scope gets lost!
				$AllRequestInPolicy = (Get-UDElement -Id 'checkboxAllRequestInPolicy').checked
				if ($AllRequestInPolicy -eq $true -and $AllBookInPolicy -eq $false)
				{
					New-UDColumn -Size 2 -Content {
						# later we need to fill this with the people that are allowed to book
						New-UDTextbox -Id 'txtAllBookinPolicyList' -Label 'List of people allowed to book.' -Placeholder 'Provide a list of user mail addressess separated by ;' -FullWidth
					}
				}
				else
				{
					Set-UDElement -Id 'txtAllBookinPolicyList' -Properties @{ Value = '' } #Clear upon deselect, just to be sure.
				}
			}
		}
	} # end of submit.
} -Title 'Room Mailbox Config' 

This used mocked data to simplify the code.
The problem I have is with the checkboxes.
When i retrieve the data and `AllBookInPolicy` is `$false` then
if `AllRequestInPolicy` is `true` it should be selected and show the textbox `txtAllBookinPolicyList`.

The problem is that these dynamic containers, only update when I have an onChange event. These happen after the page is loaded.
Is there any way around this?


This used mocked data to simplify the code.
The problem I have is with the checkboxes on pageload.

When i retrieve the data and AllBookInPolicy is $false then
if AllRequestInPolicy is true it should be selected and show the textbox txtAllBookinPolicyList.

The problem is that these dynamic containers, only update when I have an onChange event. These happen after the page is loaded. The dynamic containers work when the page is loaded.

Perhaps I am doing it all wrong. Is there any way to get around this?

All Comments (2)

avatar

So after a lot of reading and struggle, i came up with the following solution.
This seems to work 98% of the time. The 2% is when you do a reload of the page too soon after the previous one. Somehow , the submit button doesn’t work, no clue why.

<#
.SYNOPSIS
    The goal of the UI should be:

    If AllBookinPolicy is checked --> Don't show anything else.
    If AllBookinPolicy if NOT checked --> Show AllRequestInPolicy checkbox.
    If AllRequestInPolicy is checked --> Show Textbox txtAllBookinPolicyList.
    If AllRequestInPolicy is NOT checked --> Don't show textbox txtAllBookinPolicyList.

.DESCRIPTION
    The problem is that by using Get-UDElement & Set-UDElement, we encouter the issue that
        
        - When the page is loading,
        - I address DOM-objects, that are not ready loading yet.

    This means that if I use Get-UDElement 'checkboxAllBookInPolicy' and the object in the browser isn't ready yet at the time that I call it
    it breaks the entire code.

    In my use case, we can retrieve our desired INITIAL state of the UI object, by using Get-mailbox .... , and store those in $Cache:variables.
    When we then change the state of the object, we use the -onChange event and $Eventdata (which holds true/false), to adjust the $Cache:variable.
    This way, the variables are always up to date and the UI should have the correct state.
#>

New-UDPage -Url "/DynamicChecks" -Name "Test" -Content {
    New-UDTypography -Text 'Test dynamic checkboxes in UI' -Variant 'h4' -Id 'pageTitle'
    New-UDForm -Id 'roomConfigForm' -Content {
        New-UDRow -Columns {
            New-UDColumn -Size 2 -Content {
                # create a single textbox with verifcations to AD, update UI 'on the fly'
                New-UDTextbox -Id 'txtMailboxEmailAddress' -Label 'mailbox address' -Placeholder 'yaya@domain.com ' -Value 'toure@domain.com' -FullWidth
            }
        }
        # Empty container (div) to display errors concerning mailaddress validation.
        New-UDDynamic -Id 'dynamicContent' -Content {
            New-UDElement -Tag 'div' -Id 'errorMailboxEmailAddress' -Attributes @{
                style = @{
                    color = 'red'
                }
            }
        }
    } -OnSubmit {
        Start-sleep 5
        # Mock the initiale session state for checkbox values. 
        # These should normally come from Exchange by using Get-Mailbox ....
        $Cache:AllBookInPolicy = $false
        $Cache:AllRequestInPolicy = $true

        # Create custom object to build our new UI elements with.
        $Properties = [PSCustomObject]@{
            AllBookInPolicy     = $Cache:AllBookInPolicy
            AllRequestInPolicy  = $Cache:AllRequestInPolicy
            AutomateProcessing  = $true
            BookingWindowInDays = '428'
            Tags                = 'wifi'
        }

        # Debug code to console
        $Properties | Write-Host
        
        # Dynamic section to 're'-create UI form.
        # New-UDDynamic -Id 'dynamicSettings' -Content {
        New-UDRow -Columns {
            New-UDColumn -Size 6 -Content {
                New-UDCheckBox -Label 'AllBookInPolicy' -Id 'checkboxAllBookInPolicy' -Checked $Cache:AllBookInPolicy -OnChange {
                    # Update cache state when checkbox changes --> basically replaces Get-UDElement, which was not reliable.
                    $Cache:AllBookInPolicy = $EventData
                    Sync-UDElement -Id 'dynamicAllBookInPolicyCheckboxContainer'
                    Sync-UDElement -Id 'dynamicAllRequestInPolicyInputContainer'
                }
            }
        }
        # }

        New-UDColumn -Size 6 -Content {
            New-UDDynamic -Id 'dynamicAllBookInPolicyCheckboxContainer' -Content {

                # Use cache state instead of reading the DOM with Get-UDElement.
                $AllBookInPolicy = $Cache:AllBookInPolicy

                # Only show "Disable AllRequestInPolicy" checkbox when AllBookInPolicy is FALSE
                if ($AllBookInPolicy -eq $false)
                {
                    New-UDCheckBox -Id 'checkboxAllRequestInPolicy' -Checked $Cache:AllRequestInPolicy -Style @{
                        marginRight = '-16px' #For some reason, the checkbox gets a margin of 16px, this is to reverse that undesired margin.
                    } -OnChange {
                        # Update cache state when checkbox changes --> basically replaces Get-UDElement, which was not reliable.
                        $Cache:AllRequestInPolicy = $EventData
                        Sync-UDElement -Id 'dynamicAllRequestInPolicyInputContainer'
                    }
                    New-UDTooltip -TooltipContent {
                        New-UDTypography -Text 'When you want AllBookinPolicy to be limited this needs to be set to $false. Otherwise the booking will go to a ''tentative'' state. Waiting for approval by a delegate.'
                    } -Content {
                        New-UDTypography -Text 'Disable AllRequestInPolicy'
                    }
                }
                # If AllBookInPolicy is true, don't show the AllRequestInPolicy checkbox at all
            } # end dynamic

            New-UDDynamic -Id 'dynamicAllRequestInPolicyInputContainer' -Content {
                   
                # Use cache state instead of reading the DOM with Get-UDElement.
                $AllBookInPolicy = $Cache:AllBookInPolicy
                $AllRequestInPolicy = $Cache:AllRequestInPolicy

                # Only show textbox when AllBookInPolicy is FALSE
                if ($AllBookInPolicy -eq $false)
                {
                    # Show textbox when AllRequestInPolicy is TRUE AND AllBookInPolicy is FALSE
                    if ($AllRequestInPolicy -eq $true)
                    {
                        New-UDColumn -Size 2 -Content {
                            # later we need to fill this with the people that are allowed to book
                            New-UDTextbox -Id 'txtAllBookinPolicyList' -Label 'List of people allowed to book.' -Placeholder 'Provide a list of user mail addressess separated by ;' -FullWidth
                        }
                    }
                }
                # If AllBookInPolicy is true, don't show anything in this container!
            }
        }


        # Stuck here : 
        # Stuck here : 
        # Stuck here : 
        # Add a separate form for final submission that will hide after submit
       

    }-OnProcessing {
        New-UDCard -Title 'Processing' -Content {
            New-UDProgress
        }
        
    } 
} -Title 'Learning PSU'```


avatar
(anonymous user)

Hi KST

You could take advantage of dynamic content, so that the bulk of your code is not triggered by the onsubmit and more importantly not being redirect to a different “page”.
Here is an example where a textbox will only appear when AllRequestInPolicy is checked (manually). Any other combination will not show that textbox/checkbox. You could apply the same logic to any other component.

New-UDPage -Name "AnotherOption" -Content {
    
    

    New-UDCard -Content {

        New-UDStack -Children {

            New-UDCheckBox -Label 'AllBookInPolicy' -OnChange {
                $Page:AllBookInPolicy = $EventData

            }
            New-UDCheckBox -Label 'AllRequestInPolicy' -OnChange {
                $Page:AllRequestInPolicy = $EventData
            }

        } -Direction row

        New-UDButton -Text "Submit" -OnClick {
                Sync-UDElement -id "MyDynamicContent"
            }

    }

    New-UDDynamic -Id "MyDynamicContent" -Content {
     
        New-UDCard -Content {

            If ($Page:AllBookInPolicy -eq $false -or [string]::IsNullOrEmpty($Page:AllBookInPolicy)) {

                Show-UDSnackbar -Message "AllBookInPolicy is False"

                If ($Page:AllRequestInPolicy -eq $true) {


                    Show-UDSnackbar -Message "AllRequestInPolicy is True"

                    # Only visible when RequestInPolicy is set to true when submitting
                    New-UDStack -Children {
                        New-UDCheckBox -Label "AllRequestInPolicy" -Checked $true
                        New-UDCheckBox -Label "AllBookInPolicy" -Checked $false
                    } -Direction row

                    New-UDTextbox -Label "mytextbox"
                }

            }

        
        }

    }
    
}