0

I have an Add button that is bound to ng-click="add()" and within this function, it adds a new object to the angular array which in turn adds a new row in my html table that uses ng-repeat. However, i want to set focus to the new textarea once the element is rendered on the page. Currently it seems that i am trying to set focus before the element is actually on the page. Any ideas around this?

Markup:

 <button id="AddNote" type="button" class="btn btn-primary btn-sm" ng-click="add()">New</button>

JS code:

$scope.add = function () {
    $scope.notes.splice(0, 0, {
        NoteID: 0,
        SubmissionID: 0,
        Value: '',
        CreatedDate: new Date(),
        CreatedDateDisplay: '',
        CreatedByUserID: 0,
        CreatedByUserDisplay: '',
        IsNew: true,
        ShowRemove: true,
        IsDirty: true,
        IsDisabled: false
    });

    $scope.showTable = true;
    //$('tr[index="0"]').first('td').find('textarea').focus();
    //$('#NotesGrid tr:last').first('td').find('textarea').focus();
    $('#AddNote').prop('disabled', true);
    $('#SaveNote').show();
};
1
  • thanks for the edits btw, still waking up lol Commented Jan 12, 2017 at 15:24

3 Answers 3

1

Indeed, it takes time to Angular to kick in and render the new element into the page.

The most simple way to achieve what you want is to use a timer:

window.setTimeout(function() {
    $('#NotesGrid tr:last').first('td').find('textarea').focus();
}, 500);

Half a second should be enough time for angular to render the new element.

Sign up to request clarification or add additional context in comments.

6 Comments

Where would i place the timeout? Within the add function i assume
@user1732364 yes, instead of the line you commented out.
What if I have a slow computer and it takes longer than a half a second? A better option would be to make a directive that sets the focus on the element once it loads.
@GiovaniVercauteren this can happen only if there are lots (hundreds) of rows.
key point here is: "can". It's not a good idea to leave something over to chance.
|
1

You can create a simple directive that will give focus to whatever element as soon as it loads.

angular.module('myApp').directive('focusMe', [function() {
    return {
        link: function(scope, element) {
        element[0].focus();
      }
    }
  }]);

Add it to an input as such:

<input type="text" focus-me>

And a little JSFiddle just to show the grand scheme of things: https://jsfiddle.net/2yt04ztr/5/

1 Comment

This works for very simple forms, not those with more than one dynamic input. Usually you want to target the first added input and not last one (which this solution does)
1

First of to disable an element or add a property to an element you'd better use angularjs directives like ng-attr-disabled or ng-disabled.

To answer your main question, you have to wait until your current stack is finished for angular to compile your new change and then you could focus if you want, and to do so you could use setTimeout zero:

$scope.add = function () {
  // ....
  setTimeout(function{
    $('#NotesGrid tr:last').first('td').find('textarea').focus();
  }, 0);
};

The important point is angular doesn't need any time to compile, you should just wait for the current stack to be finished. Angular compiles your new changes at the end of current stack that's why we use setTimeout zero. There is also a function (which is not available in all of the browsers) called setImmediate which does the same thing. So it doesn't have anything to with your computer being slow or not, even if you pass 0 to setTimeout it waits at least 4 milliseconds and even if it didn't it would work, because setTimeout runs your function after the current stack.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.