각도 방식으로 요소 초점 설정


113

각도로 포커스 요소를 설정하는 방법에 대한 예제를 찾은 후 대부분이 변수를 사용하여 관찰 한 다음 포커스를 설정하고, 대부분은 포커스를 설정하려는 각 필드에 대해 하나의 다른 변수를 사용하는 것을 확인했습니다. 필드가 많은 양식에서 다양한 변수를 의미합니다.

jquery 방식을 염두에두고 각도 방식으로하고 싶었으므로 요소의 ID를 사용하여 모든 기능에 초점을 맞춘 솔루션을 만들었으므로 각도가 매우 새롭기 때문에 다음과 같은 의견을 듣고 싶습니다. 그 방법이 옳습니다. 문제가 있습니다. 제가 각도에서 더 나은 방법으로이 작업을 수행하는 데 도움이 될 수있는 모든 것이 있습니다.

기본적으로 지시문 또는 기본값의 focusElement로 사용자가 정의한 범위 값을 감시하는 지시문을 만들고 해당 값이 요소의 ID와 같으면 해당 요소가 포커스를 설정합니다.

angular.module('appnamehere')
  .directive('myFocus', function () {
    return {
      restrict: 'A',
      link: function postLink(scope, element, attrs) {
        if (attrs.myFocus == "") {
          attrs.myFocus = "focusElement";
        }
        scope.$watch(attrs.myFocus, function(value) {
          if(value == attrs.id) {
            element[0].focus();
          }
        });
        element.on("blur", function() {
          scope[attrs.myFocus] = "";
          scope.$apply();
        })        
      }
    };
  });

어떤 이유로 포커스를 받아야하는 입력은 이런 식으로 수행됩니다.

<input my-focus id="input1" type="text" />

포커스를 설정할 요소는 다음과 같습니다.

<a href="" ng-click="clickButton()" >Set focus</a>

그리고 포커스를 설정하는 예제 함수 :

$scope.clickButton = function() {
    $scope.focusElement = "input1";
}

각도에서 좋은 솔루션입니까? 내 가난한 경험으로 아직 보지 못하는 문제가 있습니까?

답변:


173

솔루션의 문제는 새 범위를 생성하는 다른 지시문 (예 :)에 묶여있을 때 제대로 작동하지 않는다는 것 ng-repeat입니다. 더 나은 솔루션은 컨트롤러 내에서 명령 적으로 요소에 초점을 맞추거나 html에서 선언적으로 요소에 초점을 맞출 수있는 서비스 함수를 만드는 것입니다.

데모

자바 스크립트

서비스

 .factory('focus', function($timeout, $window) {
    return function(id) {
      // timeout makes sure that it is invoked after any other event has been triggered.
      // e.g. click events that need to run before the focus or
      // inputs elements that are in a disabled state but are enabled when those events
      // are triggered.
      $timeout(function() {
        var element = $window.document.getElementById(id);
        if(element)
          element.focus();
      });
    };
  });

지령

  .directive('eventFocus', function(focus) {
    return function(scope, elem, attr) {
      elem.on(attr.eventFocus, function() {
        focus(attr.eventFocusId);
      });

      // Removes bound events in the element itself
      // when the scope is destroyed
      scope.$on('$destroy', function() {
        elem.off(attr.eventFocus);
      });
    };
  });

제어 장치

.controller('Ctrl', function($scope, focus) {
    $scope.doSomething = function() {
      // do something awesome
      focus('email');
    };
  });

HTML

<input type="email" id="email" class="form-control">
<button event-focus="click" event-focus-id="email">Declarative Focus</button>
<button ng-click="doSomething()">Imperative Focus</button>

이 솔루션이 정말 마음에 듭니다. 그러나 $ timeout을 사용하는 이유를 좀 더 설명해 주시겠습니까? "Angular Thing"또는 "DOM Thing"때문에 사용하신 이유입니까?
user1821052 2014

앵귤러가 수행하는 다이제스트 사이클 이후에 실행되는지 확인하지만 시간 초과 후 실행되는 비동기 작업 후에 영향을받는 다이제스트 사이클은 제외됩니다.
ryeballar 2014

3
감사! 이것은 각 문서에서 참조된다 궁금 사람들을 위해, 여기에의 링크 (찾기 위해 영원히 걸렸다)
user1821052을

@ryeballar, 감사합니다!. 좋은 간단한 해결책. 그래도 질문입니다. 이벤트가 발생하기를 기다리지 않고 속성을 통해 생성 된 팩토리를 사용할 수 있습니까?
Pratik Gaikwad

4
입력에 초점을 맞추기 위해 각도에서 필요한 작업의 양은 미쳤습니다.
Bruno Santos

19

이 솔루션에 대해 우리는 지시문을 생성하고 주어진 조건이 충족 될 때 포커스를 얻어야하는 DOM 요소에 첨부 할 수 있습니다. 이 접근 방식을 따르면 컨트롤러를 DOM 요소 ID에 연결하지 않습니다.

샘플 코드 지시문 :

gbndirectives.directive('focusOnCondition', ['$timeout',
    function ($timeout) {
        var checkDirectivePrerequisites = function (attrs) {
          if (!attrs.focusOnCondition && attrs.focusOnCondition != "") {
                throw "FocusOnCondition missing attribute to evaluate";
          }
        }

        return {            
            restrict: "A",
            link: function (scope, element, attrs, ctrls) {
                checkDirectivePrerequisites(attrs);

                scope.$watch(attrs.focusOnCondition, function (currentValue, lastValue) {
                    if(currentValue == true) {
                        $timeout(function () {                                                
                            element.focus();
                        });
                    }
                });
            }
        };
    }
]);

가능한 사용법

.controller('Ctrl', function($scope) {
   $scope.myCondition = false;
   // you can just add this to a radiobutton click value
   // or just watch for a value to change...
   $scope.doSomething = function(newMyConditionValue) {
       // do something awesome
       $scope.myCondition = newMyConditionValue;
  };

});

HTML

<input focus-on-condition="myCondition">

1
myCondition$ scope 변수가 이미 true로 설정되어 있고 사용자가 다른 요소에 초점을 맞추도록 선택 했을 때 어떤 일이 발생하는지 , myCondition이미 true 일 때 여전히 초점을 다시 트리거 할 수 있습니까? 코드는 속성에 대한 변경 사항을 감시 focusOnCondition하지만 언제 트리거되지 않습니다. 변경하려는 값은 여전히 ​​동일합니다.
ryeballar

샘플을 업데이트 할 것입니다.이 경우 두 개의 라디오 버튼이 있고 값에 따라 플래그를 true 또는 false로 전환합니다. myCondition 플래그를 true 또는 false로 변경할 수 있습니다.
Braulio

일반적인 솔루션처럼 보입니다. ID에 의존하는 것보다 낫습니다. 나는 그것을 좋아한다.
mortb

다른 사람이 이것을 시도하고 작동하지 않는 경우 element.focus (); to element [0] .focus ();
아드리안 카

1
이 솔루션은 위의 ID 기반 해킹보다 훨씬 더 '각진 방식'입니다.
setec jul.

11

가능한 한 DOM 조회, 감시 및 전역 이미 터를 피하는 것을 좋아하므로보다 직접적인 접근 방식을 사용합니다. 지시문을 사용하여 지시문 요소에 초점을 맞춘 간단한 기능을 지정하십시오. 그런 다음 컨트롤러 범위 내에서 필요할 때마다 해당 함수를 호출하십시오.

다음은 범위에 연결하는 간단한 방법입니다. 컨트롤러로서의 구문 처리에 대한 전체 스 니펫을 참조하십시오.

지령:

app.directive('inputFocusFunction', function () {
    'use strict';
    return {
        restrict: 'A',
        link: function (scope, element, attr) {
            scope[attr.inputFocusFunction] = function () {
                element[0].focus();
            };
        }
    };
});

그리고 html에서 :

<input input-focus-function="focusOnSaveInput" ng-model="saveName">
<button ng-click="focusOnSaveInput()">Focus</button>

또는 컨트롤러에서 :

$scope.focusOnSaveInput();

이 접근 방식의 이유에 대한 자세한 설명을 제공하고 컨트롤러 사용을 위해 코드 스 니펫을 확장하도록 편집 되었습니다.


그것은 매우 훌륭하고 나를 위해 잘 작동하고 있습니다. 하지만 이제를 사용하는 입력 ng-repeat세트가 있으며 첫 번째에만 초점 기능을 설정하고 싶습니다. 내가 조건부 포커스 기능을 설정할 수있는 방법을 어떤 생각 <input>에 따라 $index, 예를 들면?
Garret Wilson

유용 하다니 다행입니다. 내 각도 1은 약간 녹슬었지만, 같은 입력에 다른 속성을 추가 할 수 있어야합니다. assign-focus-function-if="{{$index===0}}"그런 다음, 그것이 사실이 아닌 경우 함수를 할당하기 전에 지시문의 첫 번째 줄이 일찍 종료됩니다. if (attr.assignFocusFunctionIf===false) return; 참고 명시 적 false이며 거짓이 아니므로 해당 속성이 정의되지 않은 경우에도 지시문은 계속 작동합니다.
cstricklan

컨트롤러는 lodash를 사용하면 훨씬 간단합니다. _.set(scope, attributes.focusOnSaveInput, function() { element.focus(); }).
Atomosk

9

당신은 시도 할 수 있습니다

angular.element('#<elementId>').focus();

예를 들어.

angular.element('#txtUserId').focus();

그것은 나를 위해 일하고 있습니다.


4
참고 : Angular에 포함 된 jqLite에 의존하는 대신 전체 jQuery를 사용하는 경우에만 작동합니다. docs.angularjs.org/api/ng/function/angular.element
John Rix

4
이것은 각도가 아닌 jQuery 방식입니다. 질문은 구체적으로 각도 방식으로 수행하는 방법을 묻습니다.
forgivenson

4

또 다른 옵션은 Angular의 내장 pub-sub 아키텍처를 사용하여 지시문에 집중하도록 알리는 것입니다. 다른 접근 방식과 유사하지만 속성에 직접 연결되지 않고 대신 특정 키에 대한 범위를 수신합니다.

지령:

angular.module("app").directive("focusOn", function($timeout) {
  return {
    restrict: "A",
    link: function(scope, element, attrs) {
      scope.$on(attrs.focusOn, function(e) {
        $timeout((function() {
          element[0].focus();
        }), 10);
      });
    }
  };
});

HTML :

<input type="text" name="text_input" ng-model="ctrl.model" focus-on="focusTextInput" />

제어 장치:

//Assume this is within your controller
//And you've hit the point where you want to focus the input:
$scope.$broadcast("focusTextInput");

3

나는 표현을 선호했습니다. 이렇게하면 필드가 유효하고 특정 길이에 도달 할 때, 물론로드 후에 버튼에 초점을 맞추는 것과 같은 작업을 수행 할 수 있습니다.

<button type="button" moo-focus-expression="form.phone.$valid">
<button type="submit" moo-focus-expression="smsconfirm.length == 6">
<input type="text" moo-focus-expression="true">

복잡한 형태에서는 초점을 맞추기 위해 추가 범위 변수를 생성 할 필요성도 줄어 듭니다.

참조 https://stackoverflow.com/a/29963695/937997를

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.