# Javascript inject in Perspective... have fun

**URL:** <https://forum.inductiveautomation.com/t/javascript-inject-in-perspective-have-fun/65805>\
**Category:** Ignition\
**Tags:** perspective\
**Created:** [October 28, 2022, 9:17am UTC](https://forum.inductiveautomation.com/t/javascript-inject-in-perspective-have-fun/65805 "2022-10-28T09:17:54Z")\
**Posts on this page:** 20\
**Page:** 1

<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:** [October 28, 2022, 9:17am UTC](https://forum.inductiveautomation.com/t/javascript-inject-in-perspective-have-fun/65805/1 "2022-10-28T09:17:55Z")

</div>

Soo i'll just link this here...  
You can do whatever with it, but its not really gonna be clean or easy xD Have fun 🧙‍♂️

> [@Perspective Mouse Click & Drag](https://forum.inductiveautomation.com/t/perspective-mouse-click-drag/28583/27):
>
> Soooo.... i was playing around a bit and i found something to inject js in perspective. I know i know crazy_face Its kinda terrible and requires some knowlegde about the perspective react props... But this seems like it would fit here. A little demo, not to complex for drag and drop. Im writing it to a sessionprop, seems to be easier than trying to find the view props. [dndjsinject.zip](https://forum.inductiveautomation.com/uploads/short-url/k9uW6F1ZYMhCSZY1l161wy5UWue.zip) (7.5 KB) @nader.chinichian

**WARNING**  
Dont let userinput enter in here

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/b/1/b199b09f04449e37906614d2e397dc8c6bbb9c62.png)

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [October 28, 2022, 10:54am UTC](https://forum.inductiveautomation.com/t/javascript-inject-in-perspective-have-fun/65805/2 "2022-10-28T10:54:47Z")

</div>

You magician! 🪄🧙If I knew any JavaScript I would certainly try this out, haha, but this seems VERY cool! It _would_ be cool if you could write it back to the view... 😅

---

<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:** [October 28, 2022, 11:21am UTC](https://forum.inductiveautomation.com/t/javascript-inject-in-perspective-have-fun/65805/3 "2022-10-28T11:21:41Z")

</div>

At first sight i found the page context and session context. But the page context isn't really the same as the view... There is a function `findView(resourcePath: string, mountPath: string)` in it though... So i bet you could find it... It would require a lot more javascript though, so probably not idea to try and code that inside a markdown string xD

---

<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 2, 2022, 8:56am UTC](https://forum.inductiveautomation.com/t/javascript-inject-in-perspective-have-fun/65805/4 "2022-11-02T08:56:25Z")

</div>

Here ya go xd

> [@Perspective Mouse Click & Drag](https://forum.inductiveautomation.com/t/perspective-mouse-click-drag/28583/40):
>
> Gotcha mage const view = [...window.\_\_client.page.views.\_data.values()].find(view =\> view.value.mountPath == this.parentNode.parentNode.getAttributeNode('data-component-path').value.split('.')[0]).value; you can than do things like view.custom.read('yourprop'), view.custom.write('yourprop', thevalue), view.props.write('yourprop', thevalue), view.params.read('key') you could dig into the children/root too, but you should probably just use bindings to the custom props unless you know what you…

---

<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 3, 2022, 3:11pm UTC](https://forum.inductiveautomation.com/t/javascript-inject-in-perspective-have-fun/65805/5 "2022-11-03T15:11:53Z")

</div>

Gonna try to keep this topic updated with all my cool injectings 😛  
Version 8.1.22 svg clicker 😉

> [@New Feature: Perspective Piping](https://forum.inductiveautomation.com/t/new-feature-perspective-piping/49919/138):
>
> welp... i just had to try it out didnt it crazy_face Required version 8.1.22 Behold! JS INJECTED SVG CLICKER [jsInjectedSvgClicker.zip](https://forum.inductiveautomation.com/uploads/short-url/yDwMpbCRuyjgMnIYAO9s4YWkTIz.zip) (3.6 KB) edit: I made the value of the binding become the name it writes to in the view.custom props Be sure to set the custom prop back to null after handling your event so you can trigger the onchange events on the prop wink It should only detect things inside this view. Haven't fully tested it though.

---

<div class="post-metadata">

**Author:** ![cmallonee](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/cmallonee/32/6416_2.png) [@cmallonee](https://forum.inductiveautomation.com/u/cmallonee)\
**Post date:** [November 3, 2022, 4:28pm UTC](https://forum.inductiveautomation.com/t/javascript-inject-in-perspective-have-fun/65805/6 "2022-11-03T16:28:48Z")

</div>

This seems like something geared more toward Ignition Exchange, as opposed to sporadic forum postings.

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [November 3, 2022, 4:29pm UTC](https://forum.inductiveautomation.com/t/javascript-inject-in-perspective-have-fun/65805/7 "2022-11-03T16:29:58Z")

</div>

Let's say... keep it to one thread, instead of creating new ones.

---

<div class="post-metadata">

**Author:** ![kgamble](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kgamble/32/8019_2.png) [@kgamble](https://forum.inductiveautomation.com/u/kgamble)\
**Post date:** [November 3, 2022, 9:22pm UTC](https://forum.inductiveautomation.com/t/javascript-inject-in-perspective-have-fun/65805/8 "2022-11-03T21:22:12Z")

</div>

> [@cmallonee](#):
>
> This seems like something geared more toward Ignition Exchange

I am surprised that the JS Injection hack would even be approved into the exchange! lol

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [November 3, 2022, 11:16pm UTC](https://forum.inductiveautomation.com/t/javascript-inject-in-perspective-have-fun/65805/9 "2022-11-03T23:16:20Z")

</div>

> [@kgamble](#):
>
> even be approved

Shhhh! 🤫 😬  
We might find this thread just...  
 ![disappear](https://us1.discourse-cdn.com/inductiveautomation/original/3X/e/5/e5ebb46b6d89ab94335e74d6b69c4b62c00d268d.gif)

---

<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 10, 2022, 3:56pm UTC](https://forum.inductiveautomation.com/t/javascript-inject-in-perspective-have-fun/65805/10 "2022-11-10T15:56:43Z")

</div>

**WARNING**  
Dont let userinput enter in here

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/b/1/b199b09f04449e37906614d2e397dc8c6bbb9c62.png)

Edited the top for this too.

---

<div class="post-metadata">

**Author:** ![Roger\_Henley](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/roger_henley/32/68473_2.png) [@Roger\_Henley](https://forum.inductiveautomation.com/u/Roger_Henley)\
**Post date:** [October 12, 2023, 8:53am UTC](https://forum.inductiveautomation.com/t/javascript-inject-in-perspective-have-fun/65805/11 "2023-10-12T08:53:08Z")

</div>

Have you tried to determine if the device running the perspective screen had geolocation functionality and if so were you able to get device location? With something like this: ```  
function get\_location() {  
if (Modernizr.geolocation) {  
navigator.geolocation.getCurrentPosition(show\_map);  
} else {  
getCurrentPosition  
}  
}  
Navigator.geolocation snippet:

````auto

For my use case I would not want a map, just longitude and latitude coordinates. Would use them to confirm location, then check location against a variable set to confirm the user is in a location that will allow certain on page functionality to become accessible. Purpose is to write a perspective screen to handle hourly employees clock in / out, but only allow if user is on site or within a certain range of the facility they were clocking into. Would need to get the long and lat values to run a comparison. Link above suggests: ```
function show_map(position) {
  var latitude = position.coords.latitude;
  var longitude = position.coords.longitude;
}

````

---

<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:** [October 12, 2023, 11:26am UTC](https://forum.inductiveautomation.com/t/javascript-inject-in-perspective-have-fun/65805/12 "2023-10-12T11:26:34Z")

</div>

session settings have geolocation already  
[https://docs.inductiveautomation.com/display/DOC81/Session+Properties](https://docs.inductiveautomation.com/display/DOC81/Session+Properties)

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/7/a/7acaeafd8775c5ef33a84ebab2832b3833bc6d0b.png)

---

<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:** [October 12, 2023, 11:30am UTC](https://forum.inductiveautomation.com/t/javascript-inject-in-perspective-have-fun/65805/13 "2023-10-12T11:30:34Z")

</div>

Anyways this seems weird to use it for checkins...  
Dont you need to be on the company ip addres already to enter perspective xd (be in wifi range)  
Or are you hosting it online?  
In which case this is not very secure

---

<div class="post-metadata">

**Author:** ![Roger\_Henley](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/roger_henley/32/68473_2.png) [@Roger\_Henley](https://forum.inductiveautomation.com/u/Roger_Henley)\
**Post date:** [October 12, 2023, 12:19pm UTC](https://forum.inductiveautomation.com/t/javascript-inject-in-perspective-have-fun/65805/14 "2023-10-12T12:19:22Z")

</div>

Victor,

Thank you for pointing that out. What do you do for a living? Are you interested in work? I have a couple of Ignition projects I would be interested in hiring someone to create for me.

Roger E. Henley II

VP Engineering & Technology

Whiskey House

[rhenley@whiskeyhouse.com](mailto:rhenley@whiskeyhouse.com)

304-932-8706

![](https://us1.discourse-cdn.com/inductiveautomation/original/3X/1/2/12eea8df3a826b6387b0a9da40f89326ad855f75.png)

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [May 22, 2025, 1:41am UTC](https://forum.inductiveautomation.com/t/javascript-inject-in-perspective-have-fun/65805/15 "2025-05-22T01:41:12Z")

</div>

I haven't found a reliable way to focus a component on View load (tried onStartup events on both the popup View and the input component, as well as on custom prop value change scripts on the input component...), outside of JS.. so here is what I use:

```python
[
  {
    "type": "ia.display.markdown",
    "version": 0,
    "props": {
      "markdown": {
        "escapeHtml": false
      }
    },
    "meta": {
      "name": "SetFocusById"
    },
    "position": {
      "shrink": 0,
      "basis": 0
    },
    "custom": {
      "domIdToFocus": "setpointInputField"
    },
    "propConfig": {
      "props.source": {
        "binding": {
          "type": "expr",
          "config": {
            "expression": "{this.custom.domIdToFocus}"
          },
          "transforms": [
            {
              "code": "\tcode = \"<img style='display:none' src='/favicon.ico' onload=\\\"const element = document.getElementById('\" + value + \"');if (element) { element.focus(); }\\\"></img>\"\n\treturn code",
              "type": "script"
            }
          ]
        }
      }
    }
  }
]

```

---

<div class="post-metadata">

**Author:** ![bmusson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmusson/32/87530_2.png) [@bmusson](https://forum.inductiveautomation.com/u/bmusson)\
**Post date:** [May 22, 2025, 2:01am UTC](https://forum.inductiveautomation.com/t/javascript-inject-in-perspective-have-fun/65805/16 "2025-05-22T02:01:56Z")

</div>

JavaScript injection? 🤮

> **[system.perspective.runJavaScriptAsync | Musson Industrial](https://docs.mussonindustrial.com/ignition/embr-periscope/scripting/perspective/system-perspective-runJavaScriptAsync/)**
>
> The system.perspective.runJavaScriptAsync function allows you to asynchronously run JavaScript code on the client side within a Perspective session.

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [May 22, 2025, 2:15am UTC](https://forum.inductiveautomation.com/t/javascript-inject-in-perspective-have-fun/65805/17 "2025-05-22T02:15:29Z")

</div>

haha, I know this is a thing and NEED to start using it.. let me try

@bmusson

I've tried this with both blocking and async and no worky. It prints "focusing element" to the console but doesn't actually focus it on _ **launch** _ of the popup (tried same things as above: onStartup scripts and on custom prop script transform and onChange script with a binding just setting it to 1, non-persistent value). Calling the function from a button on the view works though. How would I make it work on load?

```python
def onChange(...):
	function = '''(domId)=>{
		const element = document.getElementById(domId);
		console.log(element)
		if (element){
			console.log('focusing element');
			element.focus();
		}
	}'''
	system.perspective.runJavaScriptBlocking(function, {'domId': self.custom.domIdToFocus})

```

I presume the markdown hack works because the markdown component has to load first, presumably along with all the other componnets including the input field to focus, and it adds in the "img" component into the div after these have all loaded, so the onLoad script can then find the focus element and actually focus it. This seems to be the issue with other methods; the component to focus isn't actually loaded and/or displayed when the focus function is called.

---

<div class="post-metadata">

**Author:** ![bmusson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmusson/32/87530_2.png) [@bmusson](https://forum.inductiveautomation.com/u/bmusson)\
**Post date:** [May 22, 2025, 5:06am UTC](https://forum.inductiveautomation.com/t/javascript-inject-in-perspective-have-fun/65805/18 "2025-05-22T05:06:36Z")

</div>

> [@nminchin](#):
>
> I presume the markdown hack works because the markdown component has to load first, presumably along with all the other componnets including the input field to focus, and it adds in the "img" component into the div after these have all loaded, so the onLoad script can then find the focus element and actually focus it. This seems to be the issue with other methods; the component to focus isn't actually loaded and/or displayed when the focus function is called.

Yup, you're exactly right, `runJavaScriptAsync` won't work for this 😕

> [@nminchin](#):
>
> How would I make it work on load?

I do have one other option: use the `events.target.lifecycle.onMount` callback of the Portal component.

> [@Musson Industrial's Embr-Periscope Module](https://forum.inductiveautomation.com/t/musson-industrials-embr-periscope-module/99047/20):
>
> Portal Component This update adds a Portal component, that uses React's createPortal to add children wherever you want them. This allows you to: Add elements inside existing components/views. Decouple the design time structure of your views from the runtime structure of the HTML elements. Develop re-usable views from the outside in. Examples Example, Basic Usage This example demonstrates how the elements of the Portal are added to the target. Example, Alert Information This example …

The Portal component doesn't have any documentation written yet... but, basically, it allows you to interact with a DOM element and directly insert children.

A side-feature is the `events.target.lifecycle` functions. Here, you can add functions that will run when the target `element` loads, unloads, or updates. For example:

```python
# element (DOM ID or arrow function that returns a reference to a node).
TextField
# events.target.lifecycle.onMount
(element) => element.focus()

```

This is pretty much the same thing as the Markdown component injection version though, just with a little more hand-holding.

Edit:  
There is an issue with the Portal component that hasn't been fixed yet; it doesn't listen for DOM changes after the first render. This means the Portal component must load _after_ the target.  
Until this issue is fixed, the Portal component doesn't have an advantage over the Markdown injection technique. Once it's fixed, it won't be load order sensitive.

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [May 22, 2025, 5:45am UTC](https://forum.inductiveautomation.com/t/javascript-inject-in-perspective-have-fun/65805/19 "2025-05-22T05:45:25Z")

</div>

That's pretty cool! I didn't really know what I would use the Portal for when you first released it. The examples you showed like adding alarm decorations to components were cool (nice styling), but I didn't see how it would be applicable at scale e.g. for multiple devices with alarms with different conditions/priority/etc. I'm sure there are some cool use-cases for it though. But really, I wanted to use it purely because of its name 🤭

Edit: with a module, is it possible to add custom event listeners, e.g. add an onActuallyLoaded handler to run after the component has actually fully loaded and displayed?

---

<div class="post-metadata">

**Author:** ![bmusson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmusson/32/87530_2.png) [@bmusson](https://forum.inductiveautomation.com/u/bmusson)\
**Post date:** [May 22, 2025, 5:56am UTC](https://forum.inductiveautomation.com/t/javascript-inject-in-perspective-have-fun/65805/20 "2025-05-22T05:56:54Z")

</div>

> [@nminchin](#):
>
> I didn't really know what I would use the Portal for when you first released it.

Honestly, same 😆.

I’ve used the `onMount` functionality way more than the actual portal feature.

> [@nminchin](#):
>
> Edit: with a module, is it possible to add custom event listeners, e.g. add an onActuallyLoaded handler to run after the component has actually fully loaded and displayed?

Maybe? Let me mull it over.  
That seems to be a commonly requested feature.

My goal has been to make all of Embr’s components have this in the form of the `events` properties. All of them will have `events.dom` and `events.lifecycle`, but some have extras (like the Portal’s `target` or the chart’s `chart` lifecycle events).

[Next page](https://forum.inductiveautomation.com/t/javascript-inject-in-perspective-have-fun/65805.md?page=2)
