Dynamic containers on page load instead of onchange?

Dynamic containers on page load instead of onchange?

avatar
(anonymous user)
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

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"
                }

            }

        
        }

    }
    
}