Focus an element in Aurelia
Asked Answered
F

2

11

I want to set focus to a form element. With jQuery this is so easy, just $('selector').focus.

I have created a simple <input ref="xxx" id="xxx" type="text"> and in my .ts file I add a property and use it here:

attached() {
    this.xxx.focus()
}

Nothing happens. Beginning to feel that some easy things are getting difficult, which I'm sure never was the point.

(the original use case was to set focus to a form element inside a Bootstrap collapse, when the collapse is shown, like this:

// set focus to the first element when the add-cell collapse is shown
$('#collapsedAddTask').on('shown.bs.collapse', function () {
    $('#AddTaskTitle').focus()
})

That works for my basic HTML (not single page app), but not with Aurelia. What's the Aurelia way?

Update Using the answer from Miroslav Popovic below, and in the comments, I got it to work like so (remember, this is a Bootstrap collapse component):

<!-- the heading with an A that toggles visibility -->
<div class="panel-heading">
    <a href="#collapsedAddTask" data-toggle="collapse" id="addTaskHeader" click.delegate="addTaskShown()">Add task</a>
</div>
<!-- the body, which is initially hidden -->
<div class="panel-body">
    <div class="collapse" id="collapsedAddCell">
       <input type="text" focus.bind="addTaskFocused">
       <!-- more controls ... -->
    </div>
</div>
Foveola answered 15/3, 2016 at 8:26 Comment(0)
A
15

this.xxx.focus() is not working because there is no focus() method on DOM element (EDIT: apparently there is now, although Safari does not support it - https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus, thanks @classicalConditioning). jQuery adds that. Reference created by Aurelia points to a plain DOM element. To make it work, you would need to import jQuery and wrap element:

import $ from 'jquery';

// ...

attached() {
    $(this.xxx).focus();
}

Anyway, you should avoid using jQuery in regular view models. It's OK to use it for custom elements and custom attributes, where you need to interact with DOM or initialize some jQuery plugins.

There is a focus custom attribute in Aurelia. You can read more about it in this Aurelia's blog post.

Basically, it enables you to control the focus from your view model. In your view, you would have this:

<input type="text" focus.bind="hasFocus" value.bind="..."/>

And in view model:

attached() {
    this.hasFocus = true;
}

Of course, you'll probably use that for more complex scenarios. I.e. to focus an input when collapse is expanded, or when a new item is added to array bound with repeat.for.

Also, focus attribute implements two-way binding. In the sample above, it will change the value of hasFocus property accordingly.

Arenas answered 15/3, 2016 at 10:27 Comment(8)
And how would you listen for the collapse event? Import the $ and use $('#collapsedAddTask').on('shown.bs.collapse', function () { .... }) or is there an Aurelia way?Foveola
Using jQuery is one option. I don't think you can bind a trigger to that event in view (<div id="collapsedAddTask" shown.bs.collapse.trigger="someMethod()"></div>) , since it's not a regular DOM event... Usually, you'll want to encapsulate all the DOM related logic, either using jQuery or plain DOM, to custom elements or custom attributes. I.e. in this case you could use custom element and have something like <bs-collapse shown.trigger="someMethod()"></bs-collapse>. aurelia.io/docs#/aurelia/framework/1.0.0-beta.1.1.4/doc/article/…Arenas
Another idea... You could create focus-child custom attribute that would handle this shown.bs.collapse event and set a focus to first input element, or element with given ID value. With that you could just add that attribute to collapse div - <div id="collapsedAddTask" focus-child></div>. More on custom attributes in docs - aurelia.io/docs#/aurelia/framework/1.0.0-beta.1.1.4/doc/article/…Arenas
I got it to work by using the focus attribute and attaching a click.delegate to the <a element with the data-toggle="collapse" on it. The click.delegate, just a plain method, sets the focus attribute to true.Foveola
@MiroslavPopovic, are you sure there is no focus() on DOM element? developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focusMegdal
@Megdal well, I'm not really sure if there was focus at that time (three years ago) :) Apparently now there is, although Safari doesn't support it yet.Arenas
The blog link should go here: aurelia.io/blog/2015/06/05/building-aurelias-focus-attributeBentley
Thanks, @RobMosher! Fixed.Arenas
M
7

For the situation where the element isn't hidden and you'd like it to have focus once the view has finished loading, you can simply add focus.one-time="true" like so:

<input
  type="text"
  class="form-control"
  focus.one-time="true"
  value.bind="email"
  placeholder="email address">
Meenen answered 30/6, 2017 at 19:5 Comment(2)
@fracz, it's a bad practice to set the value of aurelia's boolean attribute to a string "true", as it creates wrong assumption that if you set it to "false" the result would be opposite. It's incorrect as in javascript both strings "true" and "false" are truthy.Megdal
@Megdal I'm pretty sure that by using .bind (or one-time binding, as it is here) that the value within the quotes is treated as Javascript, and will therefore evaluate booleans as expected.Spieler

© 2022 - 2024 — McMap. All rights reserved.