Bagaimana cara mengatur fokus pada bidang input?

759

Apa itu 'Cara sudut' untuk menetapkan fokus pada bidang input di AngularJS?

Persyaratan yang lebih spesifik:

  1. Ketika Modal dibuka, tetapkan fokus pada yang telah ditentukan <input>di dalam Modal ini.
  2. Setiap kali <input>menjadi terlihat (misalnya dengan mengklik beberapa tombol), tetapkan fokus padanya.

Saya mencoba untuk mencapai persyaratan pertama dengan autofocus, tapi ini hanya bekerja jika Modal dibuka untuk pertama kalinya, dan hanya dalam browser tertentu (misalnya di Firefox itu tidak bekerja).

Bantuan apa pun akan dihargai.

Misha Moroshko
sumber

Jawaban:

579
  1. Saat Modal dibuka, setel fokus pada <input> yang telah ditentukan di dalam Modal ini.

Tetapkan arahan dan minta $ tonton properti / pemicu sehingga tahu kapan harus memfokuskan elemen:

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

$ Timeout tampaknya diperlukan untuk memberikan modal waktu untuk merender.

'2.' Setiap kali <input> menjadi terlihat (misalnya dengan mengklik beberapa tombol), atur fokus padanya.

Buat arahan dasarnya seperti yang ada di atas. Tonton beberapa properti lingkup, dan ketika itu menjadi benar (atur di pawang ng-klik Anda), jalankan element[0].focus(). Bergantung pada kasus penggunaan Anda, Anda mungkin perlu atau tidak perlu $ timeout untuk yang ini:

<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


Pembaruan 7/2013 : Saya telah melihat beberapa orang menggunakan arahan lingkup isolat asli saya dan kemudian memiliki masalah dengan bidang input yang disematkan (yaitu, bidang input dalam modal). Arahan tanpa ruang lingkup baru (atau mungkin ruang lingkup anak baru) harus mengurangi rasa sakit. Jadi di atas saya memperbarui jawabannya untuk tidak menggunakan cakupan isolasi. Di bawah ini adalah jawaban asli:

Jawaban orisinal untuk 1., menggunakan ruang lingkup isolasi:

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

Plunker .

Jawaban orisinal untuk 2., menggunakan ruang lingkup isolasi:

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

Plunker .

Karena kita perlu mereset properti trigger / focusInput dalam direktif, '=' digunakan untuk penyatuan data dua arah. Dalam arahan pertama, '@' sudah cukup. Perhatikan juga bahwa ketika menggunakan '@' kami membandingkan nilai pemicu ke "true" karena @ selalu menghasilkan string.

Mark Rajcok
sumber
1
Lihat juga arahan "fokus" Josh @: stackoverflow.com/a/14859639/215945 Dia tidak menggunakan lingkup isolat dalam implementasinya.
Mark Rajcok
2
@ MarkRajcok hanya ingin tahu tentang ini: versi ini berfungsi tetapi jika saya menetapkan ng-modelpada bidang input, nilai model hilang ketika saya menggunakan direktif ini w / ruang lingkup isolat digunakan. Masalahnya tidak terjadi jika saya mencoba versi Josh tanpa ruang lingkup isolasi. Masih pemula, dan saya ingin memahami perbedaannya. Berikut adalah Plunker yang menunjukkannya.
Sunil D.
1
Saya menemukan bahwa # 1 bekerja sangat baik dengan AngularJS 1.0.6. Namun, ketika berjalan di bawah debugger, saya perhatikan bahwa setiap kali saya menolak dan membuka kembali modal saya, saya melihat satu lagi panggilan tambahan ke fungsi yang menetapkan fokus daripada waktu sebelumnya. Saya memodifikasi fungsi itu sedikit untuk melepaskan ikatan arloji kapan value != "true", dan itu muncul untuk mengatasi masalah saya.
Andrew Brown
1
Jadi ... pada halaman stateful saya memiliki hal yang sama terjadi karena $ watch adalah $ watch dan pengembang sudut suka $ watch ... well saya mendapatkan masalah, Mr @MarkRajcok, masalah yang saya pecahkan dengan solusi (dasar) I diusulkan di bawah ini.
Ben Lesh
3
hmm bagi saya kode berfungsi, seperti pada saya dapat melihatnya mengeksekusi dengan benar dan elemen [0] adalah kontrol yang tepat. namun .focus () tidak memicu fokus. mungkin bootstrap atau sesuatu yang lain mengganggu ini?
Sonic Soul
264

(EDIT: Saya telah menambahkan solusi yang diperbarui di bawah penjelasan ini)

Mark Rajcok adalah pria ... dan jawabannya adalah jawaban yang valid, tetapi memiliki cacat (Mark maaf) ...

... Coba gunakan boolean untuk fokus pada input, lalu buramkan input, lalu coba gunakan untuk memfokuskan input lagi. Ini tidak akan berfungsi kecuali jika Anda mengatur ulang boolean ke false, lalu $ digest, lalu reset kembali ke true. Bahkan jika Anda menggunakan perbandingan string dalam ekspresi Anda, Anda akan dipaksa untuk mengubah string ke sesuatu yang lain, $ digest, lalu ubah kembali. (Ini telah diatasi dengan pengendali acara blur.)

Jadi saya mengusulkan solusi alternatif ini:

Gunakan acara, fitur Angular yang terlupakan.

Bagaimanapun, JavaScript menyukai acara. Acara secara inheren digabungkan secara longgar, dan bahkan lebih baik, Anda menghindari menambahkan $ menonton lain ke $ digest Anda.

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

Jadi sekarang Anda bisa menggunakannya seperti ini:

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

dan kemudian di mana saja di aplikasi Anda ...

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

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

Ini luar biasa karena Anda dapat melakukan segala macam hal dengan sesuatu seperti ini. Untuk satu, Anda bisa mengikat ke acara yang sudah ada. Untuk hal lain, Anda mulai melakukan sesuatu yang cerdas dengan meminta bagian yang berbeda dari aplikasi Anda mempublikasikan acara yang dapat diikuti oleh bagian lain dari aplikasi Anda.

Bagaimanapun, jenis hal ini berteriak "event driven" kepada saya. Saya pikir sebagai pengembang Angular kami berusaha sangat keras untuk memalu pasak berbentuk $ lingkup ke lubang bentuk acara.

Apakah ini solusi terbaik? Saya tidak tahu. Ini sebuah solusi.


Solusi Terbaru

Setelah komentar @ ShimonRachlenko di bawah, saya telah mengubah metode saya untuk melakukan ini sedikit. Sekarang saya menggunakan kombinasi layanan dan arahan yang menangani acara "di belakang layar":

Selain itu, prinsipal yang sama dijelaskan di atas.

Ini demo singkat Plunk

Pemakaian

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

Sumber

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);
    });
  }
});
Ben Lesh
sumber
3
Anda harus mengakhiri panggilan $broadcastdengan $timeoutjika Anda ingin ini berhasil memasuki controller. Kalau tidak solusi yang bagus.
Shimon Rachlenko
@ShimonRachlenko - Terima kasih. Tapi saya tidak yakin apa yang Anda maksud dengan $ timeout. Jika saya ingin menyiarkan ketika konstruktor controller sedang diproses, saya baru saja menyiarkannya. Waktu tunggu tidak akan melakukan apa pun kecuali menunda siaran ke eksekusi nanti di loop acara.
Ben Lesh
1
Ya, dan itu cukup bagi arahan untuk menginisialisasi. Melebihi acara disiarkan sebelum arahan mulai mendengarkannya .. Sekali lagi, ini hanya diperlukan ketika Anda ingin memicu arahan Anda ketika Anda memasuki halaman.
Shimon Rachlenko
2
Kamu benar. Saya kira saya tidak menggunakannya untuk fokus pada beban. Saya akan memperbarui jawabannya dengan sesuatu yang lebih kuat.
Ben Lesh
1
Sejauh ini, ini adalah solusi "cara sudut" yang paling elegan. Meskipun saya kebanyakan hanya menyalin kode ketika saya pertama kali mengalami masalah ini, saya senang Anda membuat modul untuk itu! Jujur saya pikir mungkin ada baiknya mencoba memasukkannya ke sudut inti.
Randolpho
241

Saya telah menemukan beberapa jawaban lain yang terlalu rumit ketika semua yang Anda butuhkan adalah ini

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

penggunaan adalah

<input name="theInput" auto-focus>

Kami menggunakan batas waktu untuk membiarkan hal-hal di dom render, meskipun nol, setidaknya menunggu untuk itu - dengan cara ini bekerja dalam modals dan yang lainnya juga

ecancil
sumber
1
Akan ada beberapa cara untuk melakukan ini, salah satu cara yang mungkin benar-benar lurus ke depan dan mudah adalah pada ruang lingkup (pengontrol di sini) mengatur ID item yang ingin Anda fokuskan ketika Anda mengklik tombol, kemudian di direktif hanya mendengarkan ini. Dalam hal ini Anda tidak perlu menempatkan arahan di mana pun khususnya, hanya di suatu tempat di dalam halaman itu (saya telah menggunakan arahan pengamat semacam ini dengan sukses di masa lalu, terutama dengan memfokuskan hal-hal dan menggulir hal-hal) - Lalu jika Anda ' kembali menggunakan jquery (akan membuat ini lebih sederhana) temukan saja elemen id itu dan fokuskan
ecancil
14
Solusi dengan nol batas waktu tidak berfungsi untuk saya jika input terletak di modal sembulan. Tetapi bahkan 10 ms memperbaiki masalah
Eugene Fidelin
@ecancil: Saya suka pendekatan Anda karena ini paling sederhana, tetapi Anda perlu mengatur batas waktu ke ~ 500ms di IE karena animasi dari penampilan modal menghasilkan kursor yang berkedip di luar input. Saya tidak tahu cara yang bagus untuk membuat ini terjadi ketika animasi berakhir, jadi saya coba paksa dengan 500ms.
Dev93
tidak akan berfungsi, jika Anda harus menarik lebih banyak data dari basis data, ia harus menunggu pengontrol menyelesaikan data penarikan, jadi tambahkan waktu yang cukup di tempat 0
Ali Adravi
1
Bagi yang seperti @Ade yang ingin menggunakan ini dengan sederhana ng-click: Katakanlah mengklik tombol ada ng-click="showInput = !showInputpada input Anda. Kemudian, pada input Anda yang sebenarnya, tambahkan ng-if="showInput". Beralih tombol akan membuat arahan dijalankan kembali setiap kali. Saya mengalami masalah dengan ini karena saya menggunakan ng-showyang merupakan pendekatan yang salah.
JVG
91

HTML memiliki atribut autofocus.

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

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

Rayron Victor
sumber
29
Sayangnya, ini hanya berfungsi sekali jika sama sekali. Saya menggunakan ini pada pengeditan sudut pada situasi tempat , dan itu bekerja sangat baik pertama kali di Chrome, tidak sama sekali di Firefox. Di Chrome, ketika saya mengklik item lain untuk diedit, atau bahkan pada item yang sama lagi, item itu tidak lagi mendapatkan fokus. Dokumen menyatakan ini berfungsi pada pemuatan halaman, yang hanya terjadi sekali dalam aplikasi Angular. Kalau saja ini sesederhana ini, kita semua akan duduk di pantai dengan penghasilan 20%!
Nocturno
62

Anda juga dapat menggunakan fungsionalitas jqlite bawaan sudut.

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

JordanC
sumber
2
Tanpa jquery dimuat: angular.forEach (document.querySelectorAll ('. Selector'), function (elem) {elem.focus ();});
Dan Benamy
29
Bukankah itu praktik yang buruk untuk memasukkannya ke dalam pengontrol?
VitalyB
2
Jika menempatkan garis jqlite ini di dalam pengontrol adalah praktik yang buruk, bukankah lebih baik untuk menempatkan garis jqlite ini di dalam arahan?
Olah raga
3
Saya mendapatkan ini:Looking up elements via selectors is not supported by jqLite!
Maria Ines Parnisari
1
@VitalyB Saya punya kasus di mana saya perlu mengaburkan elemen setelah panggilan ajax. Saya bisa menambahkan hanya satu baris JS murni dalam callback di dalam controller, atau membangun seluruh arahan khusus untuk mengaburkan input itu. Saya hanya merasa itu terlalu merepotkan, jadi saya memilih opsi pertama.
Sebastianb
55

Ini bekerja dengan baik dan cara sudut untuk memfokuskan kontrol input

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

Meskipun ini bukan cara sudut murni dalam melakukan tugas namun sintaksinya mengikuti gaya sudut. Jquery memainkan peran secara tidak langsung dan langsung mengakses DOM menggunakan Angular (jQLite => JQuery Light).

Jika diperlukan, kode ini dapat dengan mudah dimasukkan ke dalam arahan sudut sederhana di mana elemen dapat diakses secara langsung.

Sanjeev Singh
sumber
Saya tidak yakin itu pendekatan yang bagus untuk ViewModel-apps. Di Angular itu harus dilakukan melalui arahan.
Agat
egJika seseorang mengubah texbox A dan Anda perlu menampilkan sembulan dan mengatur fokus pada kotak teks B. lainnya
Sanjeev Singh
1
Saya mendapatkan kesalahan ini saat menggunakan ini:Looking up elements via selectors is not supported by jqLite!
JVG
6
Sejauh yang saya tahu Anda harus memuat jQuery sebagai ketergantungan pertama, dalam hal ini angular.elementmenjadi pembungkus $() / jQuery(). Jadi tanpa itu ini tidak akan berhasil, dan Anda pada dasarnya hanya menggunakan jQuery (tapi perbaiki jika saya salah)
JVG
@Jascination: jqLite dikembangkan untuk menghapus ketergantungan jQuery. Anda tidak perlu seluruh jQuery untuk mengakses elemen di DOM. Tetapi jika Anda telah menginstal jQuery, maka Angular akan merujuk jQuery. Periksa ini: docs.angularjs.org/api/angular.element
Sanjeev Singh
31

Saya tidak berpikir $ timeout adalah cara yang baik untuk memfokuskan elemen pada penciptaan. Berikut adalah metode yang menggunakan fungsionalitas sudut bawaan, yang digali dari kedalaman suram dokumen sudut. Perhatikan bagaimana atribut "tautan" dapat dipecah menjadi "pra" dan "pos", untuk fungsi pra-tautan dan pasca-tautan.

Contoh Kerja: 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 />

Dokumen Petunjuk AngularJS Lengkap: https://docs.angularjs.org/api/ng/service/$compile

Cody Moniz
sumber
2
Harus membungkus elemen [0] .focus () dalam $ timeout untuk membuatnya berfungsi untuk saya.
codin
@bbodenmiller Modal saya memiliki hal fade-out yang diterapkan, ketika elemen dibangun tidak terlihat (100% transparan), sehingga browser memblokir pemanggilan fokus secara diam-diam. Rupanya beberapa milidetik berlalu memungkinkan untuk fokus pada input / tombol hampir transparan tetapi terlihat.
Snowindy
1
per dokumen, fungsi "tautan" adalah "postLink" secara default. juga lihat: bennadel.com/blog/…
jody tate
17

Ini solusi asli saya:

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

Dan HTML:

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

Apa fungsinya:

Ini memfokuskan input karena menjadi terlihat dengan ng-show. Tidak ada penggunaan $ watch atau $ di sini.

Edhowler
sumber
Sebenarnya saya percaya {{isVisible}} tetap membuat arloji, jadi pernyataan "No use of $ watch" tidak benar.
masimplo
Ya, saya pikir Anda benar. Tapi itu masih berfungsi sebagai cara mudah untuk melakukannya.
Edhowler
17

Saya telah menulis arahan fokus mengikat dua arah, seperti halnya model baru-baru ini.

Anda dapat menggunakan arahan fokus seperti ini:

<input focus="someFocusVariable">

Jika Anda membuat variabel scope someFocusVariable true di mana saja di controller Anda, input menjadi fokus. Dan jika Anda ingin "mengaburkan" input Anda, someFocusVariable dapat disetel ke false. Ini seperti jawaban pertama Mark Rajcok tetapi dengan ikatan dua arah.

Ini adalah arahannya:

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

Pemakaian:

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

Ini biola:

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

Umut Benzer
sumber
Ini seharusnya jawaban yang benar. Ini mencakup semua kasus penggunaan.
Kunal
11

Bagi mereka yang menggunakan Angular dengan plugin Bootstrap:

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

Anda dapat mengaitkan openedjanji dengan instance modal:

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

modalInstance.result.then(function ( etc...
BPH
sumber
Baik! Namun dalam kasus saya, $timeoutdengan 50mssedang membutuhkan alih-alih 0.
lk_vc
8

Saya merasa berguna untuk menggunakan ekspresi umum. Dengan cara ini Anda dapat melakukan hal-hal seperti memindahkan fokus secara otomatis ketika input teks valid

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

Atau secara otomatis fokus ketika pengguna menyelesaikan bidang panjang tetap

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

Dan tentu saja fokus setelah memuat

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

Kode untuk arahan:

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

Untuk tidak menghidupkan kembali zombie atau memasang arahan saya sendiri (ok itulah yang saya lakukan):

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
        };
    }
})();
Jon Hieb
sumber
Saya sekarang menggunakan arahan ini dan itu bekerja dengan baik, memecahkan masalah umum, dan tidak terlalu rumit. Menyerah mencari solusi $ timeout-free. Terus temukan komentar yang mengatakan fokus "pada peta jalan" untuk Angular 1.1 dan 1.2, tapi saya menggunakan 2.x dan masih tidak ada manajemen fokus. Heh.
tekHedd
6

Pertama, cara resmi untuk melakukan fokus adalah pada peta jalan untuk 1.1 . Sementara itu, Anda dapat menulis arahan untuk menerapkan fokus pengaturan.

Kedua, untuk menetapkan fokus pada item setelah terlihat saat ini membutuhkan solusi. Cukup tunda panggilan Anda ke fokus elemen () dengan a $timeout.

Karena masalah kontroler-modifikasi-DOM yang sama ada untuk fokus, kabur dan pilih, saya mengusulkan memiliki ng-targetarahan:

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

Utas sudut di sini: http://goo.gl/ipsx4 , dan detail lainnya di-blog di sini: http://goo.gl/4rdZa

Arahan berikut akan membuat .focus()fungsi di dalam controller Anda seperti yang ditentukan oleh ng-targetatribut Anda . (Ini membuat .blur()dan .select()juga.) Demo: http://jsfiddle.net/bseib/WUcQX/

broc.seib
sumber
+1 untuk referensi peta jalan. Sebenarnya saya baru saja melihatnya di dokumentasi 1.2 masih dianggap tidak stabil ( docs.angularjs.org/api/ng.directive:ngFocus )
Edwin Dalorzo
27
@EdwinDalorzo ngFocustampaknya menjadi cara untuk menangani focusacara, bukan cara untuk mengatur fokus pada suatu elemen.
teleclimber
6

Alih-alih membuat arahan Anda sendiri, dimungkinkan untuk hanya menggunakan fungsi javascript untuk mencapai fokus.

Berikut ini sebuah contoh.

Dalam file html:

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

Dalam file javascript, di controller misalnya, tempat Anda ingin mengaktifkan fokus:

document.getElementById("myInputId").focus();
pengguna3657103
sumber
9
Ini bukan 'cara sudut' dan tidak menyarankan orang untuk menyentuh DOM di pengontrol mereka.
smajl
Sebaiknya jangan menggunakan vanila di Angular, karena Angular tidak dapat melacaknya atau tetap menyelaraskannya dengan yang lain.
Edgar Quintero
4

Jika Anda hanya menginginkan fokus sederhana yang dikendalikan oleh ng-klik.

Html:

<input ut-focus="focusTigger">

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

Pengarahan:

'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();
                });
            });
        }
    }
});
TOBlender
sumber
4

Sederhana yang bekerja dengan baik dengan modals:

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

        link: function (scope, element, attrs)
        {


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



        }
    };
}])

Contoh

<input ng-model="your.value" focus-me-now />
Shawn Dotey
sumber
Sempurna untukku. Terima kasih
Alexander
3

Anda bisa membuat arahan yang memaksa fokus pada elemen yang didekorasi pada postLinking:

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

Kemudian di html Anda:

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

Ini akan berfungsi untuk elemen-elemen yang di-modals dan ng-if, bukan untuk ng-show karena postLinking hanya terjadi pada pemrosesan HTML.

ibaixas
sumber
3

Mark dan Blesh memiliki jawaban yang luar biasa; Namun, Mark's memiliki kekurangan yang ditunjukkan oleh Blesh (selain rumit untuk diterapkan), dan saya merasa bahwa jawaban Blesh memiliki kesalahan semantik dalam menciptakan layanan yang secara khusus tentang mengirim permintaan fokus ke frontend ketika benar-benar semua yang ia butuhkan adalah cara untuk tunda acara sampai semua arahan mendengarkan.

Jadi di sini adalah apa yang akhirnya saya lakukan yang mencuri banyak dari jawaban Blesh tetapi menjaga semantik acara controller dan layanan "after load" terpisah.

Hal ini memungkinkan acara pengontrol dengan mudah dihubungkan untuk hal-hal selain dari hanya memfokuskan elemen tertentu dan juga memungkinkan untuk menimbulkan overhead fungsi "after load" hanya jika diperlukan, yang mungkin tidak dalam banyak kasus.

Pemakaian

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

  afterLoad(notifyControllerEvent);
});

Sumber

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);
  }
});
Joshperry
sumber
Satu-satunya jawaban, yang saya (seorang pemula lengkap) bisa mengerti. Alih-alih "afterLoad (notifyControllerEvent);", saya biasa "notifyControllerEvent ()". Kalau tidak, itu berakhir dengan beberapa kesalahan.
Vel Murugan S
3

Ini juga memungkinkan untuk digunakan ngModelController. Bekerja dengan 1.6+ (tidak tahu dengan versi yang lebih lama).

HTML

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

JS

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

-

NB: Tergantung dari konteksnya, Anda mungkin harus membungkus dengan fungsi timeout.

NB²: Saat menggunakan controllerAs, ini hampir sama. Cukup ganti name="myForm"dengan name="vm.myForm"dan di JS vm.myForm.myText.$$element.focus();,.

Ludovic Guillaume
sumber
3

Mungkin, solusi paling sederhana pada usia ES6.

Menambahkan arahan satu liner berikut membuat atribut 'autofokus' HTML efektif di Angular.js.

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

Sekarang, Anda bisa menggunakan sintaks autofokus HTML5 seperti:

<input type="text" autofocus>
Tsuneo Yoshioka
sumber
@Sthane ya, jadi itu menjadi.directive('autofocus', ['$timeout', ($timeout) => ({link: (_, e) => $timeout(() => e[0].focus())})])
Michael Plautz
2

Hanya seorang pemula di sini, tapi saya bisa membuatnya bekerja di ui.bootstrap.modal dengan arahan ini:

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

dan dalam metode $ modal.open saya menggunakan mengikuti untuk menunjukkan elemen di mana fokus harus diletakkan:

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

pada template saya punya ini:

<input id="myInputId" focus />
pitervergara
sumber
2

Arahan berikut ini membantu saya. Gunakan atribut html autofokus yang sama untuk input.

.directive('autofocus', [function () {
    return {
        require : 'ngModel',
        restrict: 'A',
        link: function (scope, element, attrs) {
            element.focus();
        }
    };
}])
Kishore Relangi
sumber
1
Anda akan mendapatkan kesalahan saat menjalankan ini kecuali jika jQuery disertakan, seharusnya elemen [0] .focus ()
Ryan M
2

Jika Anda menggunakan modalInstance dan memiliki objek, Anda dapat menggunakan "lalu" untuk melakukan tindakan setelah membuka modal. Jika Anda tidak menggunakan modalInstance, dan kode keras untuk membuka modal Anda dapat menggunakan acara tersebut. Batas waktu $ bukanlah solusi yang baik.

Anda dapat melakukannya (Bootstrap3):

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

Di modalInstance Anda dapat melihat perpustakaan bagaimana mengeksekusi kode setelah modal terbuka.

Jangan gunakan $ timeout seperti ini, $ timeout bisa 0, 1, 10, 30, 50, 200 atau lebih ini akan tergantung pada komputer klien, dan proses untuk membuka modal.

Jangan gunakan $ timeout, biarkan metode memberi tahu Anda kapan Anda bisa fokus;)

Saya harap ini membantu! :)

Filipe Cotrim Melo
sumber
2

Semua jawaban sebelumnya tidak berfungsi jika elemen fokus yang diinginkan disuntikkan dalam template direktif. Direktif berikut cocok untuk elemen sederhana atau elemen yang disuntikkan direktif (saya menulisnya dalam naskah ). itu menerima pemilih untuk elemen fokus dalam. jika Anda hanya perlu memfokuskan elemen mandiri - jangan mengirim parameter pemilih ke arahan:

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

}

contoh penggunaan untuk elemen sederhana:

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

contoh penggunaan untuk elemen dalam (biasanya untuk elemen injeksi dinamis seperti direktif dengan template):

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

Anda dapat menggunakan pemilih jQuery apa saja alih-alih "input"

Ofir Meguri
sumber
2

Saya mengedit arahan fokusMe Mark Rajcok agar berfungsi untuk beberapa fokus dalam satu elemen.

HTML:

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

di AngularJs Controller:

$scope.myInputFocus= true;

Petunjuk AngulaJS:

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);
                }
            });
        }
    };
});
Mohamad Khani
sumber
1

Saya ingin berkontribusi dalam diskusi ini setelah mencari solusi yang lebih baik dan tidak menemukannya, harus membuatnya.

Kriteria: 1. Solusi harus independen dari lingkup pengendali induk untuk meningkatkan kegunaan kembali. 2. Hindari penggunaan $ watch untuk memantau beberapa kondisi, ini lambat, meningkatkan ukuran loop digest dan membuat pengujian lebih sulit. 3. Hindari $ timeout atau $ scope. $ Apply () untuk memicu loop intisari. 4. Elemen input hadir dalam elemen di mana Directive digunakan terbuka.

Ini adalah solusi yang paling saya sukai:

Pengarahan:

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

Saya harap ini akan membantu seseorang di luar sana!

xiaoma
sumber
Anda baru saja membuat ulang apa yang html "label" lakukan, Anda hanya bisa mengganti "div focus-input" dengan "label" dan menyingkirkan direktif.
frst
1

Mudah .. coba ini

html

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

javascript

document.getElementById("ddl00").focus();
isanka thalagala
sumber
Benar di luar konteks, tetapi bukan cara AngularJS dalam melakukan sesuatu
CodeMonkey
1

Jika Anda ingin menetapkan fokus pada elemen tertentu, Anda dapat menggunakan pendekatan di bawah ini.

  1. Buat layanan yang disebut 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. Masukkan ke dalam pengontrol dari tempat Anda ingin menelepon.

  3. Panggil layanan ini.

Rakesh Burbure
sumber
0

Saya pikir arahan tidak perlu. Gunakan id HTML dan atribut kelas untuk memilih elemen yang diperlukan dan meminta layanan menggunakan document.getElementById atau document.querySelector untuk menerapkan fokus (atau setara dengan jQuery).

Markup adalah arahan HTML / sudut standar dengan id / kelas tambahan untuk seleksi

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

Pengendali siaran acara

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

Dalam layanan UI menggunakan querySelector - jika ada beberapa pertandingan (katakanlah karena kelas) itu hanya akan mengembalikan yang pertama

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

Anda mungkin ingin menggunakan $ timeout () untuk memaksakan siklus intisari

johans
sumber
0

Hanya melempar kopi.

app.directive 'ngAltFocus', ->
    restrict: 'A'
    scope: ngAltFocus: '='
    link: (scope, el, attrs) ->
        scope.$watch 'ngAltFocus', (nv) -> el[0].focus() if nv
Talasan Nicholson
sumber