Creating forms and validating forms, what is best practice?

Product: PowerShell Universal
Version: 5.1.0

I apologize in advance for the long text, there is just no way i can ask the question without going over my issue.

I have been studying Powershell Universal for a few weeks. Below are basically my notes during my study. Now my issue is with Forms and Form validations.
You can do this in different ways.

TL;DR What is the best way to 1) create a form and 2) to validate it

First, lets go over my understanding of forms within PSU.

Forms in PSU

It looks like there are 2 methods/ways to create a form, one gives more control than the other.

Method 1 : New-UDForm

  • New-UDForm → seems to create a submit button that we cannot really manage all that well (disabling seems an issue). In previous versions of PSU this was know as New-UDInput.
New-UDForm -Content {
    New-UDTextbox -Id 'txtTextField'
    New-UDCheckbox -Id 'chkCheckbox'
} -OnSubmit {
    Show-UDToast -Message $EventData.txtTextField
    Show-UDToast -Message $EventData.chkCheckbox
}

The -OnSubmit automatically adds a submit button.

This is great for easy forms but harder to do when you want to control the submit button (e.g with validation rules).

Method 2 : Manually build your form

New-UDApp -Content { 
    New-UDCard -Title "Create Shared Mailbox" -Content {
        New-UDSelect -Id 'selectOU' -Label 'OU' -Option {
            New-UDSelectOption -Name 'CMMC' -Value 'CMMC'
            New-UDSelectOption -Name 'CM' -Value 'CM'
            New-UDSelectOption -Name 'MC' -Value 'MC'
        }
        New-UDTextbox -Id 'txtDisplayName' -Label 'Display Name' -Placeholder 'Enter Display Name'
            
        New-UDButton -Id 'SubmitButton' -Text 'Submit' -OnClick {
            $OU = (Get-UDElement -Id 'selectOU').value
            $DisplayName = (Get-UDElement -Id 'txtDisplayName').value

            if ($OU -and $DisplayName)
            {
                Show-UDToast -Message "OU: $OU, Display Name: $DisplayName" -Duration 4000
            }
            else
            {
                Show-UDToast -Message "Please fill in all fields!" -Severity error
            }
        }
    }
}

This is its most basic form and looks like:

$Eventdata

When you use the 1st method, $EventData is available for you to use.
​This doesn’t seem to be the case when you manually build the form.
​You then have to capture your individual components, based on their ID.

E.g $OU = (Get-UDElement -Id 'selectOU').value

Validating forms

You can do it in 2 ways.

1) Validation at (input)-field level

New-UDColumn -Size 2 -Content {
    New-UDTextbox -Id 'txtDisplayName' -Label 'Displayname' -Placeholder 'CM - Koerswedstrijd De zeven kamp' -HelperText 'Please respect naming conventions' -OnValidate {
        # Only validate if there's actual input
        if ($Eventdata) { if ($Eventdata -notmatch '\w+ - \w+') { New-UDValidationResult -ValidationError '*Displayname does not contain a space.' } else { New-UDValidationResult -Valid } } else { New-UDValidationResult -Valid }
    } -OnChange {
        Sync-UDElement -Id 'dynamicContent'
    } 
}

It is my understanding that #$Eventdata in this case seems to function like $this.
​If this filed has data, … .

If a #New-UDValidationResult-ValidationErrorgets created, the submit button gets disabled automatically.

A similar approach would be:

New-UDForm -Content {
    New-UDTextbox -Id 'txtUPN' -Label 'UserPrincipalName' -Placeholder 'UPN'
} -OnValidate {
    $UPN = (Get-UDElement -Id 'txtUPN').value -replace '\s', ''
    
    # Only validate if there's actual input
    if (-not [string]::IsNullOrWhiteSpace($UPN)) {
        $Exists = get-aduser -Filter { UserPrincipalName -like $UPN }
        
        if ($Exists) {
            New-UDValidationResult -ValidationError "*$($Exists.Name) already exists"
            return $false  # Prevent form submission
        }
    }
    
    New-UDValidationResult -Valid   # Allow submission when no input or no existing user
} -OnSubmit {
    # Your submission logic here
}

The problem with this approach is that if you have 2 validations on 2 individual fields, they will undo the validation of the other.

  • You check the UPN and another field, both fail so the submit button is disabled.

  • You change the UPN to get passed the check, the button enables.

    → Wrong because all validation rules haven’t been met yet! Our OtherField is still NOK.

2) Validation (before) submit on the entire form level


This works in a similar way. The error message however, is no longer displayed inline but just above the submit button.


We can get inline error mesages like this.

**

The problem now is, the validation check is not reliable. Sometimes it disables it but on other occasions it doesn’t (even though it should) and vice versa.

**



New-UDForm -Content {
    New-UDTextbox -Id 'txtUPN' -Label 'UserPrincipalName' -Placeholder 'UPN'
    New-UDTextbox -Id 'txtOtherField' -Label 'Other Field' -Placeholder 'Other Input'
} -OnValidate {
    $validationResults = @()
    
    # Validate UPN
    $UPN = (Get-UDElement -Id 'txtUPN').value -replace '\s', ''
    if (-not [string]::IsNullOrWhiteSpace($UPN)) {
        $Exists = get-aduser -Filter { UserPrincipalName -like $UPN }
        
        if ($Exists) {
            $validationResults += (New-UDValidationResult -ValidationError "*$($Exists.Name) already exists")
        }
    }
    
    # Validate Other Field
    $OtherField = (Get-UDElement -Id 'txtOtherField').value -replace '\s', ''
    # Add your specific validation for the other field here
    if ($OtherField -eq 'jef') {
        $validationResults += (New-UDValidationResult -ValidationError "Other field cannot be 'jef'")
    }

    # If any validation errors, return false and show errors
    if ($validationResults.Count -gt 0) {
        # This is the key change - passing all collected validation results
        return $validationResults
    }
    
    # If no errors, return valid
    New-UDValidationResult -Valid
    return $true
} -OnSubmit {
    # Your submission logic here
}
}

New-UDPage -Url "/CreateSharedMailbox" -Name "CreateSharedMailbox" -Content {
New-UDForm -Content {
    New-UDTextbox -Id 'txtUPN' -Label 'UserPrincipalName' -Placeholder 'UPN' -OnValidate {
        $UPN = (Get-UDElement -Id 'txtUPN').value -replace '\s', ''

        # Only validate if there's actual input
            $Exists = get-aduser -Filter { UserPrincipalName -like $UPN }

            if ($Exists) {
                New-UDValidationResult -ValidationError "*$($Exists.Name) already exists"
                return $false  # Prevent form submission
            }else{return $true}
        
        
        
    }

    New-UDTextbox -Id 'txtOtherField' -Label 'Other Field' -Placeholder 'Other Input' -OnValidate {
        # Validate Other Field
        $OtherField = (Get-UDElement -Id 'txtOtherField').value -replace '\s', ''
        if ($OtherField -eq 'jef') {
            New-UDValidationResult -ValidationError "Other field cannot be 'jef'"
            return $false  # Prevent form submission
        }else{return $true}
        
    }
} -OnValidate {
    # Aggregate validation from individual fields
    $UPNElement = Get-UDElement -Id 'txtUPN'
    $OtherFieldElement = Get-UDElement -Id 'txtOtherField'

    # Check if either field has a validation error
    if ($UPNElement.ValidationError -or $OtherFieldElement.ValidationError) {
        return $false
    }else{

        New-UDValidationResult -Valid
        return $true
    }
    
} -OnSubmit {
    # Your submission logic here
}
}

Notes

The OnValidate on the form level, seems to be triggered during onPageLoad and on the onChangeevent of every individual field.

Since the validation gets triggered when the page gets loaded, it is important to prevent error messages from showing in this initial stage.

Seriously, i am the only one that has these questions?