Attribute error only on Mobile

Hi everyone,

My app experiences an error when I run it on a mobile device. On my laptop and desktop it runs without error. The error occurs when I click a link that leads to a repeating panel being populated from a data table. Appently

AttributeError: 'NoneType' object has no attribute 'text'

Unfortunately I can’t share the app but does anyone have an idea why this might be happening?

Turns out it works on other peoples’ phones. Must be my terribly old iOS.

Wow, that’s a good one! Can you go into the App Logs for your app and find where that error occurred?

Yes, we’re experiencing this now on multiple mobile devices of different types. Here’s the log.

Looks like it doesn’t like
question=get_focused_component().text

Basically I have several links on my form and I need to know what the text of the clicked link is. So, I have a one callback function that asks for the currently clicked link text and this controls some other logic afterwords.

Aha! Looks like you’re relying on the browser’s tendency to focus a Link after clicking on it. Clearly, this is something mobile users don’t do: No element has focus, so get_focused_component() returns None.

There is a better way to work out which component has been interacted with - check the sender argument to an event handler. Normally, this is one of the arguments swallowed by the **event_args catch-all, eg in code like this:

  def link_click(self, **event_args):
    # The link component can be accessed as event_args['sender']

But you can also explicitly name it as an argument:

  def button_click(self, sender, **event_args):
    print("The text on the button that got clicked was: %s" % sender.text)

Of course, using the text on a component is a slightly clunky way of identifying the component itself. There’s an even better way: the tag property. It starts out as an empty object - you can set any attribute on it, and then retrieve it later. Example:

  def __init__(self, **properties):
    self.init_components(**properties)

    self.link_1.tag.number = 1
    self.link_1.set_event_handler('click', self.link_click)
    self.link_2.tag.number = 2
    self.link_2.set_event_handler('click', self.link_click)

  def link_click(self, sender, **event_args):
    if sender.tag.number == 1:
      print("You clicked the first link!")

You can put anything you like onto a component’s tag property - since it doesn’t have to be displayed to the user, you can attach strings, list, numbers, Media, database rows…you name it.

2 Likes

This is great. So helpful. Works perfectly.