Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular ng-repeat: Keep focus to input when order changes

I'm using ng-repeat to show an ordered list. I have an input in the list which where you can specify the order. When you change it, sometimes it stays in focus (when the input goes down) but when the input gets sorted up, I loose focus on the input. How can I solve this?

Example: http://jsfiddle.net/Q3Xfe/

<div ng-app ng-controller="MyCtrl">
    <div ng-repeat='person in Persons | orderBy: "number" track by person.id'>
        <p>{{ person.name }} <input type='number' ng-model='person.number'></p>
    </div>
</div>
like image 637
Kim Avatar asked May 28 '14 10:05

Kim


2 Answers

A more generic approach:

app.directive("keepFocus", ['$timeout', function ($timeout) {
    /*
    Intended use:
        <input keep-focus ng-model='someModel.value'></input>
    */
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function ($scope, $element, attrs, ngModel) {

            ngModel.$parsers.unshift(function (value) {
                $timeout(function () {
                    $element[0].focus();
                });
                return value;
            });

        }
    };
}])

Then just:

<input keep-focus ng-model="person.number"/>
like image 93
Shawn Dotey Avatar answered Oct 03 '22 00:10

Shawn Dotey


I assume this is due to how the DOM elements get recreated when the order changes. I created a directive that will maintain the focus. I'm not sure if this is the best way or not, but it works.

app.directive('setFocus', function($timeout, $rootScope) {
    return {
        restrict: 'A',
        scope: {
            personId: '@',
            index: '@',
            selectedPersonId: '@'
        },
        link: function($scope, $element, attrs) {
            $scope.$watch("index", function(currentValue, previousValue) {
                if($scope.personId == $scope.selectedPersonId)
                {
                    $timeout(function(){
                        $element[0].focus();
                    });
                }
            })
        }
    }
});

You pass it in th personId of the element, the index of the element, and the selectedPersonId (whichever one has the focus). It watches for an index change to occur, and then checks if the element's personId is equal to the selectedPersonId (setting the focus if it is).

The HTML looks like this:

<input class='filter' type='number' ng-model='person.number' ng-focus="selectPerson(person.id)" set-focus person-id="{{person.id}}" selected-person-id="{{selectedPersonId}}" index="{{$index}}">

Seems like kind of a lot of extra stuff to do something that seems simple. Maybe someone else has a more clever way.

Here's a Fiddle.

like image 26
Jerrad Avatar answered Oct 02 '22 23:10

Jerrad