Get-UDElement on custom component?

So @adam kindly pointed me to how to achieve allowing get-udelement on a custom component…except I cannot figure out or debug why this doesn’t work:-

 import React from 'react';
 import BeautyStars from 'beauty-stars';
 class <%=$PLASTER_PARAM_ControlName%> extends React.Component {
 
   // state is for keeping control state before or after changes.
   state = {
 //value: 0
   }
    constructor(props) {
         super(props);
 
         this.state = {
             value: 0
         }
     }
     onIncomingEvent(eventName, event) {
         if (event.type === "requestState") {
             UniversalDashboard.post(`/api/internal/component/element/sessionState/${event.requestId}`, {
                 attributes: {
                     value: this.state.value
                 }
             });
         }
   }
 
     onChanged(t) {
 
         this.setState({
             value: t.target.value
         });
 
         if (this.props.onChange == null) {
             return
         }
 
         var val = t.target.value;
 
         UniversalDashboard.publish('element-event', {
             type: "clientEvent",
             eventId: this.props.onChange,
             eventName: 'onChange',
             eventData: val.toString()
         });
     }
 
   render() {
       return (
       <BeautyStars
         value={this.state.value}
         onChange={value => this.setState({ value })}
       />
     );
 
   }
 }
 
 export default <%=$PLASTER_PARAM_ControlName%>

can you post new code example without all the plaster template things…

and i see your problem

Like this buddy? https://paste.ofcode.org/X5Azq2VeKDDvAccumJLBgE

import { useEffect, useState, useCallback } from "react";

const SET_STATE = "setState";
const REQUEST_STATE = "requestState";
const REMOVE_ELEMENT = "removeElement";
const ADD_ELEMENT = "addElement";
const CLEAR_ELEMENT = "clearElement";
const SYNC_ELEMENT = "syncElement";

export default function useDashboardEvent(elementId, initialState) {
  const { content, ...attributes } = initialState;

  const [state, setState] = useState({
    content: content,
    attributes: attributes
  });

  useEffect(() => {
    // console.log('UniversalDashboard Object: ', UniversalDashboard)
    // console.log("ud event hook: ", state);
    const pubSubToken = UniversalDashboard.subscribe(elementId, events);
    return () => UniversalDashboard.unsubscribe(pubSubToken);
  }, [elementId, initialState]);

  const events = useCallback(
    (msg, event) => {
      switch (event.type) {
        // Set-UDElement
        case SET_STATE:
          setState(state => {
            return {
              attributes: { ...state.attributes, ...event.state.attributes },
              content: event.state.content ? (Array.isArray(event.state.content) ? event.state.content : Array.from(event.state.content)) : []
            }
          });
          break;
        // Get-UDElement
        case REQUEST_STATE:
          UniversalDashboard.post(
            `/api/internal/component/element/sessionState/${event.requestId}`,
            { ...state }
          );
          break;
        // Add-UDElement
        case ADD_ELEMENT:
          setState(state => {
            return {
              ...state,
              content: state.content.concat(event.elements)
            };
          });
          break;
        // Remove-UDElement
        case REMOVE_ELEMENT:
          setState(state => {
            let newStateContent = state.content;
            newStateContent.splice(-1, 1);
            return {
              ...state,
              content: [...newStateContent]
            };
          });

          break;
        // Clear-UDElement
        case CLEAR_ELEMENT:
          setState(state => {
            return {
              ...state,
              content: []
            };
          });
          break;
        // Sync-UDElement
        case SYNC_ELEMENT:
          reload();
          break;
        // Just break
        default:
          break;
      }
    },
    [event]
  );

  const reload = useCallback(() => {
    UniversalDashboard.get(
      `/api/internal/component/element/${elementId}`,
      data =>
        setState(state => {
          return {
            ...state,
            content: data
          };
        })
    );
  }, [elementId]);

  return [state, reload, setState];
}

This is a custom react hook that i’ve created , it take care of all ud events so copy this content to new file

now the second step
in your component

add this line

import useDashboardEvent from "../Hooks/useDashboardEvent";

step 3 inside your component add thus lines

  const [state, reload] = useDashboardEvent(props.id, props);
  const { content, attributes } = state;

example code for onChange

  const onChange = event => {
    UniversalDashboard.publish("element-event", {
      type: "clientEvent",
      eventId: attributes.id + "onChange",
      eventName: "onChange",
      eventData: event
    });
  };

example of the switch component return

    <Switch
      {...attributes}
      {...customIcons}
      checked={checked}
      onChange={onChange}
    />
  );

Example of the full UDAntd Switch component

import React, { useState } from "react";
import { Switch } from "antd";
import useDashboardEvent from "../Hooks/useDashboardEvent";

const AntdSwitch = props => {
  const [state, reload] = useDashboardEvent(props.id, props);
  const { content, attributes } = state;
  const [checked, setChecked] = useState(attributes.checked)


  const onChange = event => {
    setChecked(!checked)
    UniversalDashboard.publish("element-event", {
      type: "clientEvent",
      eventId: attributes.id + "onChange",
      eventName: "onChange",
      eventData: event
    });
  };

  const customIcons = {
    checkedChildren: UniversalDashboard.renderComponent(attributes.checkedChildren),
    unCheckedChildren: UniversalDashboard.renderComponent(attributes.unCheckedChildren)
  }

  return (
    <Switch
      {...attributes}
      {...customIcons}
      checked={checked}
      onChange={onChange}
    />
  );
};

export default AntdSwitch;

the powershell command file look like this

function New-UDAntdSwitch {
    param(
        [Parameter()]
        [string]$Id = (New-Guid).ToString(),
        [Parameter()]
        [string]$ClassName,
        [Parameter()]
        [switch]$autoFocus,
        [Parameter()]
        [switch]$checked,
        [Parameter()]
        [object]$checkedChildren,
        [Parameter()]
        [switch]$defaultChecked,
        [Parameter()]
        [switch]$disabled,
        [Parameter()]
        [switch]$loading,
        [Parameter()]
        [ValidateSet("default","small","large")]
        [string]$size,
        [Parameter()]
        [object]$unCheckedChildren,
        [Parameter()]
        [object]$onChange,
        [Parameter()]
        [hashtable]$Style

    )

    End {

        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 ($null -ne $onChange) {
            if ($onChange -is [scriptblock]) {
                $onChange = New-UDEndpoint -Endpoint $onChange -Id ($Id + "onChange")
            }
            elseif ($onChange -isnot [UniversalDashboard.Models.Endpoint]) {
                throw "OnClick must be a script block or UDEndpoint"
            }
        }

        @{
            assetId = $AssetId 
            isPlugin = $true 
            type = "ud-antd-switch"
            id = $Id
            className = $ClassName
            autoFocus = $AutoFocus.IsPresent
            checked = $Checked.IsPresent
            checkedChildren = $CheckedChildren
            defaultChecked = $DefaultChecked.IsPresent
            disabled = $Disabled.IsPresent
            loading = $Loading.IsPresent
            size = $Size
            unCheckedChildren = $UnCheckedChildren
            # onChange = $OnChange
            # onClick = $OnClick
            style = $Style
        }

    }
}


2 Likes

Thanks @AlonGvili for sharing this code and explaining how to do this. It’s really, really appreciated as I only ask for help when I have tried all avenues I can think of, so to get a reply with an answer is great :smile: will make sure I review this and apply, as need to build this into all custom components essentially to get the most out of them interacting with universal dashboard?

2 Likes

Ok so I copied and pasted the custom hook you created into its own file, and saved that as “useDashboardEvent.jsx” in a folder called “Hooks” in the main component folder…then done the following in the script:-

import React from 'react';
import BeautyStars from 'beauty-stars';
import useDashboardEvent from "../Hooks/useDashboardEvent";
class <%=$PLASTER_PARAM_ControlName%> extends React.Component {
   constructor(props) {
    super(props);
    this.state = {
        value: 0
    }
}
  render() {
const [state, reload] = useDashboardEvent(props.id, props);
const { content, attributes } = state;
const onChange = event => {
  value => this.setState({ value })
UniversalDashboard.publish("element-event", {
  type: "clientEvent",
  eventId: attributes.id + "onChange",
  eventName: "onChange",
  eventData: event
});
  };
  return (
  <BeautyStars
    value={this.state.value}
      onChange={onChange}
  />
);

  }
}

export default <%=$PLASTER_PARAM_ControlName%>

But on the output of the build I get:-
Version: webpack 4.30.0
Time: 4243ms
Built at: 10/16/2019 10:18:37 PM
2 assets
Entrypoint index = index.0b520ba5aa6630172432.bundle.js index.0b520ba5aa6630172432.bundle.map
[3] ./components/index.js + 2 modules 7.62 KiB {0} [built]
| 3 modules
+ 3 hidden modules

ERROR in ./components/udstar.jsx
Module not found: Error: Can’t resolve ‘…/Hooks/useDashboardEvent’ in 'C:\ud\UDStar\udrate\src\components’
@ ./components/udstar.jsx 29:0-59 53:31-48
@ ./components/index.js
npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! udstar@1.1.1 build: webpack -p --env production
npm ERR! Exit status 2
npm ERR!
npm ERR! Failed at the udstar@1.1.1 build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\Adz\AppData\Roaming\npm-cache_logs\2019-10-16T21_18_37_309Z-debug.log
Copy-Item : Cannot find path ‘C:\ud\UDStar\udrate\src\public’ because it does not
exist.
At C:\ud\UDStar\udrate\src\build.ps1:21 char:1

  • Copy-Item $BuildFolder\public*.bundle.js $OutputPath

Can you add some baby steps for me please? :baby: :baby_bottle:

I did try quite a few other copy and paste into my component.jsx file from the code you kindly provided @AlonGvili , but the code I posted is the closet it got to building I could get :cry:

First you can NOT used react hooks inside a Class component only in functions


const AntdSwitch = props => {
  const [state, reload] = useDashboardEvent(props.id, props);
  const { content, attributes } = state;
  const [checked, setChecked] = useState(attributes.checked)


  const onChange = event => {
    setChecked(!checked)
    UniversalDashboard.publish("element-event", {
      type: "clientEvent",
      eventId: attributes.id + "onChange",
      eventName: "onChange",
      eventData: event
    });
  };

  const customIcons = {
    checkedChildren: UniversalDashboard.renderComponent(attributes.checkedChildren),
    unCheckedChildren: UniversalDashboard.renderComponent(attributes.unCheckedChildren)
  }

  return (
    <Switch
      {...attributes}
      {...customIcons}
      checked={checked}
      onChange={onChange}
    />
  );
};

export default AntdSwitch;

as you can see in this example code i use a function NOT a class

Second
if you file is in the same folder as the Hooks folder replace

import useDashboardEvent from "../Hooks/useDashboardEvent";

with

import useDashboardEvent from "./Hooks/useDashboardEvent";

Please create a github repo with all your code folders and files so i can help you

Many thanks again @AlonGvili I will upload this to github and let you know when on there. Will try and have a few more goes with the helpful information you provided

I created GH Repo of what i think is a good starting point to build custom control.
clone the repo see if this help you

1 Like

Sweet @AlonGvili. After your words of advice changed it from a class to a function and it built without errors. Which was great, but sadly I got a minified react error. It was half midnight by then so went to bed. I will make time today to look at this further help you have provided. Thanks again man means a lot

Thanks again man looking at this now…first build failed…so on to attempt 2 :smiley:

sorry man still struggling, I ended up opting for the original build method, as mentioned was getting some compiling errors…but with the new-found knowledge you gave me I came up with this:-
https://github.com/psDevUK/UDscripts/blob/master/udrate.jsx
but seems the this.onChanged.bind(this) is not quite working as removing that allows me to use the component, but I want to record what the current value is…help please…

Ok as not web developer, totally forgot to look at debugger in browser…Doh! saying e.target not defined…so guess thats why nothing is happening…will try your method again as bit baffled buy this…

I will create you a demo with your control, when I get back home

1 Like

Just to show my appreciation man I made you a special custom component myself tonight:-
alon
Old skool type-writer :slight_smile:

2 Likes

Love it!!! sooo coool

1 Like

I send you PR with the full source code for UDRate module

1 Like

Well I was getting all frustrated not being able to do the element support, so as you kindly said you would do me a PR which you did do, thought I need to show Alon how muchyou have inspired me. So this was the best I could come up with before I needed to get some sleep after a tough long week in the office.
I have just approved your PR whilst having my first cup of Yorskshire Tea for the day…will make sure I study and learn this, to then apply this same technique to other custom components.
Thanks again @AlonGvili

OMG only 25 lines of code! I was obviously over-complicating things…can you explain the setValue(newstar) like the newstar bit I don’t see that documented anywhere as an official property object. So is this a variable you create on the fly to describe what it is doing yeah?

Wow const [value, setValue] = useState(0) it’s all starting to click in my head how this all comes together :smiley:

const [value, setValue] = useState(0)
Its a react hook, instead of all the setState in a class component you just writing one line in the new react version

1 Like