Установите фокус элемента в angular способом
После поиска примеров того, как установить элементы фокусировки с помощью angular, я увидел, что большинство из них используют некоторую переменную, чтобы наблюдать за тем, чтобы установить фокус, и большинство из них используют одну другую переменную для каждого поля, для которого они хотят установить фокус. В форме, с большим количеством полей, что подразумевается во множестве разных переменных.
С учетом jquery, но, желая сделать это с помощью angular, я сделал решение, которое мы задали фокус в любой функции, используя идентификатор элемента, поэтому, поскольку я очень новичок в angular, я ' Я хотел бы получить некоторые мнения, если это так, проблемы, что угодно, что-нибудь, что могло бы помочь мне сделать это лучше в angular.
В принципе, я создаю директиву, которая наблюдает за значением области, определяемой пользователем с директивой или по умолчанию focusElement, и когда это значение совпадает с идентификатором элемента, этот элемент сам устанавливает фокус.
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";
}
Это хорошее решение в angular? Есть ли проблемы, которые с моим бедным опытом я еще не вижу?
Ответы
Ответ 1
Проблема с вашим решением заключается в том, что он не работает хорошо, когда привязан к другим директивам, которые создают новую область действия, например. ng-repeat
. Лучшим решением было бы просто создать служебную функцию, которая позволит вам сфокусировать элементы в своих контроллерах или спланировать элементы декларативно в html.
DEMO
JAVASCRIPT
Сервис
.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>
Ответ 2
Об этом решении мы могли бы просто создать директиву и прикрепить ее к элементу DOM, который должен получить фокус, когда данное условие будет выполнено. Следуя этому подходу, мы избегаем связывания контроллера с идентификаторами элемента DOM.
Пример кода:
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">
Ответ 3
Мне нравится избегать поиска 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();
angular.module('app', [])
.directive('inputFocusFunction', function() {
'use strict';
return {
restrict: 'A',
link: function(scope, element, attr) {
// Parse the attribute to accomodate assignment to an object
var parseObj = attr.inputFocusFunction.split('.');
var attachTo = scope;
for (var i = 0; i < parseObj.length - 1; i++) {
attachTo = attachTo[parseObj[i]];
}
// assign it to a function that focuses on the decorated element
attachTo[parseObj[parseObj.length - 1]] = function() {
element[0].focus();
};
}
};
})
.controller('main', function() {});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script>
<body ng-app="app" ng-controller="main as vm">
<input input-focus-function="vm.focusOnSaveInput" ng-model="saveName">
<button ng-click="vm.focusOnSaveInput()">Focus</button>
</body>
Ответ 4
Вы можете попробовать
angular.element('#<elementId>').focus();
например,
angular.element('#txtUserId').focus();
его работа для меня.
Ответ 5
Другим вариантом будет использование встроенной архитектуры pub-sub Angular, чтобы уведомить вашу директиву о необходимости фокусировки. Подобно другим подходам, но затем он напрямую не привязан к свойству и вместо этого прослушивает его область действия для определенного ключа.
Директива
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");
Ответ 6
Я предпочел использовать выражение. Это позволяет мне делать что-то вроде фокуса на кнопке, когда поле действительно, достигает определенной длины и, конечно, после загрузки.
<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">
В сложной форме это также уменьшает необходимость создания дополнительных переменных области для целей фокусировки.
См. fooobar.com/info/12508/...