Creating and clicking on a Link, programmatically

I’m either going crazy or missing something obvious but can’t seem to create and programmatically click on a Link… I’ve followed the docs and How to 'click' a link via code and this is a simplified version of what I’m doing:

https://anvil.works/build#clone:ZFJT3TEHERDJWRH2=BAN4PY5FHKYY5ELAPELURXQM

from ._anvil_designer import Form1Template
from anvil import *
import time

class Form1(Form1Template):

  def __init__(self, **properties):
    # Set Form properties and Data Bindings.
    self.init_components(**properties)

  def click_blue_button(self, **event_args):
    """This method is called when the button is clicked"""
    link = Link(text= "Anvil Forum", align = "center", url="https://anvil.works/forum/")
    self.add_component(link)
    self.refresh_data_bindings()
    time.sleep(5)
    link.raise_event("click")
    print("Clicked?")

As you can see it includes time.sleep and refresh_data_bindings just in case it was some sort of delay or timing issue.

It executes all the way through to printing “Clicked?” without throwing an error, and although I can manually click on the new link at any time, it doesn’t automatically pop up a new tab in any browser I tried. Can anyone spot the problem please?

Thanks very much
Peter

this may be a security implementation from the browser - preventing malicious websites from forcing tabs to open - but maybe something else.

You could try taking the approach used here:

1 Like

Thanks Stu. I see the same behaviour on on Edge, Chrome and Firefox and raise_event('click') is explicitly mentioned in the docs to do just one thing…

@hannah/@bridget - could this be a bug or compatibility issue as browsers have evolved beyond the original Link functionality?

Hi @AWSOM,

Raising the link click event will do just what it says on the tin - raise the click event and call the associated Anvil event handler. This is entirely unrelated to clicking on the DOM element that represents the link, and certainly doesn’t go as far as emulating mouse events. If you want the browser to think the user has clicked a link (so the page can open in a new tab, for example), then you will need to drop down to JavaScript and simulate the mouse event there. Beware, though, browsers have extremely strict requirements for opening popups from JS - it can only be done as a direct result of a user interaction, and there are quite a few gotchas.

It would be good to know what the end goal is here - are you trying to link to a dynamic URL, for example? Let us know and we’ll see what we can do to help!

1 Like

Thanks @daviesian.

Thanks for your suggestions re: Javascript, but I want to push things as far as I can in pure Python, and only if we move to the next stage of funding employ a Javascript/Anvil wizard to put further bells and whistles on it. I’m a one-man-band until then, and my brain is at capacity just learning Python/Anvil (it’s not my day job!) and one of the great appeals of Anvil was reusing that knowledge without having to learn another language or rely on outside help.

So the actual use case is taking a YouTube video url as input
e.g. https://www.youtube.com/watch?v=Sw6eRg7EYvw

and dynamically derive a url to take you directly to the captions upload screen


e.g. https://www.youtube.com/timedtext_editor?v=Sw6eRg7EYvw&edit_id=en-GB%3A%3A&bl=vmp&action_edit_edit_form=1&new=yes&upl=yes&ui=se&ar=1601909994391&nv=1&o=U

I wanted to then set the .url attribute of my Link to that derived url and automatically launch it in a new tab in the browser:

  def click_upload_button(self, **event_args):
      self.caption_upload_link.url = self.response.get('caption_upload_url')
      self.caption_upload_link.raise_event('click') 

Nothing seems to happen the first time (I believe .url is set however), but if I click again it does correctly load the new tab. Hence my suspicion that there’s some kind of “blocking” going on, or my thought that I data bindings needing refreshing or a short period of time was needed to update the client.

If there’s not an easy/non-JavaScript solution then please don’t worry, but I suspect this use case could be fairly common/useful with other people too - programmatically set a url then simulate a user click.

One of the amazing things about Anvil’s Javascript integration is that the amount of Javascript you need to customize it is often minimal. I know very little Javascript myself, and have been able to do whatever minimal Javascript I need to allow me to continue working in Python.

To programmatically open a link via Javascript requires very little code. Something like this in your Native Libraries section:

function open_url_same_tab(url) {
  window.open(url, "_self");
}

And then your Python code to open the link becomes:

js.call_js('open_url_same_tab', self.link.url)

That was adapted from this post: How to make a link open in the current tab You’ll find a clone example of the technique there, too.

4 Likes

Thanks @jshaffstall - that’s a great, concise solution. For future reference, bear in mind that this will only work if the code is executed directly as a result of a user interaction. If you make a server call (with anvil.server.call), or similar, the browser will decide that you’re trying to produce an unwanted popup and block it.

That said, I think this is exactly what’s required in this case. Thanks!

2 Likes

Hi @daviesian and @jshaffstall and thanks for offering a way to work around this.

I might be just missing something that’s obvious to you, but I can’t shake the thought that something’s actually buggy (or unexplained) here though… Why would raising the same click event not work immediately after setting the .url attribute, but work as expected when the event is raised a second time?

As far as I can tell, the click event for the link is not what opens a new tab. It’s just an event for you to do something when the link is clicked. The click event does get executed when the user clicks on the link directly, which also opens the link, but it’s not the click event opening the link.

So I think the answer to your original question (“Why doesn’t the click event open the link”) is that it isn’t designed to.

I’m sure if you wanted to submit a feature request to have it work that way the Anvil team would consider it. I can’t think of anything in any of my apps that would break.

In the meantime, you’ll have to programmatically open the link using Javascript.

1 Like

And if you want this to open in a new tab rather than the same tab just remove the argument '_self' from the JavaScript snippet - or change it to '_blank'

1 Like

Thanks for your patience guys, I think I’ve finally got my head around it from your explanations!