Saya ingin menutup dropdown menu login saya ketika pengguna mengklik di mana saja di luar dropdown itu, dan saya ingin melakukannya dengan Angular2 dan dengan "pendekatan" Angular2 ...
Saya telah mengimplementasikan solusi, tetapi saya benar-benar tidak merasa yakin dengan itu. Saya pikir pasti ada cara termudah untuk mencapai hasil yang sama, jadi jika Anda punya ide ... mari kita bahas :)!
Inilah implementasi saya:
Komponen dropdown:
Ini adalah komponen untuk dropdown saya:
- Setiap kali komponen ini disetel ke terlihat, (Misalnya: ketika pengguna mengklik tombol untuk menampilkannya) ia berlangganan ke subjek "global" rxjs yang disimpan oleh userMenu di dalam SubjectsService .
- Dan setiap kali disembunyikan, ia berhenti berlangganan ke subjek ini.
- Setiap klik di mana saja di dalam templat komponen ini memicu metode onClick () , yang hanya menghentikan peristiwa yang menggelegak ke atas (dan komponen aplikasi)
Ini kodenya
export class UserMenuComponent {
_isVisible: boolean = false;
_subscriptions: Subscription<any> = null;
constructor(public subjects: SubjectsService) {
}
onClick(event) {
event.stopPropagation();
}
set isVisible(v) {
if( v ){
setTimeout( () => {
this._subscriptions = this.subjects.userMenu.subscribe((e) => {
this.isVisible = false;
})
}, 0);
} else {
this._subscriptions.unsubscribe();
}
this._isVisible = v;
}
get isVisible() {
return this._isVisible;
}
}
Komponen aplikasi:
Di sisi lain, ada komponen aplikasi (yang merupakan induk dari komponen dropdown):
- Komponen ini menangkap setiap acara klik dan memancarkan pada subjek rxjs yang sama ( userMenu )
Ini kodenya:
export class AppComponent {
constructor( public subjects: SubjectsService) {
document.addEventListener('click', () => this.onClick());
}
onClick( ) {
this.subjects.userMenu.next({});
}
}
Apa yang mengganggu saya:
- Saya tidak merasa benar-benar nyaman dengan gagasan memiliki Subjek global yang bertindak sebagai penghubung antara komponen-komponen itu.
- The setTimeout : Hal ini diperlukan karena di sini adalah apa yang terjadi sebaliknya jika pengguna mengklik tombol yang menunjukkan dropdown:
- Pengguna mengklik tombol (yang bukan merupakan bagian dari komponen dropdown) untuk menampilkan dropdown.
- Dropdown ditampilkan dan segera berlangganan ke subjek userMenu .
- Acara klik menggembung ke komponen aplikasi dan tertangkap
- Komponen aplikasi memancarkan suatu peristiwa pada subjek userMenu
- Komponen dropdown menangkap tindakan ini pada userMenu dan menyembunyikan dropdown.
- Pada akhirnya dropdown tidak pernah ditampilkan.
Set timeout ini menunda langganan ke akhir pergantian kode JavaScript saat ini yang menyelesaikan masalah, tetapi menurut cara yang sangat elegan menurut saya.
Jika Anda tahu solusi yang lebih bersih, lebih baik, lebih cerdas, lebih cepat atau lebih kuat, beri tahu saya :)!
Jawaban:
Anda dapat menggunakan
(document:click)
acara:Pendekatan lain adalah membuat acara khusus sebagai arahan. Lihatlah pos-pos ini oleh Ben Nadel:
sumber
@HostListener('document:click', ['$event'])
bukanhost
properti diComponent
dekorator.Observable.fromEvent(document, 'click').subscribe(event => {your code here})
, jadi Anda selalu dapat berlangganan hanya ketika Anda perlu mendengarkan misalnya Anda membuka dropdown, dan ketika Anda menutupnya Anda berhenti berlanggananMETODE ELEGAN
Saya menemukan
clickOut
arahan ini : https://github.com/chliebel/angular2-click-outside . Saya memeriksanya dan berfungsi dengan baik (saya hanya menyalinclickOutside.directive.ts
ke proyek saya). Anda dapat menggunakannya dengan cara ini:Di mana
close
fungsi Anda yang akan dipanggil ketika pengguna mengklik di luar div. Ini adalah cara yang sangat elegan untuk menangani masalah yang dijelaskan dalam pertanyaan.Jika Anda menggunakan arahan di atas untuk menutup jendela popUp, ingatlah terlebih dahulu untuk menambahkan
event.stopPropagation()
tombol pengendali acara yang membuka popUp.BONUS:
Di bawah ini saya menyalin kode arahan oryginal dari file
clickOutside.directive.ts
(jika tautan akan berhenti berfungsi di masa mendatang) - penulisnya adalah Christian Liebel :Tampilkan cuplikan kode
sumber
<div class="wrap" *ngIf="isOpened" (clickOutside)="...// this should set this.isOpen=false"
Saya sudah melakukannya dengan cara ini.
Menambahkan pendengar acara pada dokumen
click
dan dalam handler itu memeriksa jika sayacontainer
berisievent.target
, jika tidak - sembunyikan dropdown.Akan terlihat seperti ini.
sumber
this.offClickHandler
fungsi panah.Saya pikir Sasxa menerima jawaban berfungsi untuk kebanyakan orang. Namun, saya mengalami situasi, di mana konten Elemen, yang seharusnya mendengarkan acara di luar klik, berubah secara dinamis. Jadi Elemen nativeElement tidak mengandung event.target, saat itu dibuat secara dinamis. Saya bisa menyelesaikan ini dengan arahan berikut
Alih-alih memeriksa apakah elementRef berisi event.target, saya memeriksa apakah elementRef ada di jalur (jalur DOM ke target) dari acara tersebut. Dengan begitu dimungkinkan untuk menangani Elemen yang dibuat secara dinamis.
sumber
Jika Anda melakukan ini di iOS, gunakan
touchstart
acara ini juga:Pada Angular 4,
HostListener
menghias adalah cara yang disukai untuk melakukan inisumber
Kami telah mengerjakan masalah serupa di tempat kerja hari ini, mencoba mencari cara bagaimana membuat dropdown div menghilang ketika diklik. Pertanyaan kami sedikit berbeda dari pertanyaan poster awal karena kami tidak ingin mengeklik komponen atau arahan yang berbeda , tetapi hanya di luar div tertentu.
Kami akhirnya menyelesaikannya dengan menggunakan pengendali event (window: mouseup).
Langkah-langkah:
1.) Kami memberikan seluruh div menu dropdown nama kelas yang unik.
2.) Pada menu dropdown dalam itu sendiri (satu-satunya bagian yang kita inginkan klik untuk TIDAK menutup menu), kami menambahkan event handler (window: mouseup) dan lulus dalam $ event.
CATATAN: Ini tidak dapat dilakukan dengan handler "klik" yang khas karena ini bertentangan dengan handler klik induk.
3.) Di controller kami, kami menciptakan metode yang kami ingin dipanggil pada acara klik, dan kami menggunakan event.closest ( docs di sini ) untuk mengetahui apakah tempat yang diklik berada di dalam kelas kelas yang ditargetkan.
sumber
.closest()
tidak didukung pada IE / Ujung untuk hari ini ( caniuse )Anda bisa membuat elemen saudara pada dropdown yang menutupi seluruh layar yang tidak terlihat dan berada di sana hanya untuk menangkap peristiwa klik. Kemudian Anda bisa mendeteksi klik pada elemen itu dan menutup dropdown ketika diklik. Katakanlah elemen itu dari layar silks kelas, berikut beberapa gaya untuknya:
Indeks-z harus cukup tinggi untuk menempatkannya di atas segalanya kecuali dropdown Anda. Dalam hal ini dropdown saya akan b-indeks 2.
Jawaban lain bekerja dalam beberapa kasus untuk saya, kecuali kadang-kadang dropdown saya ditutup ketika saya berinteraksi dengan elemen-elemen di dalamnya dan saya tidak menginginkannya. Saya secara dinamis menambahkan elemen yang tidak terkandung dalam komponen saya, sesuai dengan target acara, seperti yang saya harapkan. Daripada memilah yang berantakan saya pikir saya hanya akan mencobanya dengan cara silkscreen.
sumber
Saya tidak menemukan solusi. Saya baru saja melampirkan dokumen: klik pada fungsi sakelar saya sebagai berikut:
Jadi, ketika saya berada di luar arahan saya, saya menutup dropdown.
sumber
BAWAHKAN: - Pendengar acara klik dua kali untuk setiap komponen ini di halaman. Jangan gunakan ini pada komponen yang ada di halaman ratusan kali.
sumber
Saya ingin melengkapi jawaban @Tony, karena acara tersebut tidak dihapus setelah klik di luar komponen. Tanda terima lengkap:
Tandai elemen utama Anda dengan #container
Pada elemen yang dapat diklik, gunakan:
Sekarang Anda dapat mengontrol status dropdown Anda dengan variabel dropstatus, dan menerapkan kelas yang tepat dengan [ngClass] ...
sumber
Anda dapat menulis arahan:
Di komponen Anda:
Acara memancarkan arahan ini ketika elemen html mengandung di DOM dan ketika properti input [clickOut] 'benar'. Ini mendengarkan acara mousedown untuk menangani acara sebelum elemen akan dihapus dari DOM.
Dan satu catatan: firefox tidak mengandung properti 'path' jika Anda dapat menggunakan fungsi untuk membuat path:
Jadi, Anda harus mengubah event handler di directive: event.path harus diganti getEventPath (event)
Modul ini dapat membantu. https://www.npmjs.com/package/ngx-clickout Ini berisi logika yang sama tetapi juga menangani acara esc pada elemen html sumber.
sumber
Jawaban yang benar memiliki masalah, jika Anda memiliki komponen clicakble di popover Anda, elemen tidak akan lagi pada
contain
metode dan akan ditutup, berdasarkan @ JuHarm89 saya membuat sendiri:Terima kasih untuk bantuannya!
sumber
Versi yang lebih baik untuk @Tony solusi hebat:
Dalam file css: // TIDAK diperlukan jika Anda menggunakan drop-down bootstrap.
sumber
Anda harus memeriksa jika Anda mengklik pada overlay modal, jauh lebih mudah.
Template Anda:
Dan metodenya:
sumber
Saya telah membuat arahan untuk mengatasi masalah serupa ini dan saya menggunakan Bootstrap. Tetapi dalam kasus saya, daripada menunggu acara klik di luar elemen untuk menutup menu dropdown yang dibuka saat ini saya pikir lebih baik jika kita menonton acara 'mouseleave' untuk secara otomatis menutup menu.
Inilah solusi saya:
Pengarahan
HTML
sumber
Jika Anda menggunakan Bootstrap, Anda dapat melakukannya langsung dengan cara bootstrap melalui dropdown (komponen Bootstrap).
Sekarang tidak apa-apa untuk meletakkan
(click)="clickButton()"
barang di tombol. http://getbootstrap.com/javascript/#dropdownssumber
Saya juga melakukan sedikit penyelesaian sendiri.
Saya membuat acara (dropdownOpen) yang saya dengarkan di komponen elemen ng-select saya dan memanggil fungsi yang akan menutup semua SelectComponent lainnya yang dibuka terlepas dari SelectComponent yang saat ini dibuka.
Saya memodifikasi satu fungsi di dalam file select.ts seperti di bawah ini untuk memancarkan acara:
Dalam HTML saya menambahkan pendengar acara untuk (dropdownOpened) :
Ini adalah fungsi panggilan saya pada pemicu acara di dalam komponen yang memiliki tag ng2-select:
sumber
CATATAN: Bagi mereka yang ingin menggunakan pekerja web dan Anda harus menghindari menggunakan dokumen dan nativeElement, ini akan berfungsi.
Saya menjawab pertanyaan yang sama di sini: /programming/47571144
Salin / Tempel dari tautan di atas:
Saya memiliki masalah yang sama ketika saya membuat menu drop-down dan dialog konfirmasi yang ingin saya abaikan saat mengklik di luar.
Implementasi akhir saya berfungsi dengan baik tetapi membutuhkan beberapa animasi dan gaya css3.
CATATAN : saya belum menguji kode di bawah ini, mungkin ada beberapa masalah sintaks yang perlu disetrika, juga penyesuaian yang jelas untuk proyek Anda sendiri!
Apa yang saya lakukan:
Saya membuat div tetap terpisah dengan tinggi 100%, lebar 100% dan mengubah: skala (0), ini pada dasarnya adalah latar belakang, Anda dapat mengaturnya dengan warna-latar belakang: rgba (0, 0, 0, 0,466); untuk memperjelas menu terbuka dan latar belakang klik untuk menutup. Menu mendapat indeks-z lebih tinggi dari yang lainnya, maka div latar belakang mendapat indeks-z lebih rendah dari menu tetapi juga lebih tinggi dari yang lainnya. Kemudian latar belakang memiliki acara klik yang menutup drop-down.
Ini dia dengan kode html Anda.
Inilah css3 yang membutuhkan beberapa animasi sederhana.
Jika Anda tidak mengejar apa pun visual Anda hanya dapat menggunakan transisi seperti ini
sumber
Saya menemukan solusi lain, terinspirasi oleh contoh-contoh dengan acara fokus / blur.
Jadi, jika Anda ingin mencapai fungsi yang sama tanpa melampirkan pendengar dokumen global, Anda dapat mempertimbangkan sebagai contoh berikut yang valid. Ini juga berfungsi di Safari dan Firefox di OSx, meskipun mereka memiliki penanganan acara fokus tombol lainnya: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#Clicking_and_focus
Contoh kerja pada stackbiz dengan sudut 8: https://stackblitz.com/edit/angular-sv4tbi?file=src%2Ftoggle-dropdown%2Ftoggle-dropdown.directive.ts
Markup HTML:
Arahan akan terlihat seperti ini:
sumber
Anda dapat menggunakannya
mouseleave
dalam tampilan seperti iniUji dengan sudut 8 dan bekerja dengan sempurna
sumber
METODE PALING ELEGAN: D
Ada satu cara termudah untuk melakukan itu, tidak perlu arahan untuk itu.
"element-that-toggle-your-dropdown" harus berupa tag tombol. Gunakan metode apa pun dalam atribut (blur). Itu saja.
sumber