# Perspective Component

**URL:** <https://forum.inductiveautomation.com/t/perspective-component/98768>\
**Category:** Module Development\
**Tags:** ignition81, database, perspective\
**Created:** [November 19, 2024, 7:02am UTC](https://forum.inductiveautomation.com/t/perspective-component/98768 "2024-11-19T07:02:54Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![Grace\_Gan](https://avatars.discourse-cdn.com/v4/letter/g/e5b9ba/32.png) [@Grace\_Gan](https://forum.inductiveautomation.com/u/Grace_Gan)\
**Post date:** [November 19, 2024, 7:02am UTC](https://forum.inductiveautomation.com/t/perspective-component/98768/1 "2024-11-19T07:02:54Z")

</div>

I'm new to ignition module development and I would like to know if it is possible to build a module that create and register custom perspective components to the designer. Would appreciate pointers into the right directions in any ways as I've struggling to find the useful resource or examples.

I would like to have a custom perspective components that display data which is obtained from querying the database. From my understanding we can bind a property to database query via query binding with named query and ignition handles that nicely. However, named query seems to be project scoped, which means I'd have to create the query for each project. Is there a way to have a query that is available across all project that can be used to bind to a component's property?

Ideally, I would like the component to have its data property to default to the query binding and select a default query, and the query will have params to it which may alter data returned (data format still same). Any idea if this will be possible?

I'm not sure if doing this via property data binding is a good idea, or if they should be done within the perspective component. Any help would be appreciated. Thanks in advanced

---

<div class="post-metadata">

**Author:** ![Transistor](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/transistor/32/3380_2.png) [@Transistor](https://forum.inductiveautomation.com/u/Transistor)\
**Post date:** [November 19, 2024, 9:30am UTC](https://forum.inductiveautomation.com/t/perspective-component/98768/2 "2024-11-19T09:30:54Z")

</div>

Are you sure you can't just use [Query Tags](https://www.docs.inductiveautomation.com/docs/8.1/platform/tags/types-of-tags#query-tags)?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [November 19, 2024, 1:31pm UTC](https://forum.inductiveautomation.com/t/perspective-component/98768/3 "2024-11-19T13:31:52Z")

</div>

Use project inheritance. Define your named query in an inheritable project and have your various UI projects inherit from that. In my recommended hierarchy, that would be in the `perspective_common` project:

> [@Where do/should Gateway Scripts live with respect to an inherited project structure?](https://forum.inductiveautomation.com/t/where-do-should-gateway-scripts-live-with-respect-to-an-inherited-project-structure/83460/3):
>
> Put all of the logic in project library scripts, in the "universe" project at the root of your hierarchy, if you must. Then, in leaf projects, use one-line calls to the appropriate logic from event scripts and message handlers. (I don't agree with your desire, but this is what you must do to achieve it.) I recommend you not put all your scripts (eggs) in one inheritable project (basket). I recommend a hierarchy something like this: universe ├bg\_common │├gsp │├background1 │├background2 │└we…

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [November 19, 2024, 4:31pm UTC](https://forum.inductiveautomation.com/t/perspective-component/98768/4 "2024-11-19T16:31:46Z")

</div>

Project inheritance is definitely the simplest option here, not requiring a custom module at all.

If you _do_ decide to go with a custom module, I would skip the custom component that's pre-registered with a default binding, and just register a custom binding type in your module.

---

<div class="post-metadata">

**Author:** ![Grace\_Gan](https://avatars.discourse-cdn.com/v4/letter/g/e5b9ba/32.png) [@Grace\_Gan](https://forum.inductiveautomation.com/u/Grace_Gan)\
**Post date:** [November 19, 2024, 7:10pm UTC](https://forum.inductiveautomation.com/t/perspective-component/98768/5 "2024-11-19T19:10:56Z")

</div>

I want to build a custom perspective component and make it available under "Perspective Components" in the Designer for users to add into their views. And the only way I see this from happening is through building a module. Correct me if I am wrong here.

I don't quite get what you mean by register a custom binding type in your module, could you explain further on this?

Essentially I'll have data in the database (connected from gateway) that I want the component to query from and display the data. And I want to abstract away the query (or make it reusable across projects) so that when the user wants to use the component, they won't have to worry about the query details, they just need to pass in a few parameters to the query and that's it.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [November 19, 2024, 7:45pm UTC](https://forum.inductiveautomation.com/t/perspective-component/98768/6 "2024-11-19T19:45:26Z")

</div>

> [@Grace\_Gan](#):
>
> they won't have to worry about the query details

Ignition's query bindings are extraordinarily flexible. If you really want users to not worry about the behavior of the query inside your component, do not put the query inside your component.

You are re-inventing the wheel. You are unlikely to do this as well as IA already did, with query bindings. Really. Don't have your component run its own queries.

IA has some components that run their own queries. They are frustrating to use and utterly inflexible. Don't follow that example.

---

<div class="post-metadata">

**Author:** ![Grace\_Gan](https://avatars.discourse-cdn.com/v4/letter/g/e5b9ba/32.png) [@Grace\_Gan](https://forum.inductiveautomation.com/u/Grace_Gan)\
**Post date:** [November 19, 2024, 8:18pm UTC](https://forum.inductiveautomation.com/t/perspective-component/98768/7 "2024-11-19T20:18:53Z")

</div>

Is your suggestion to just have the custom component that have properties in the desired format, and when using the component, user can use query binding to get the data? Although this seems to be nice, I don't see how this abstracts away the query from the user. Perhaps I can have a named query that gets created by the module in a inheritable project and ensure all project inherits it? Then user can just select the custom component and select the named query for query binding? It just worries me that the module cannot ensure the named query exists.

I've been looking at the [ignition-sdk-examples for perspective components](https://github.com/inductiveautomation/ignition-sdk-examples/tree/master/perspective-component). It looks like with the tag counter it is fetching data from a endpoint hosted on the gateway. This seems like another approach to get data from the database (via the endpoint hosted in gateway which I'm guessing can query the database) and display the data in the component. I will still need property as input to the component to select certain fields, for e.g., a machine id, and i can pass that to the endpoint to filter data being returned. Will this be a recommended approach?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [November 19, 2024, 8:22pm UTC](https://forum.inductiveautomation.com/t/perspective-component/98768/8 "2024-11-19T20:22:33Z")

</div>

> [@Grace\_Gan](#):
>
> just have the custom component that have properties in the desired format,

Yes.

> [@Grace\_Gan](#):
>
> abstracts away the query from the user

It doesn't. That would be the **opposite** of flexibility.

> [@Grace\_Gan](#):
>
> named query that gets created by the module

Maybe. Or just publish the suggested named query in the documentation for your component, and let the user customize it from there.

(You were planning to include documentation, I hope.)

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [November 19, 2024, 9:26pm UTC](https://forum.inductiveautomation.com/t/perspective-component/98768/9 "2024-11-19T21:26:16Z")

</div>

> [@Grace\_Gan](#):
>
> I don't quite get what you mean by register a custom binding type in your module, could you explain further on this?

Perspective fully supports registration of additional binding types by modules. That is, the 'Tag', 'HTTP', 'Expression', etc binding types - are just registered artifacts. So you can register your own binding type, with its own customization UI and whatever parameters make sense for it, with Perspective, and from your end user's perspective (🕶) it just looks like a native part of the product.

Exposing simple properties and running your own code in the backend is also absolutely an option - but Phil and I share the view that this limits your component's flexibility to detrimental effect.

In other words:  
If you define a custom component that also does its own data fetching, you are tightly coupling your _data model_ and your _presentation model_.  
Compare/contrast Perspective's Table component and the Alarm Status Table component. The former is only \[1\] concerned with displaying _some kind_ of data, and has huge support for customization and flexibility. The latter is only concerned with _one_ kind of data, and thus _can only_ do one thing, and also doesn't have support for the same amount of customization because it's always _one piece_; it's not assembled out of component pieces.

This is, ultimately, more of a **philosophical** argument than a strict technical one. You absolutely don't have to follow what Phil and I are saying here - as I just said, even Inductive doesn't follow this advice consistently. But _in general_, especially given what you've described so far, I would _not_ want to go the custom component route. Only if you have a new _fundamental_ building block that can't be composed out of our existing "primitive"s would I reach that far.

* * *

1. mostly

---

<div class="post-metadata">

**Author:** ![Grace\_Gan](https://avatars.discourse-cdn.com/v4/letter/g/e5b9ba/32.png) [@Grace\_Gan](https://forum.inductiveautomation.com/u/Grace_Gan)\
**Post date:** [November 19, 2024, 9:58pm UTC](https://forum.inductiveautomation.com/t/perspective-component/98768/10 "2024-11-19T21:58:50Z")

</div>

Thanks for your response, that all make sense.

What I'm trying to build is in fact a component that is only concern with one kind of data.

As for background context, I'll have the gateway connected to a database (postgres) with tables and data that I'm interested in. In the designer, I want a custom component that handles the data querying logic behind the scene. It does need some simple property as input that will be passed to the query as params to filter the data. I'm aware that this isn't a recommended approach in terms of flexibility of the component but it make sense for what I'm trying to build here.

My questions now turns into if it is possible to build a custom component like this, that queries the database for the data. And if so, how does it look like  
architecturally. An approach I can think of is to host endpoints in the gateway that does the database queries logic and return the data and have the component to call the endpoint, and probably needing to handle polling to keep the data up to date. Or will it be better to use RPC instead of endpoint. I'm just trying to explore the available options here and coming up with potential workable ideas. Do you have any better ideas?

---

<div class="post-metadata">

**Author:** ![victordcq](https://avatars.discourse-cdn.com/v4/letter/v/f6c823/32.png) [@victordcq](https://forum.inductiveautomation.com/u/victordcq)\
**Post date:** [November 20, 2024, 1:53pm UTC](https://forum.inductiveautomation.com/t/perspective-component/98768/11 "2024-11-20T13:53:15Z")

</div>

> [@Grace\_Gan](#):
>
> and probably needing to handle polling to keep the data up to date.

uh yikes...

Anyways idk if its the best mothode but i ones made a componet with an extension with default code in it, so it can be overwritten. Maybe thats a better option. 🙂

> [@How to get the ScriptManager inside Gateway Module Java](https://forum.inductiveautomation.com/t/how-to-get-the-scriptmanager-inside-gateway-module-java/56137/9):
>
> Here some exmaples of what i did: create a json file simalar to like for the props: { "extensionFunctions": [ { "name": "onRowStartEdit", "description": "Fired when rows in the table are being triggered to edited, if not enabled the default grids update popup will show up which will trigger an event onRowUpdated \nIf you return True the default popup will also show (example to first filter on user role)", "default": "\tsystem.perspective.sendMessage(messageType \u003d\…
