Custom button component that used to work with ver 2.9.0 wont work on v3

Product: PowerShell Universal
Version: 1.5.9

@adam

i have a custom button build for v.2.9.0 before and used to work perfect but trying it with V3 it shows up and everything except properties wont make it to onclick script block.
like data from column like $EvenetData.Name will be null inside onclick {}

my custom button used to use this line in the script

if ($null -ne $OnClick) {
            if ($OnClick -is [scriptblock]) {
                $OnClick = New-UDEndpoint -Endpoint $OnClick -Id ($Id + "onClick") 
                
            }
            elseif ($OnClick -isnot [UniversalDashboard.Models.Endpoint]) {
                throw "OnClick must be a script block or UDEndpoint"
            }
        }

hot to modify above for this custom button to work again.

Thank you.

by default we register the OnClick endpoint i don’t think you can register it again

what you try to achieve with this code ?

@AlonGvili
so in this case how to rebuild that component to work with psu?

@AlonGvili
This is a button with busy toggle so when you click it it starts spinning and become unclickable until the job is done

@AlonGvili
my issue with it is $eventdata.name become empty string inside the onclick scriptblock{}

let me test this and get back to you

@AlonGvili just fyi , below is my .jsx code

import React from 'react';
import ButtonLoader from 'react_button_loader';
import UdIcon from './ud-icon';

export default class UDButtonLoader extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            toggleloader: false,
            icon: this.props.icon,
            text: this.props.text,
            disabled: this.props.disabled,
            hidden: this.props.hidden,
            style: this.props.style
        }
    }

    onClick() {
        if (this.props.onClick) {
            this.setState({toggleLoader: true});
		    UniversalDashboard.get(`/api/internal/component/element/${this.props.id + "onClick"}`,function(json){
                if (json.error) {
                    this.setState({
                        hasError: true,
                        errorMessage: json.error.message,
                        toggleLoader: false
                    })
                } else {
                    this.setState({
                        hasError: false,
                        toggleLoader: false
                    });
                }
            }.bind(this));
            UniversalDashboard.publish({
                type: "clientEvent",
                eventId: this.props.onClick,
                eventName: 'onChange',
                eventData: ''
            });
        }
      
    }

    onIncomingEvent(eventName, event) {
        if (event.type === "requestState") {
            var data = {
                attributes: this.state
            }
            UniversalDashboard.post(`/api/internal/component/element/sessionState/${event.requestId}`, data);

        }
        else if (event.type === "setState") {
            this.setState(event.state.attributes);
        }
        else if (event.type === "clearElement") {
            this.setState({
                content: null
            });
        }
        else if (event.type === "removeElement") {
            this.setState({
                hidden:true
            });
        }
    }

    componentWillMount() {
        this.pubSubToken = UniversalDashboard.subscribe(this.props.id, this.onIncomingEvent.bind(this));
    }

    componentWillUnmount() {
        UniversalDashboard.unsubscribe(this.pubSubToken);
    }

    render() {
        if(this.state.hidden) {
            return null;
        }

        var icon = null;
        if (this.state.icon) {
            icon = <UdIcon icon={this.state.icon} style={{marginRight: this.state.floating || !this.state.text ? 'unset' : '5px'}}/>
        }

        return <ButtonLoader
                    className="ud-buttonloader"
                    onClick={this.onClick.bind(this)}
                    id={this.props.id}
                    isLoading={this.state.toggleLoader}
                    disabled={this.state.disabled}
                    loaderType= 'jiggling-lines'
                    style={this.state.style}
					background={this.props.background}
                >
                    {icon}
                    {this.state.text}
                </ButtonLoader>
    }
}

image

New-UDButton -Id ‘long_job’ -Text “Long Job” -OnClick {

Set-UDElement -Id 'long_job' -Properties @{

    Text = 'Working...'

    Disabled = $true

}

Start-Sleep 8

Set-UDElement -Id 'long_job' -Properties @{

    Text = "Long Job"

    Disabled = $false

}

}

the start-sleep is the place for your long job running

@AlonGvili
is there a way to build the component i posted for psu ?

it should work but i need your source code for the ps1 and jsx
if it’s ok with you open github repo so i can clone

@AlonGvili

i have posted the .jsx code above and below is the .ps1 script

function New-UDButtonLoader {
    param(
        [Parameter()]
        [string]$Id = ([Guid]::NewGuid()),
        [Parameter()]
        $Text,
        [Parameter()]
        [Switch]$isLoading,
        [Parameter()]
        [UniversalDashboard.Models.FontAwesomeIcons]$Icon,
        [Parameter()]
        [ValidateSet('left', 'right')]
        [String]$IconAlignment = 'left',
        [Parameter()]
        [object]$onClick,
        [Parameter()]
        [String]$BackgroundColor,
        [Parameter()]
        [string]$loaderType,
        [Parameter()]
        [Switch]$disabled     
    )

    if ($null -ne $OnClick) {
            if ($OnClick -is [scriptblock]) {
                $OnClick = New-UDEndpoint -Endpoint $OnClick -Id ($Id + "onClick") 
                
            }
            elseif ($OnClick -isnot [UniversalDashboard.Models.Endpoint]) {
                throw "OnClick must be a script block or UDEndpoint"
            }
        }

        

        if ($PSBoundParameters.ContainsKey("Icon")) {
            $IconName = [UniversalDashboard.Models.FontAwesomeIconsExtensions]::GetIconName($Icon)
        }

    

        @{
            # The AssetID of the main JS File
            assetId = $AssetId 
            # Tell UD this is a plugin
            isPlugin = $true 
            # This ID must be the same as the one used in the JavaScript to register the control with UD
            type = "ud-buttonloader"
            # An ID is mandatory 
            id = $Id

            # This is where you can put any other properties. They are passed to the React control's props
            # The keys are case-sensitive in JS. 
            text = $Text
            icon = $IconName
            iconAlignment = $IconAlignment           
            isLoading = $isLoading
            disabled = $disabled.IsPresent
            loaderType = $loaderType
            onClick = $onClick.Name
            background = $BackgroundColor
        }

    }

thank you very much

thanks it’s going to take some time i have others things to fix befor i can work on this ok ?

BTW do you see some error in the browser console ?

NP i really appreciate your help am just struggling to find out why the $eventdata.name does not make it to the scriptblock of onclick.

i think building this component will be very helpful for everyone since it works great on v2 before but has this issue on v3.

Thanks again.

1 Like

image

@AlonGvili
Just FYI i have tried the Chip element built-in PSU and the same behavior, if you build a table with a chip for every object and tried to use the chip -onclick {} the eventdata.property ex. “$EventData.Name” will be null.

try do like we do in the UDButton

    in the param => replace [object] with [Endpoint]

    [Parameter (Position = 7)]
    [Endpoint]$OnClick,

in the function body
replace this

    if ($null -ne $OnClick) {
        if ($OnClick -is [scriptblock]) {
            $OnClick = New-UDEndpoint -Endpoint $OnClick -Id ($Id + "onClick")
        }
        elseif ($OnClick -isnot [UniversalDashboard.Models.Endpoint]) {
            throw "OnClick must be a script block or UDEndpoint"
        }
    }

with this
if ($OnClick)
{
$OnClick.Register($Id, $PSCmdlet)
}

also
you need to add this import statement in your component
import { withComponentFeatures } from ‘universal-dashboard’

in your package.json add this under dependencies “universal-dashboard”: “1.0.3”

and in your component do this for the onclick event
const handleClick = () => {

if (props.onClick == null) return

props.onClick();

}

and for the last thing
export default withComponentFeatures(you component)

1 Like

we need to update some components to work like the button the chip is one of them

@AlonGvili
but what about the event when you click the button i mean the toggleloader and the get status from the api after you click the button so you know the job is done and the button go back to normal?

am referencing this section

onClick() {
        if (this.props.onClick) {
            this.setState({toggleLoader: true});
		    UniversalDashboard.get(`/api/internal/component/element/${this.props.id + "onClick"}`,function(json){
                if (json.error) {
                    this.setState({
                        hasError: true,
                        errorMessage: json.error.message,
                        toggleLoader: false
                    })
                } else {
                    this.setState({
                        hasError: false,
                        toggleLoader: false
                    });
                }
            }.bind(this));
            UniversalDashboard.publish({
                type: "clientEvent",
                eventId: this.props.onClick,
                eventName: 'onChange',
                eventData: ''
            });
        }
      
    }