Giriş alanına odak nasıl ayarlanır?


759

AngularJS'de giriş alanına odaklanmanın 'Açısal yolu' nedir?

Daha spesifik gereksinimler:

  1. Bir Modal açıldığında, <input>bu Modal içinde önceden tanımlanmış bir odağa odaklanın .
  2. Her zaman <input>görünür hale gelir (örneğin, bazı düğmelere tıklayarak), odaklanın.

Ben ilk şartı sağlamak için çalıştı ile autofocus, ancak bu Modal ilk kez açıldığında ve yalnızca belirli tarayıcılarda (Firefox bu işi yapmaz mesela) sadece çalışır.

Herhangi bir yardım takdir edilecektir.

Yanıtlar:


579
  1. Bir Modal açıldığında, bu Modal içindeki önceden tanımlanmış bir <input> öğesine odaklanın.

Bir yönerge tanımlayın ve öğeye ne zaman odaklanacağını bilmesi için bir özelliği / tetikleyiciyi izlemesini sağlayın:

Name: <input type="text" focus-me="shouldBeOpen">

app.directive('focusMe', ['$timeout', '$parse', function ($timeout, $parse) {
    return {
        //scope: true,   // optionally create a child scope
        link: function (scope, element, attrs) {
            var model = $parse(attrs.focusMe);
            scope.$watch(model, function (value) {
                console.log('value=', value);
                if (value === true) {
                    $timeout(function () {
                        element[0].focus();
                    });
                }
            });
            // to address @blesh's comment, set attribute value to 'false'
            // on blur event:
            element.bind('blur', function () {
                console.log('blur');
                scope.$apply(model.assign(scope, false));
            });
        }
    };
}]);

Plunker

Modalın oluşturulmasına zaman tanımak için $ zaman aşımı gerekli görünmektedir.

'2.' <input> öğesi her görüntülendiğinde (örneğin, bazı düğmelere tıklayarak), odağı ayarlayın.

Esasen yukarıdaki gibi bir yönerge oluşturun. Scope özelliğinin bazılarını izleyin ve gerçek olduğunda (ng-click işleyicinizde ayarlayın), yürütün element[0].focus(). Kullanım durumunuza bağlı olarak, bunun için $ zaman aşımına ihtiyacınız olabilir veya olmayabilir:

<button class="btn" ng-click="showForm=true; focusInput=true">show form and
 focus input</button>
<div ng-show="showForm">
  <input type="text" ng-model="myInput" focus-me="focusInput"> {{ myInput }}
  <button class="btn" ng-click="showForm=false">hide form</button>
</div>

app.directive('focusMe', function($timeout) {
  return {
    link: function(scope, element, attrs) {
      scope.$watch(attrs.focusMe, function(value) {
        if(value === true) { 
          console.log('value=',value);
          //$timeout(function() {
            element[0].focus();
            scope[attrs.focusMe] = false;
          //});
        }
      });
    }
  };
});

Plunker


Güncelleme 7/2013 : Birkaç kişinin orijinal izolat kapsam direktiflerimi kullandığını ve gömülü girdi alanlarıyla (yani moddaki bir girdi alanı) sorun yaşadığını gördüm. Yeni bir kapsamı olmayan (veya muhtemelen yeni bir çocuk kapsamı) olmayan bir direktif, ağrının bir kısmını hafifletmelidir. Bu yüzden yukarıdaki yanıtı izolat kapsamlarını kullanmamak için güncelledim. Orijinal cevap aşağıdadır:

Bir izolat kapsamı kullanarak 1. için orijinal cevap:

Name: <input type="text" focus-me="{{shouldBeOpen}}">

app.directive('focusMe', function($timeout) {
  return {
    scope: { trigger: '@focusMe' },
    link: function(scope, element) {
      scope.$watch('trigger', function(value) {
        if(value === "true") { 
          $timeout(function() {
            element[0].focus(); 
          });
        }
      });
    }
  };
});

Dalgıç .

Bir izolat kapsamı kullanarak 2. için orijinal cevap:

<button class="btn" ng-click="showForm=true; focusInput=true">show form and
 focus input</button>
<div ng-show="showForm">
  <input type="text" focus-me="focusInput">
  <button class="btn" ng-click="showForm=false">hide form</button>
</div>

app.directive('focusMe', function($timeout) {
  return {
    scope: { trigger: '=focusMe' },
    link: function(scope, element) {
      scope.$watch('trigger', function(value) {
        if(value === true) { 
          //console.log('trigger',value);
          //$timeout(function() {
            element[0].focus();
            scope.trigger = false;
          //});
        }
      });
    }
  };
});

Dalgıç .

Yönergede trigger / focusInput özelliğini sıfırlamamız gerektiğinden, '=' iki yönlü veri bağlama için kullanılır. İlk yönergede '@' yeterliydi. Ayrıca, @ @ kullanırken tetikleyici değerini "true" ile karşılaştırdığımızdan, @ her zaman bir dizeyle sonuçlandığını unutmayın.


1
Ayrıca bkz. @ Josh'un "odak" direktifi: stackoverflow.com/a/14859639/215945 Uygulamasında ayrı bir kapsam kullanmadı.
Mark Rajcok

2
@MarkRajcok sadece bunu merak ediyor: bu sürüm çalışıyor, ancak ng-modelgiriş alanında bir ayar yaparsam , bu yönergeyi yalıtımlı kapsamla birlikte kullandığımda model değeri kaybolur. Ayrı tutma kapsamı olmadan Josh'un sürümünü denersem sorun olmaz. Hala bir acemi ve farkı anlamak istiyorum. İşte bunu gösteren bir Plunker .
Sunil D.Haziran

1
# 1'in AngularJS 1.0.6 ile çok iyi çalıştığını gördüm. Bununla birlikte, bir hata ayıklayıcı altında çalışırken, modalımı her kapattığımda ve yeniden açtığımda, odağı önceki zamana göre ayarlayan bir ek çağrı daha gördüğümü fark ettim. Saatin bağlantısını kesmek için bu işlevi biraz değiştirdim value != "true"ve sorunumu giderdi.
Andrew Brown

1
Yani ... durum bilgisi olan bir sayfada aynı şey vardı çünkü $ watch $ watch ve açısal geliştiriciler $ watch'u seviyor ... iyi bir sorunla karşılaştım, Bay @MarkRajcok, (temel) çözüm ile çözdüğüm bir sorun I aşağıda önerilmiştir.
Ben Lesh

3
hmm benim için kod düzgün i yürütme görebilirsiniz ve eleman [0] doğru kontrol olduğu gibi çalışır. ancak .focus () bir odağı tetiklemez. muhtemelen bootstrap ya da başka bir şey buna müdahale ediyor mu?
Sonic Soul

264

(EDIT: Bu açıklamanın altına güncellenmiş bir çözüm ekledim)

Mark Rajcok adam ... ve onun cevabı geçerli bir cevaptır, ancak etmiştir bir kusuru (üzgün Mark) vardı ...

... Girişe odaklanmak için boolean'ı kullanmayı deneyin, ardından girişi bulanıklaştırın, daha sonra girişi tekrar odaklamak için kullanmayı deneyin. Boole değerini false değerine, ardından $ digest değerine sıfırlamadığınız ve tekrar true değerine sıfırlamadığınız sürece çalışmaz. İfadenizde dize karşılaştırması kullansanız bile, dizeyi başka bir şeye ($ digest), sonra da geri değiştirmeye zorlayacaksınız. (Bu, bulanıklaştırma olay işleyicisi ile giderildi.)

Bu alternatif çözümü öneriyorum:

Angular'ın unutulmuş özelliği olan bir olay kullanın.

Ne de olsa JavaScript olayları çok seviyor. Etkinlikler doğası gereği gevşek bir şekilde birleştirilmiştir ve daha da iyisi, $ özeti için başka bir $ saat eklemekten kaçınırsınız.

app.directive('focusOn', function() {
   return function(scope, elem, attr) {
      scope.$on(attr.focusOn, function(e) {
          elem[0].focus();
      });
   };
});

Şimdi bunu şu şekilde kullanabilirsiniz:

<input type="text" focus-on="newItemAdded" />

ve sonra uygulamanızın herhangi bir yerinde ...

$scope.addNewItem = function () {
    /* stuff here to add a new item... */

    $scope.$broadcast('newItemAdded');
};

Bu harika, çünkü böyle bir şeyle her türlü şeyi yapabilirsiniz. Birincisi, zaten var olan olaylara bağlanabilirsiniz. Başka bir şey ise, uygulamanızın farklı bölümlerinin uygulamanızın diğer bölümlerinin abone olabileceği yayınlama olayları sunarak akıllıca bir şeyler yapmaya başlarsınız.

Her neyse, bu tür şeyler bana "olay güdümlü" diye bağırıyor. Açısal geliştiriciler olarak, kapsam şekilli mandalları olay şekli deliklerine çekiçlemek için gerçekten çok çalışıyoruz.

En iyi çözüm mü? Bilmiyorum. Bu bir çözüm.


Güncellenmiş Çözüm

@ ShimonRachlenko'nun aşağıdaki yorumundan sonra, bunu yapma yöntemimi biraz değiştirdim. Şimdi bir hizmet ve "perde arkasında" bir olay işleyen bir direktif kombinasyonu kullanın:

Bunun dışında, yukarıda belirtilen aynı prensip.

İşte hızlı bir demo Plunk

kullanım

<input type="text" focus-on="focusMe"/>
app.controller('MyCtrl', function($scope, focus) {
    focus('focusMe');
});

Kaynak

app.directive('focusOn', function() {
   return function(scope, elem, attr) {
      scope.$on('focusOn', function(e, name) {
        if(name === attr.focusOn) {
          elem[0].focus();
        }
      });
   };
});

app.factory('focus', function ($rootScope, $timeout) {
  return function(name) {
    $timeout(function (){
      $rootScope.$broadcast('focusOn', name);
    });
  }
});

3
Sen çağrısına sarmak gerekir $broadcastile $timeoutsize denetleyici girerken çalışmalarına bu istiyorum. Aksi takdirde güzel bir çözüm.
Shimon Rachlenko

@ShimonRachlenko - Teşekkürler. Ama $ timeout ile ne demek istediğinden emin değilim. Denetleyici kurucusu işlenirken yayın yapmak isteseydim, o zaman yayın yapardım. Zaman aşımı, yayını olay döngüsünde daha sonraki bir yürütmeye ertelemek dışında hiçbir şey yapmaz.
Ben Lesh

1
Evet, bu direktifin başlaması için yeterli. Yönerge onu dinlemeye başlamadan önce olay tersine yayınlanır .. Bu, yalnızca sayfaya girdiğinizde direktifinizi tetiklemek istediğinizde gereklidir.
Shimon Rachlenko

2
Haklısın. Sanırım yüke odaklanmak için kullanmamıştım. Cevabı daha sağlam bir şeyle güncelleyeceğim.
Ben Lesh

1
Bu, en zarif, "açısal yol" çözümüdür. Bu soruna ilk girdiğimde çoğunlukla kodu kopyaladığım halde, bunun için bir modül yaptığınıza sevindim! Dürüst olmak gerekirse, onu çekirdek açısal içine almaya çalışmanın değerli olabileceğini düşünüyorum.
Randolpho

241

İhtiyacınız olan tek şey bu olduğunda aşırı derecede karmaşık diğer cevapları buldum

app.directive('autoFocus', function($timeout) {
    return {
        restrict: 'AC',
        link: function(_scope, _element) {
            $timeout(function(){
                _element[0].focus();
            }, 0);
        }
    };
});

kullanımı

<input name="theInput" auto-focus>

Zaman aşımını dom'daki şeylerin işlenmesine izin vermek için kullanıyoruz, sıfır olmasına rağmen, en azından bunu bekliyor - bu şekilde modals'da çalışıyor ve ne de değil


1
Bunu yapmanın birkaç yolu olurdu, gerçekten basit ve kolay olan olası bir yol, kapsamda (burada denetleyici), düğmeyi tıkladığınızda odaklanmak istediğiniz öğenin kimliğini ayarlamaktır. direktif sadece bunu dinleyin. Bu durumda, direktifin özellikle bu sayfa içinde bir yere yerleştirmeniz gerekmeyecekti (bu tür izleyici direktiflerini geçmişte başarılı bir şekilde kullandım, özellikle şeylere odaklanmak ve kaydırma yapmak) - Sonra jquery kullanarak (bu daha basit yapar) sadece bu öğe kimliği bulmak ve odaklanmak
ecancil

14
Giriş açılır pencerede bulunuyorsa sıfır zaman aşımı olan çözüm benim için çalışmaz. Ancak 10 ms bile sorunu çözdü
Eugene Fidelin

@ecancil: Yaklaşımınızı seviyorum çünkü en basit olanı, ancak modal görünümün animasyonu girişin dışında yanıp sönen bir imleçle sonuçlandığı için IE'de zaman aşımını ~ 500ms olarak ayarlamanız gerekiyor. Animasyon sona erdiğinde bunun gerçekleşmesi için iyi bir yol bilmiyorum, bu yüzden onu 500ms ile zorlamıyorum.
Dev93

çalışmaz, eğer veritabanından daha fazla veri çekmek zorunda kalırsanız, kontrolörün çekme verilerini tamamlamasını beklemeniz gerekir, bu yüzden 0 yerine yeterli zaman ekleyin
Ali Adravi

1
@Ade gibi bunu basit bir şekilde kullanmak isteyenler için ng-click: Diyelim ki girdinizde bir düğmeye ng-click="showInput = !showInputtıklamanız var. Ardından, gerçek girişinize ekleyin ng-if="showInput". Düğmeyi değiştirmek, yönergeyi her seferinde yeniden çalıştırır. Kullanırken bununla ilgili bir sorunum vardıng-showYanlış yaklaşım olan .
JVG

91

HTML'nin bir özelliği vardır autofocus.

<input type="text" name="fname" autofocus>

http://www.w3schools.com/tags/att_input_autofocus.asp


29
Ne yazık ki, bu sadece bir kez çalışır. Bunu yerinde bir Açısal düzenleme üzerinde kullandım ve ilk kez Chrome'da harika çalıştı, Firefox'ta hiç de iyi değildi. Chrome'da, yerinde düzenlemek için veya başka bir öğeyi tekrar düzenlemek için başka bir öğeyi tıkladığımda, artık odaklanmıyor. Dokümanlar, bir Açısal uygulamada yalnızca bir kez gerçekleşen sayfa yüklemesinde çalıştığını belirtir. Keşke bu kadar basit olsaydı, hepimiz% 20 kazanç sağlayan bir plajda otururduk!
Nocturno

62

Açısal olarak yerleşik jqlite işlevselliğini de kullanabilirsiniz.

angular.element('.selector').trigger('focus');


2
Jquery yüklü olmadan: angular.forEach (document.querySelectorAll ('. Selector'), işlev (elem) {elem.focus ();});
Dan Benamy

29
Bunu bir denetleyiciye koymak kötü bir uygulama değil mi?
VitalyB

2
Bu jqlite hattını bir denetleyiciye koymak kötü bir uygulama ise, bu jqlite hattını bir yönerge içine koymak daha iyi olmaz mıydı?
spor

3
Bunu anlıyorum:Looking up elements via selectors is not supported by jqLite!
Maria Ines Parnisari

1
Bir ajax çağrısından sonra bir öğeyi bulanıklaştırmam gereken bir durum vardı. Denetleyicinin içindeki geri aramaya yalnızca bir satır saf JS ekleyebilir veya yalnızca bu girdinin bulanıklaştırılması için tam bir yönerge oluşturabilirim. Sadece bir güçlük çok hissettim, bu yüzden ilk seçenek için gittim.
Sebastianb

55

Bu iyi çalışıyor ve giriş kontrolüne odaklanmanın açısal bir yolu

angular.element('#elementId').focus()

Bu, işi yapmanın saf bir açısal yolu olmamasına rağmen, sözdizimi açısal stili takip eder. Jquery, Angular (jQLite => JQuery Light) kullanarak dolaylı ve doğrudan DOM'ya rol oynar.

Gerekirse, bu kod, elemanın doğrudan erişilebilir olduğu basit bir açısal direktif içine kolayca yerleştirilebilir.


Bunun ViewModel uygulamaları için harika bir yaklaşım olduğundan emin değilim. Açısal olarak direktiflerle yapılmalıdır.
Agat

Birisi bir metin kutusunu A değiştirirse ve pop-up'ı göstermeniz ve diğer metin kutusu B'ye odaklanmanız gerekir.
Sanjeev Singh

1
Bunu kullanırken bu hatayı alıyorum: Looking up elements via selectors is not supported by jqLite!
JVG

6
Bildiğim kadarıyla jQuery önce bir bağımlılık olarak yüklemeniz gerekir, bu durumda angular.elementbir sarıcı olur $() / jQuery(). Bu olmadan bu işe yaramaz ve temelde sadece jQuery kullanıyorsunuz (ama yanılıyorsam beni düzeltin)
JVG

@Jascination: jqLite, jQuery bağımlılığını ortadan kaldırmak için geliştirilmiştir. DOM'daki bir öğeye erişmek için tüm jQuery'ye ihtiyacınız yoktur. Ancak jQuery yüklüyse, Angular jQuery'ye başvurur. Bunu kontrol et: docs.angularjs.org/api/angular.element
Sanjeev Singh

31

$ Timeout'un öğeyi yaratıma odaklamanın iyi bir yolu olduğunu düşünmüyorum. Açısal belgelerin bulanık derinliklerinden çıkarılan yerleşik açısal işlevselliği kullanan bir yöntem. Bağlantı öncesi ve bağlantı sonrası işlevleri için "link" özelliğinin "pre" ve "post" olarak nasıl bölünebileceğine dikkat edin.

Çalışma Örneği: http://plnkr.co/edit/Fj59GB

// this is the directive you add to any element you want to highlight after creation
Guest.directive('autoFocus', function() {
    return {
        link: {
            pre: function preLink(scope, element, attr) {
                console.debug('prelink called');
                // this fails since the element hasn't rendered
                //element[0].focus();
            },
            post: function postLink(scope, element, attr) {
                console.debug('postlink called');
                // this succeeds since the element has been rendered
                element[0].focus();
            }
        }
    }
});
<input value="hello" />
<!-- this input automatically gets focus on creation -->
<input value="world" auto-focus />

Tam Açısal JS Yönergesi Dokümanları: https://docs.angularjs.org/api/ng/service/$compile


2
Benim için çalışmasını sağlamak için [0] .focus () öğesini bir $ zaman aşımı içinde sarmak zorunda kaldım.
codin

@bbodenmiller Modalımda solukluk var, eleman inşa edildiğinde görünmez (% 100 şeffaf), bu yüzden tarayıcı odaklamayı sessizce odaklıyor. Görünüşe göre, geçen milisaniyeler neredeyse şeffaf ancak görünür giriş / düğmeye odaklanmaya izin veriyor.
Karlı

1
dokümanlar uyarınca, "link" işlevleri varsayılan olarak "postLink" dir. ayrıca bkz: bennadel.com/blog/…
jody tate

17

İşte benim orijinal çözümüm:

plunker

var app = angular.module('plunker', []);
app.directive('autoFocus', function($timeout) {
    return {
        link: function (scope, element, attrs) {
            attrs.$observe("autoFocus", function(newValue){
                if (newValue === "true")
                    $timeout(function(){element[0].focus()});
            });
        }
    };
});

Ve HTML:

<button ng-click="isVisible = !isVisible">Toggle input</button>
<input ng-show="isVisible" auto-focus="{{ isVisible }}" value="auto-focus on" />

Bu ne yapar:

Ng-show ile görünür hale geldiğinde girişi odaklar. Burada $ watch veya $ kullanamazsınız.


Aslında {{isVisible}} zaten bir saat oluşturduğuna inanıyorum, bu yüzden "$ watch kullanmıyor" ifadesi yanlış.
masimplo

Evet, bence haklısın. Ama yine de bunu yapmanın kolay bir yolu olarak hizmet ediyor.
Edhowler

17

Tıpkı son zamanlarda olduğu gibi iki yönlü bir bağlayıcı odaklama talimatı yazdım.

Odak yönergesini şu şekilde kullanabilirsiniz:

<input focus="someFocusVariable">

SomeFocusVariable kapsam değişkeni yaparsanız trueDenetleyicinizin herhangi bir yerinde , giriş odaklanır. Ve sonra girdinizi "bulanıklaştırmak" istiyorsanız, someFocusVariable öğesi false olarak ayarlanabilir. Mark Rajcok'un ilk cevabı gibi ama iki yönlü bağlayıcı.

İşte yönerge:

function Ctrl($scope) {
  $scope.model = "ahaha"
  $scope.someFocusVariable = true; // If you want to focus initially, set this to true. Else you don't need to define this at all.
}

angular.module('experiement', [])
  .directive('focus', function($timeout, $parse) {
    return {
      restrict: 'A',
      link: function(scope, element, attrs) {
          scope.$watch(attrs.focus, function(newValue, oldValue) {
              if (newValue) { element[0].focus(); }
          });
          element.bind("blur", function(e) {
              $timeout(function() {
                  scope.$apply(attrs.focus + "=false"); 
              }, 0);
          });
          element.bind("focus", function(e) {
              $timeout(function() {
                  scope.$apply(attrs.focus + "=true");
              }, 0);
          })
      }
    }
  });

Kullanımı:

<div ng-app="experiement">
  <div ng-controller="Ctrl">
    An Input: <input ng-model="model" focus="someFocusVariable">
    <hr>
        <div ng-click="someFocusVariable=true">Focus!</div>  
        <pre>someFocusVariable: {{ someFocusVariable }}</pre>
        <pre>content: {{ model }}</pre>
  </div>
</div>

İşte keman:

http://fiddle.jshell.net/ubenzer/9FSL4/8/


Bu doğru cevap olmalı. Tüm kullanım durumlarını kapsar.
Kunal

11

Angular'ı Bootstrap eklentisi ile kullananlar için:

http://angular-ui.github.io/bootstrap/#/modal

openedKalıcı örneğin vaadine girebilirsiniz :

modalInstance.opened.then(function() {
        $timeout(function() {
            angular.element('#title_input').trigger('focus');
        });
    });

modalInstance.result.then(function ( etc...

İyi! Ancak benim durumumda, $timeoutile 50msyerine ihtiyacı var 0.
lk_vc

8

Genel bir ifade kullanmayı yararlı buldum. Bu şekilde, giriş metni geçerli olduğunda odağı otomatik olarak taşıma gibi şeyler yapabilirsiniz

<button type="button" moo-focus-expression="form.phone.$valid">

Veya kullanıcı sabit uzunluk alanını tamamladığında otomatik olarak odaklan

<button type="submit" moo-focus-expression="smsconfirm.length == 6">

Ve elbette yükten sonra odaklanın

<input type="text" moo-focus-expression="true">

Direktifin kodu:

.directive('mooFocusExpression', function ($timeout) {
    return {
        restrict: 'A',
        link: {
            post: function postLink(scope, element, attrs) {
                scope.$watch(attrs.mooFocusExpression, function (value) {

                    if (attrs.mooFocusExpression) {
                        if (scope.$eval(attrs.mooFocusExpression)) {
                            $timeout(function () {
                                element[0].focus();
                            }, 100); //need some delay to work with ng-disabled
                        }
                    }
                });
            }
        }
    };
});

7

Bir zombi diriltmek veya kendi direktifimi takmamak (tamam yaptığım şey tam olarak bu):

https://github.com/hiebj/ng-focus-if

http://plnkr.co/edit/MJS3zRk079Mu72o5A9l6?p=preview

<input focus-if />

(function() {
    'use strict';
    angular
        .module('focus-if', [])
        .directive('focusIf', focusIf);

    function focusIf($timeout) {
        function link($scope, $element, $attrs) {
            var dom = $element[0];
            if ($attrs.focusIf) {
                $scope.$watch($attrs.focusIf, focus);
            } else {
                focus(true);
            }
            function focus(condition) {
                if (condition) {
                    $timeout(function() {
                        dom.focus();
                    }, $scope.$eval($attrs.focusDelay) || 0);
                }
            }
        }
        return {
            restrict: 'A',
            link: link
        };
    }
})();

Şimdi bu yönergeyi kullanıyorum ve harika çalışıyor, genel sorunu çözüyor ve aşırı karmaşık değil. $ Timeout içermeyen bir çözüm aramaya başladı. Angular 1.1 ve 1.2 için odaklamanın "yol haritasında" olduğunu söyleyen yorumları bulmaya devam edin, ancak 2.x kullanıyorum ve hala odak yönetimi kullanmıyorum. Heh.
tekHedd

6

İlk olarak, odaklanmanın resmi bir yolu 1.1 için yol haritasıdır . Bu arada, ayar odağını uygulamak için bir yönerge yazabilirsiniz.

İkinci olarak, bir öğe görünür hale geldikten sonra odağı ayarlamak için şu anda bir çözüm gerekiyor. Bir öğeyle öğe odağı () öğesine yapılan aramayı ertelemeniz yeterlidir $timeout.

Aynı denetleyici-değiştirir-DOM sorunu odak, bulanıklık ve seçim için mevcut olduğundan, bir ng-targetyönerge olmasını öneriyorum :

<input type="text" x-ng-model="form.color" x-ng-target="form.colorTarget">
<button class="btn" x-ng-click="form.colorTarget.focus()">do focus</button>

Açısal iş parçacığı burada: http://goo.gl/ipsx4 ve daha fazla ayrıntı burada bloglandı: http://goo.gl/4rdZa

Aşağıdaki yönergede, .focus()denetleyicinizin içinde ng-targetözniteliğiniz tarafından belirtilen bir işlev oluşturulur . (A .blur()ve .select()çok oluşturur .) Demo: http://jsfiddle.net/bseib/WUcQX/


Yol haritası referansı için +1. Aslında bunu hala kararsız olarak kabul edilen 1.2 belgelerinde gördüm ( docs.angularjs.org/api/ng.directive:ngFocus )
Edwin Dalorzo

27
@EdwinDalorzo ngFocusişlemek için bir yol olarak görünmektedir focusolayları değil bir yolu ayarlamak bir öğe odağı.
teleclimber

6

Kendi direktifinizi oluşturmak yerine, bir odaklamayı gerçekleştirmek için javascript işlevlerini kullanmak mümkündür.

İşte bir örnek.

Html dosyasında:

<input type="text" id="myInputId" />

Bir dosya javascriptinde, örneğin odağı etkinleştirmek istediğiniz bir denetleyicide:

document.getElementById("myInputId").focus();

9
Bu 'açısal bir yol' değildir ve insanlara kontrolörlerinde DOM'ye dokunmalarını önermez.
smajl

Angular'da vanilya kullanmamak en iyisidir, çünkü Angular onu izleyemez veya diğer her şeyle senkronize tutamaz.
Edgar Quintero

4

Eğer sadece bir tıklamayla kontrol edilen basit bir odak istiyorsanız.

Html:

<input ut-focus="focusTigger">

<button ng-click="focusTrigger=!focusTrigger" ng-init="focusTrigger=false"></button>

Direktif:

'use strict'

angular.module('focus',['ng'])
.directive('utFocus',function($timeout){
    return {
        link:function(scope,elem,attr){
            var focusTarget = attr['utFocus'];
            scope.$watch(focusTarget,function(value){
                $timeout(function(){
                    elem[0].focus();
                });
            });
        }
    }
});

4

Modals ile iyi çalışan basit bir tane:

.directive('focusMeNow', ['$timeout', function ($timeout)
{
    return {
        restrict: 'A',

        link: function (scope, element, attrs)
        {


            $timeout(function ()
            {
                element[0].focus();
            });



        }
    };
}])

Misal

<input ng-model="your.value" focus-me-now />

Benim için mükemmel. Teşekkür ederim
Alexander

3

Sadece postLinking'te dekore edilmiş öğeye odaklanmaya zorlayan bir yönerge oluşturabilirsiniz:

angular.module('directives')
.directive('autoFocus', function() {
    return {
        restrict: 'AC',
        link: function(_scope, _element) {
            _element[0].focus();
        }
    };
});

Sonra html'nizde:

<input type="text" name="first" auto-focus/> <!-- this will get the focus -->
<input type="text" name="second"/>

PostLinking yalnızca HTML işlemede gerçekleştiğinden, bu modlar ve ng-if değiştirilmiş öğeler için çalışır, ng-show için değil.


3

Mark ve Blesh'in harika cevapları var; Ancak, Mark'ın Blesh'in işaret ettiği bir kusur var (uygulamak için karmaşık olmanın yanı sıra) ve Blesh'ın cevabının, gerçekten ihtiyaç duyduğu tek şey bir önyükleme için ön talebe odak isteği göndermekle ilgili bir hizmet oluşturmada anlamsal bir hata olduğunu hissediyorum. tüm direktifler dinleyene kadar etkinliği geciktirir.

İşte burada yaptığım şey, Blesh'ın cevabından çok şey çaldı, ancak denetleyici olayının anlamını ve "yük sonrası" hizmetini ayrı tutan şey.

Bu, kontrolör olayının sadece belirli bir öğeye odaklanmaktan başka şeyler için kolayca bağlanmasına izin verir ve aynı zamanda "gerektiğinde" pek çok durumda bulunmayabilecekse "yükleme sonrası" işlevselliğinin ek yüküne neden olur.

kullanım

<input type="text" focus-on="controllerEvent"/>
app.controller('MyCtrl', function($scope, afterLoad) {
  function notifyControllerEvent() {
      $scope.$broadcast('controllerEvent');
  }

  afterLoad(notifyControllerEvent);
});

Kaynak

app.directive('focusOn', function() {
   return function(scope, elem, attr) {
      scope.$on(attr.focusOn, function(e, name) {
        elem[0].focus();
      });
   };
});

app.factory('afterLoad', function ($rootScope, $timeout) {
  return function(func) {
    $timeout(func);
  }
});

Ben (tam bir başlangıç) anlayabildiğim tek cevap. "AfterLoad (notifyControllerEvent);" yerine "notifyControllerEvent ()" için kullanılırdım. Aksi takdirde, bazı hatalarla sona erdi.
Vel Murugan S

3

Bu da kullanılabilir ngModelController. 1.6+ ile çalışma (eski sürümlerle bilmiyorum).

HTML

<form name="myForm">
    <input type="text" name="myText" ng-model="myText">
</form>

JS

$scope.myForm.myText.$$element.focus();

-

Not: Bağlama bağlı olarak, bir zaman aşımı işlevini sarmanız gerekebilir.

NB²: Kullanırken controllerAsbu neredeyse aynı. Sadece JS name="myForm"ile değiştirin .name="vm.myForm"vm.myForm.myText.$$element.focus();


3

Muhtemelen, ES6 yaşındaki en basit çözüm.

Aşağıdaki bir liner yönergesinin eklenmesi HTML 'autofocus' özelliğini Angular.js üzerinde etkili hale getirir.

.directive('autofocus', ($timeout) => ({link: (_, e) => $timeout(() => e[0].focus())}))

Artık HTML5 otomatik odaklama sözdizimini şu şekilde kullanabilirsiniz:

<input type="text" autofocus>

@Stephane evet, o zaman olur.directive('autofocus', ['$timeout', ($timeout) => ({link: (_, e) => $timeout(() => e[0].focus())})])
Michael Plautz

2

Burada sadece bir acemi, ama ben bu yönerge ile bir ui.bootstrap.modal çalışmak mümkün oldu :

directives.directive('focus', function($timeout) {
    return {
        link : function(scope, element) {
            scope.$watch('idToFocus', function(value) {
                if (value === element[0].id) {
                    $timeout(function() {
                        element[0].focus();
                    });
                }
            });
        }
    };
});

ve $ modal.open yönteminde, odağın nereye yerleştirilmesi gerektiğini belirten öğeyi belirtmek için kullandım:

var d = $modal.open({
        controller : function($scope, $modalInstance) {
            ...
            $scope.idToFocus = "cancelaAteste";
    }
        ...
    });

şablonda bu var:

<input id="myInputId" focus />

2

Aşağıdaki direktif benim için hile yaptı. Giriş için aynı otomatik netleme html özelliğini kullanın.

.directive('autofocus', [function () {
    return {
        require : 'ngModel',
        restrict: 'A',
        link: function (scope, element, attrs) {
            element.focus();
        }
    };
}])

1
jQuery dahil edilmediği sürece bunu çalıştırırken bir hata alırsınız, bunun yerine öğe [0] .focus ()
Ryan M

2

ModalInstance kullanıyorsanız ve nesneye sahipseniz, modal açıldıktan sonra eylemler yapmak için "then" kullanabilirsiniz. Eğer modalInstance kullanmıyorsanız ve modal açmak için sabit kodlanmışsa olayı kullanabilirsiniz. $ Zaman aşımı iyi bir çözüm değildir.

Şunları yapabilirsiniz (Bootstrap3):

$("#" + modalId).on("shown.bs.modal", function() {
    angular.element("[name='name']").focus();
});

ModalInstance adresinde kodu açık moddan sonra nasıl yürüteceğinize bakabilirsiniz.

Bu şekilde $ zaman aşımı kullanmayın, $ zaman aşımı 0, 1, 10, 30, 50, 200 veya daha fazla olabilir, bu istemci bilgisayara ve modal açma işlemine bağlı olacaktır.

$ Timeout kullanmayın, yöntem ne zaman odaklanabileceğinizi söylesin;)

Umarım bu yardımcı olur! :)


2

Yönerge şablonunda istenen odak öğesi enjekte edilirse, önceki yanıtın tümü çalışmaz. Aşağıdaki yönerge hem basit öğeye hem de yönerge enjekte edilen öğeye uygundur (bunu daktiloda yazdım ). iç odaklanabilir eleman için seçici kabul eder. sadece self elemente odaklanmanız gerekiyorsa - direktife herhangi bir selector parametresi göndermeyin:

module APP.Directives {

export class FocusOnLoadDirective implements ng.IDirective {
    priority = 0;
    restrict = 'A';

    constructor(private $interval:any, private $timeout:any) {

    }

    link = (scope:ng.IScope, element:JQuery, attrs:any) => {
        var _self = this;
        var intervalId:number = 0;


        var clearInterval = function () {
            if (intervalId != 0) {
                _self.$interval.cancel(intervalId);
                intervalId = 0;
            }
        };

        _self.$timeout(function(){

                intervalId = _self.$interval(function () {
                    let focusableElement = null;
                    if (attrs.focusOnLoad != '') {
                        focusableElement = element.find(attrs.focusOnLoad);
                    }
                    else {
                        focusableElement = element;
                    }
                    console.debug('focusOnLoad directive: trying to focus');
                    focusableElement.focus();
                    if (document.activeElement === focusableElement[0]) {
                        clearInterval();
                    }
                }, 100);

                scope.$on('$destroy', function () {
                    // Make sure that the interval is destroyed too
                    clearInterval();
                });

        });
    };

    public static factory = ():ng.IDirectiveFactory => {
        let directive = ($interval:any, $timeout:any) => new FocusOnLoadDirective($interval, $timeout);
        directive.$inject = ['$interval', '$timeout'];
        return directive;
    };
}

angular.module('common').directive('focusOnLoad', FocusOnLoadDirective.factory());

}

basit eleman için kullanım örneği:

<button tabindex="0" focus-on-load />

iç eleman için kullanım örneği (genellikle şablonlu direktif gibi dinamik enjekte edilen eleman için):

<my-directive focus-on-load="input" />

"input" yerine herhangi bir jQuery selector kullanabilirsiniz


2

Mark Rajcok'un focusMe yönergesini bir öğede birden çok odak için çalışacağım.

HTML:

<input  focus-me="myInputFocus"  type="text">

AngularJs Kontrol Cihazında:

$scope.myInputFocus= true;

AngulaJS Direktifi:

app.directive('focusMe', function ($timeout, $parse) {
    return {
        link: function (scope, element, attrs) {
            var model = $parse(attrs.focusMe);
            scope.$watch(model, function (value) {
                if (value === true) {
                    $timeout(function () {
                        scope.$apply(model.assign(scope, false));
                        element[0].focus();
                    }, 30);
                }
            });
        }
    };
});

1

Daha iyi bir çözüm arayıp bulmadıktan sonra bu tartışmaya katkıda bulunmak istiyorum.

Kriterler: 1. Yeniden kullanılabilirliği artırmak için çözüm ana denetleyici kapsamından bağımsız olmalıdır. 2. Bazı durumları izlemek için $ watch kullanmaktan kaçının, bu hem yavaştır, sindirim döngüsünün boyutunu arttırır ve testi zorlaştırır. 3. Özet döngüsünü tetiklemek için $ timeout veya $ scope. $ Uygulamak () kullanmaktan kaçının. 4. Direktifin açık kullanıldığı elemanın içinde bir giriş elemanı bulunmaktadır.

En çok sevdiğim çözüm bu:

Direktif:

.directive('focusInput', [ function () {
    return {
        scope: {},
        restrict: 'A',
        compile: function(elem, attr) {
            elem.bind('click', function() {
                elem.find('input').focus();                
            });
        }        
    };
}]);

Html:

 <div focus-input>
     <input/>
 </div>

Umarım bu birisine yardım eder!


Html "label" ın ne yaptığını yeniden yarattınız, "div focus-input" yerine "label" yazıp direktiften kurtulabilirsiniz.
ilk

1

Çok kolay .. bunu dene

html

<select id="ddl00">  
 <option>"test 01"</option>  
</select>

javaScript

document.getElementById("ddl00").focus();

Bağlam dışında doğru, ama bir şeyleri yapmanın AngularJS yolu değil
CodeMonkey

1

Belirli bir öğeye odaklanmak istiyorsanız, aşağıdaki yaklaşımı kullanabilirsiniz.

  1. Adlı bir hizmet oluşturun focus.

    angular.module('application')
    .factory('focus', function ($timeout, $window) {
        return function (id) {
            $timeout(function () {
                var element = $window.document.getElementById(id);
                if (element)
                    element.focus();
            });
        };
    });
  2. Aramak istediğiniz yerden denetleyiciye enjekte edin.

  3. Bu servisi arayın.


0

Direktifin gereksiz olduğunu düşünüyorum. Gerekli öğeyi seçmek için HTML kimliği ve sınıf niteliklerini kullanın ve hizmetin odağı (veya jQuery eşdeğerlerini) uygulamak için document.getElementById veya document.querySelector uygulamasını kullanmasını sağlayın.

İşaretleme, seçim için kimlik / sınıf eklenmiş standart HTML / açısal yönergelerdir

<input id="myInput" type="text" ng-model="myInputModel" />

Denetleyici yayınları etkinliği

$scope.$emit('ui:focus', '#myInput');

UI hizmeti querySelector kullanıyorsa - birden fazla eşleşme varsa (sınıf nedeniyle) varsa, yalnızca ilkini döndürür

$rootScope.$on('ui:focus', function($event, selector){
  var elem = document.querySelector(selector);
  if (elem) {
    elem.focus();
  }
});

Özet döngüsünü zorlamak için $ timeout () kullanmak isteyebilirsiniz


0

Biraz kahve atıyorum.

app.directive 'ngAltFocus', ->
    restrict: 'A'
    scope: ngAltFocus: '='
    link: (scope, el, attrs) ->
        scope.$watch 'ngAltFocus', (nv) -> el[0].focus() if nv
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.