Calling Function to Retrieve System Resources in Component JavaScript

Hi everyone,

I'm currently working on an Ignition Perspective component, and I need to call a function that retrieves some system resources, like a list of tags or historical values of a specific tag, directly from within the component's JavaScript.

Here’s a simplified version of my code:

export class Something extends Component<ComponentProps<MyProps>, any> {

    render() {
        const { props: { something }, position, emit } = this.props;
        const tagList = getTagList("my provider");  // This is where I'm stuck
    }
}

I’d like to know the recommended way to:

  • Call a function to retrieve the list of tags from a specific provider.
  • Access historical values of a specific tag within the component’s JavaScript.

If anyone could provide an example or point me to relevant documentation, it would be greatly appreciated!

Thanks in advance!

You would use a ComponentStoreDelegate for this I believe.

Delegate Code
export class AssetSelectorGatewayDelegate extends ComponentStoreDelegate{
  private handleUpdateAssets: React.Dispatch<React.SetStateAction<Array<Asset> | null | undefined>>
  
  constructor(componentStore: AbstractUIElementStore) {
    super(componentStore);
}

  init(updateAssets:React.Dispatch<React.SetStateAction<Array<Asset> | null | undefined>>):void{
    this.handleUpdateAssets = updateAssets;
  }
  handleEvent(eventName: string, eventObject: JsObject): void {
    if(eventName === "assetReturn"){
      this.handleUpdateAssets((eventObject.assets as Array<any>).map((e)=>(e as Asset)));
    }
  }

  fetchAssets(datasource:string){
    console.log(datasource)
    this.fireEvent("getAssets",{datasource:datasource});
    this.notify();
  }

Inside of your actual component you can access the delegate via props.strore.delegate

  React.useEffect(() => {
    (props.store.delegate! as AssetSelectorGatewayDelegate).init(setLocalAssets);
  }, []);

  React.useEffect(() => {
    if (props.props.datasource) {
      (props.store.delegate! as AssetSelectorGatewayDelegate).fetchAssets(props.props.datasource);
    }
  }, [props.props.datasource]);

Make sure to update your Meta as well

Meta
export class AssetSelectorMeta implements ComponentMeta {
    isDeepSelectable = true;
    getComponentType(): string {
        return COMPONENT_TYPE;
    }

    // the class or React Type that this component provides
    getViewComponent(): PComponent {
        return AssetSelector;
    }

    getDefaultSize(): SizeObject {
        return ({
            width: 360,
            height: 360
        });
    }


    createDelegate(component: AbstractUIElementStore): ComponentStoreDelegate | undefined {
        return new AssetSelectorGatewayDelegate(component);
    }
    // Invoked when an update to the PropertyTree has occurred,
    // effectively mapping the state of the tree to component props.
    getPropsReducer(tree: PropertyTree): AssetSelectorProps {
        return {
          assets :tree.readArray("assets",[]),
          datasource:tree.readString("datasource",""),
          selectedAsset:tree.readObject("selectedAsset",undefined),
          titleStyle:tree.readObject("titleStyle",{}),
          refreshAssets:tree.readBoolean("refreshAssets",false)
        };
    }
}

The other option is to pass information via the prop tree from bindings made by a user. This might work better if you are wanting something more dynamic. receive an array of tagPaths or history provider paths via props.tagPaths then that would put the work on the binding rather than a possibly convoluted delegate lifecycle.

Without knowing more about what you are trying to accomplish that is all I have.

Hi Benjamin,

I'm kind of new to React and haven't fully immersed myself in useEffect yet. I can see how it might help, but it's still a bit challenging for me to fully understand it without trying it out.

Just to clarify, could you confirm if this approach would allow me to accomplish the following?

I want to call the system.tag.browse() function directly from within the component (using parameters generated at runtime within the component itself) and then collect the results for use within the component. It’s not as simple as collecting the tags and passing them down via props.

I also have some other scenarios in mind, such as calling system.tag.queryTagHistory(paramsFromComponentReact), where the parameters would be dynamically generated by the React component logic. I would then need to process the retrieved historical data and plot the results within the component, potentially updating the chart in real-time as the parameters change.

Thanks again for your help!

useEffect is a react hook that runs a function based on state changes.

the useEffect with [] as the dependency runs on the initial render.

In terms of calling the functions that would happen within your delegate in the java side and return json to the react component.

I don't have the time to give you a full end to end example right now, but you should be able to look at the SDK Example and see how it is using delegates.

1 Like

I'll note for posterity a couple things here:
First, from Java code in a module, you're not going to be calling system functions directly, you're going to have to use Java types and call SDK methods directly. Start from the GatewayContext that is delivered to your module in its setup function call and explore the various "managers" of different subsystems.

Second, it's often (though not always) an antipattern to "hard code" in logic like querying history/browsing tags/etc into a component. Inevitably, your component won't be quite doing the right thing, where it's often a better idea to have your component just be a "dumb" display of whatever data it's given, and have the source of that data be something that end users can provide their own binding or scripting or whatever logic for in the Designer.

3 Likes