Product: PowerShell Universal
Version: 2.5.5
Framework: 3.8.0
TL;DR: When I have a New-UDTable
with an -id
, wrapped in a New-UDDynamic
, the table does not reload/refresh when Sync-UDElement
is called on the Dynamic wrapper. When the -id
is omitted, it behaves as expected and reloads. Why does specifying the tableās ID change this behaviour?
Iāve bumped up against an issue and could do with some advice. Iāve come up with a work-around but it doesnāt really feel like how the framework should work - itās brittle and makes me feel icky! I want to make sure Iām not missing a trick.
Iāll outline the problem and them show how Iāve worked around it. Iāve put together a dummy dashboard to repro this. The dashboard itās a part of is more complex - but isnāt relevant to this issue.
Problem
I have a table of values that contains some data that I want the user to be able to select and perform some action on the selected rows. That action can affect the underlying data in the table so once the user has performed the action - the table needs to be reloaded. As the user selects the row items - the intent of the action needs to be made clear to them.
Iām doing this with a table that has selectable rows. On selection the table tells the button to refresh - everytime the button refreshes, it gets the table element and checks how many selected rows it has. It displays the appropriate text / disables itself as required.
Should be a simple one - a New-UDButton
inside a New-UDDynamic
and a New-UDTable
inside a New-UDDynamic
.
New-UDDashboard -Title "š or š„" -Content {
# Button needs to be wrapped in a dynamic along with logic to work out
# a) is the button enabled
# b) what text to show the user
New-UDDynamic -Id 'DynButton' -Content {
# From the table, get the number of selected rows.
# Assume if we fail to get the table element it may not be loaded yet
# and so nothing can be selected.
$SelectedRows = try {
(Get-UDElement -Id 'Table' -ErrorAction Stop).'selectedRows'
} catch {
@()
}
# Decide, based on the number of selected rows, what the text of the
# button will read.
$NumSel = ($SelectedRows | Measure-Object).Count
if ($NumSel -eq 10) {
$NumSel = 'All'
}
$ButtonText = switch ($NumSel) {
0 { 'Nothing Selected' }
1 { '1 Item Selected' }
Default { "$NumSel Items Selected" }
}
New-UDButton -Text $ButtonText -OnClick {
# This is a placeholder for manipulating the selected rows in some
# way. Think - interacting with a Database.
$SelRows = (Get-UDElement -Id 'Table' -ErrorAction Stop).'selectedRows'
Show-UDToast "$(
($SelRows | Measure-Object).Count
) rows selected. Their sum is $(
($SelRows | Select-Object -Expand Randos | Measure-Object -Sum).Sum
)"
# The underlying data for the table may have changed so reload the
# table.
Sync-UDElement -Id 'DynTable'
} -Disabled:($NumSel -eq 0)
}
# Table needs to be dynamic
New-UDDynamic -Id 'DynTable' {
New-UDTable -Id 'Table' -LoadData {
# This part is unimportant. Just showing 10 random numbers here so
# it's very obvious when the table has reloaded.
$TableData = ConvertFrom-Json $Body
Get-Random -Count 10 | ForEach-Object {
@{
'Randos' = $_
}
} | Out-UDTableData -Total 10 -Page 0 -Properties $TableData.Properties
} -COlumns @(
New-UDTableColumn -Property 'Randos'
) -ShowSelection -OnRowSelection {
# When a row is selected/unselected - refresh the button
Sync-UDElement -Id 'DynButton'
}
}
}
The table is able to refresh the button when rows are selected/unselected and the button is able to get the selected rows of the table just fine.
The issue is that the table does not refresh. No call to Sync-UDElement
aimed a table with an ID or itās parent New-UDDynamic
will cause said table to refresh. Any other content inside the Dynamic is re-executed as expected.
If I remove the -id
from the table (and in the example code - change the button logic so the button is enabled) - the table refreshes when Sync-UDElement
is called on the New-UDDynamic
. This, however, means I cannot use Get-UDElement
to get the selected rows of the table (as I donāt know itās -Id
).
I can either have:
- The table with an ID and row selection enables the button - but the button canāt refresh the table.
or
- The table with No ID - is hypothetically refreshable. Rows can be selected but the button canāt find the table so stays at 'Nothing Selected`
Workaround
The workaround came about when I saw that New-UDElements
return their content when you Get-UDElement
on them. I remove the ID from the table and
basically replace the New-UDDynamic
wrapping the table with a New-UDElement
. Then in the button I first call Get-UDElement
on the tableās parent element. Then I get the id
of the first child in the content property and call Get-UDElement
on that. If the order of itās children changes - this workaround would break.
New-UDDashboard -Title "š or š„" -Content {
# Button needs to be wrapped in a dynamic along with logic to work out
# a) is the button enabled
# b) what text to show the user
New-UDDynamic -Id 'DynButton' -Content {
# From the table, get the number of selected rows.
# Assume if we fail to get the table element it may not be loaded yet
# and so nothing can be selected.
$SelectedRows = try {
Get-UDElement -Id $((Get-UDElement -Id 'DynTable').Content.Id) -ErrorAction Stop | Select-Object -ExpandProperty 'selectedRows' -ErrorAction Stop
} catch {
@()
}
# Decide, based on the number of selected rows, what the text of the
# button will read.
$NumSel = ($SelectedRows | Measure-Object).Count
if ($NumSel -eq 10) {
$NumSel = 'All'
}
$ButtonText = switch ($NumSel) {
0 { 'Nothing Selected' }
1 { '1 Item Selected' }
Default { "$NumSel Items Selected" }
}
New-UDButton -Text $ButtonText -OnClick {
# This is a placeholder for manipulating the selected rows in some
# way. Think - interacting with a Database.
$SelRows = try {
Get-UDElement -Id $((Get-UDElement -Id 'DynTable').Content.Id) -ErrorAction Stop | Select-Object -ExpandProperty 'selectedRows' -ErrorAction Stop
} catch {
@()
}
Show-UDToast "$(
($SelRows | Measure-Object).Count
) rows selected. Their sum is $(
($SelRows | Select-Object -Expand Randos | Measure-Object -Sum).Sum
)"
# The underlying data for the table may have changed so reload the
# table.
Sync-UDElement -Id 'DynTable'
Sync-UDElement -Id 'DynButton'
} -Disabled:($NumSel -eq 0)
}
# Table needs to be dynamic
New-UDElement -Tag 'div' -Id 'DynTable' -Endpoint {
New-UDTable -LoadData {
# This part is unimportant. Just showing 10 random numbers here so
# it's very obvious when the table has reloaded.
$TableData = ConvertFrom-Json $Body
Get-Random -Count 10 | ForEach-Object {
@{
'Randos' = $_
}
} | Out-UDTableData -Total 10 -Page 0 -Properties $TableData.Properties
} -COlumns @(
New-UDTableColumn -Property 'Randos'
) -ShowSelection -OnRowSelection {
# When a row is selected/unselected - refresh the button
Sync-UDElement -Id 'DynButton'
}
}
}
Note: There was a gif here similar to above but showing the above workaround code working - Iām a new user so can only have one embedded image per post
Any advice appreciated - thanks in advance