I have a text field in a popup view, and I added an onStartup event script that is simply self.focus(). While the script seems to execute every time the popup is opened, the focus only seems to stick about 50% of the time. I'm guessing I could use a Timer to delay the focus a tad and make it stick, but I'd rather not use such a hack if possible. Am I missing something?
EDIT: Yep, this works:
def runAction(self):
from threading import Timer
def focus(self):
self.focus()
Timer(0.1, focus, [self]).start()
...but why is that necessary?
What are you trying to focus, the popup itself?
I didn't read your post close enough. I do this as well and it works for me. onStartUp
event on the view
self.getChild("root").getChild("TextField").focus()
When a Popup is opened, what would you expect to receive focus? We can't just arbitrarily apply focus to the first component (input) in the Popup, so focus is (I believe) applied to the Popup itself.
If you want to determine where focus should go, you need to do something like this.
That very likely only works for a very simple View. As the View becomes more complicated, immediate accessing of internal components during onStartup will become increasingly riskier as it becomes something approaching a race condition. It's probably a bit safer to just do self.focus()
in the onStartup
Event of the Text Field component.
May be safer, but it doesn't work, that's the point.
I tried doing it from the onStartup of the view, but I get the same results. It only works about 50% of the time.
What about start up script on the container the component is in?
Like I said: race condition. The onStartup
Event fires as the View begins to load, and there's a chance that the content of the View hasn't "loaded" quite yet. Even within the context of the component, it may not be in a state where it can even receive focus yet.
1 Like
Makes sense. An onLoad alternative that fires when the view is done loading would be ideal...
The view I use this on is a single container, basically a confirmation popup. It works every time.
That's exactly what I'm creating:
![image](https://global.discourse-cdn.com/inductiveautomation/original/3X/2/5/252031ee4fc15b0190dd7d41c31f2639a1a509f4.png)
Very simple, and it doesn't seem like it should be so convoluted to simply make sure the input field has focus when it opens...
I tried that, same result...
1 Like
In theory, if you have a component which you know will load after your Text Field, you could move the logic to that component.
# onStartup Event of "later" sibling component
self.getSibling("TextField").focus()
It would disassociate the logic from the parent and Text Field, but it should work.
1 Like
How would you determine what would load after it?
Could a "onComponentFinishedLoading" hook be possible, and would you consider adding it ?
It seems like a lot of these issues would be solved by having a different event that's triggered "later".
I created a feature request, vote for it here:
1 Like