Ustawianie ostrości elementu w sposób kątowy

Po zapoznaniu się z przykładami ustawiania elementów ostrości za pomocą kąta, zauważyłem, że większość z nich używa jakiejś zmiennej, aby obserwować, a następnie ustawić ostrość, a większość z nich używa jednej innej zmiennej dla każdego pola, które chcą ustawić ostrość. W formie, z wieloma polami, która implikuje wiele różnych zmiennych.

Mając na uwadze sposób jquery, ale chcąc to zrobić w angular way, zrobiłem rozwiązanie, które ustawiamy focus w dowolnej funkcji za pomocą identyfikatora elementu, więc, ponieważ jestem bardzo nowy w angular, chciałbym chciałbym uzyskać jakieś opinie, czy ten sposób jest właściwy, mieć problemy, cokolwiek, cokolwiek, co mogłoby mi pomóc zrobić to lepiej w angular.

Zasadniczo, tworzę dyrektywę, która monitoruje wartość zakresu zdefiniowaną przez Użytkownika za pomocą dyrektywy lub domyślnego elementu focusElement, a gdy ta wartość jest taka sama jak ID elementu, element ustawia focus.

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();
        })        
      }
    };
  });

Wejście, które z jakiegoś powodu musi uzyskać ostrość, zrobi to w ten sposób

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

Tutaj dowolny element do Ustawienia focus:

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

I przykładowa funkcja ustawiająca ostrość:

$scope.clickButton = function() {
    $scope.focusElement = "input1";
}
Czy to dobre rozwiązanie w angular? Czy ma problemy, których z moim słabym doświadczeniem jeszcze nie widzę?
Author: sudo bangbang, 2014-09-01

6 answers

Problem z Twoim rozwiązaniem polega na tym, że nie działa ono dobrze, gdy jest powiązane z innymi dyrektywami, które tworzą nowy zakres, np. ng-repeat. Lepszym rozwiązaniem byłoby po prostu stworzenie funkcji serwisowej, która umożliwia imperatywne skupianie elementów w kontrolerach lub deklaratywne skupianie elementów w html.

DEMO

JAVASCRIPT

serwis

 .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();
      });
    };
  });

Dyrektywa

  .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

.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>
 169
Author: ryeballar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-20 14:21:11

Jeśli chodzi o to rozwiązanie, możemy po prostu stworzyć dyrektywę i dołączyć ją do elementu DOM, który musi uzyskać ostrość, gdy dany warunek jest spełniony. W ten sposób unikamy sprzężenia kontrolera z ID elementu DOM.

Przykładowy kod dyrektywy:

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();
                        });
                    }
                });
            }
        };
    }
]);

Możliwe użycie

.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">
 18
Author: Braulio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-10 09:31:13

Lubię unikać wyszukiwania DOM, zegarków i globalnych emiterów, gdy tylko jest to możliwe, więc używam bardziej bezpośredniego podejścia. Użyj dyrektywy, aby przypisać prostą funkcję, która koncentruje się na elemencie dyrektywy. Następnie wywołaj tę funkcję wszędzie tam, gdzie jest to potrzebne w zakresie kontrolera.

Oto uproszczone podejście do dołączania go do scope. Zobacz pełny urywek do obsługi składni controller-as.

Dyrektywa:

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

Oraz w html:

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

Lub w kontroler:

$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>

Edytowano , aby dostarczyć więcej wyjaśnień na temat przyczyny tego podejścia i rozszerzyć fragment kodu dla controllera-as use.

 11
Author: cstricklan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-22 04:17:30

Możesz spróbować

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

Dla np.

angular.element('#txtUserId').focus();
Działa na mnie.
 9
Author: Anoop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-29 05:21:24

Inną opcją byłoby użycie wbudowanej architektury pub-sub Angular w celu powiadomienia dyrektywy o skupieniu. Podobnie jak w innych podejściach, ale nie jest to bezpośrednio związane z właściwością, a zamiast tego nasłuchuje się jej zakresu dla określonego klucza.

Dyrektywa:

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" />

Kontroler:

//Assume this is within your controller
//And you've hit the point where you want to focus the input:
$scope.$broadcast("focusTextInput");
 4
Author: Mattygabe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-27 13:31:48

Wolałem użyć wyrażenia. To pozwala mi robić rzeczy takie jak fokus na przycisku, gdy pole jest ważne, osiąga określoną długość i oczywiście po załadowaniu.

<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">

W postaci złożonej zmniejsza to również potrzebę tworzenia dodatkowych zmiennych zakresu dla celów skupienia.

Zobacz https://stackoverflow.com/a/29963695/937997

 3
Author: winry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:45