আমি কীভাবে বাইরে ক্লিক করে একটি ড্রপডাউন বন্ধ করতে পারি?


144

আমি যখন ব্যবহারকারী সেই ড্রপডাউনটির বাইরে যে কোনও জায়গায় ক্লিক করে আমার লগইন মেনু ড্রপডাউনটি বন্ধ করতে চাই এবং আমি এটি Angular2 এবং Angular2 "অ্যাপ্রোচ" দিয়ে করতে চাই ...

আমি একটি সমাধান বাস্তবায়ন করেছি, তবে আমি এটির সাথে সত্যই আত্মবিশ্বাসী বোধ করি না। আমি মনে করি একই ফলটি অর্জনের একটি সহজ উপায় থাকতে হবে, সুতরাং আপনার যদি কিছু ধারণা থাকে ... আসুন আলোচনা করুন :)!

আমার বাস্তবায়ন এখানে:

ড্রপডাউন উপাদান:

এটি আমার ড্রপডাউনয়ের উপাদান:

  • প্রতিটি সময় এই উপাদানটি এটিকে দৃশ্যমান সেট করতে চান, (উদাহরণস্বরূপ: একটি বোতামে ব্যবহারকারী ক্লিক এটি প্রদর্শন করে যখন) এটি একটি "বিশ্বব্যাপী" সাবস্ক্রাইব rxjs বিষয় userMenu মধ্যে সঞ্চিত SubjectsService
  • এবং যতবার এটি লুকানো থাকে ততবার এই বিষয়টিকে সাবস্ক্রাইব করে।
  • এই উপাদানটির টেমপ্লেটের মধ্যে যে কোনও জায়গায় ক্লিক ক্লিক করে অনক্লিক () পদ্ধতিটি ট্রিগার করে , যা কেবল ইভেন্টটি উপরের দিকে (এবং অ্যাপ্লিকেশন উপাদান) বুদবুদ থামিয়ে দেয় which

কোডটি এখানে

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

অ্যাপ্লিকেশন উপাদান:

অন্যদিকে, অ্যাপ্লিকেশন উপাদান রয়েছে (যা ড্রপডাউন উপাদানটির পিতামাতা):

  • এই উপাদানটি প্রতিটি ক্লিক ইভেন্টটি ধরে এবং একই rxjs সাবজেক্টে ( ব্যবহারকারীমেনু ) প্রেরণ করে

কোডটি এখানে:

export class AppComponent {

    constructor( public subjects: SubjectsService) {
        document.addEventListener('click', () => this.onClick());
    }
    onClick( ) {
        this.subjects.userMenu.next({});
    }
}

আমাকে কী বিরক্ত করেছে:

  1. আমি একটি গ্লোবাল সাবজেক্ট থাকা এই ধারণাগুলির মধ্যে সংযোগকারী হিসাবে কাজ করার ধারণার সাথে সত্যই স্বাচ্ছন্দ্য বোধ করি না।
  2. setTimeout এই প্রয়োজন হয় কারণ এখানে কি অন্যথায় ঘটতে যে যদি ড্রপডাউন দেখান বাটনে ব্যবহারকারী ক্লিক হল:
    • ড্রপডাউনটি দেখানোর জন্য ব্যবহারকারী বোতামটিতে ক্লিক করুন (যা ড্রপডাউন উপাদানটির একটি অংশ নয়)।
    • ড্রপডাউন প্রদর্শিত হয় এবং এটি অবিলম্বে ব্যবহারকারীমেনু সাবস্ক্রাইব করে
    • অ্যাপ্লিকেশন উপাদানটি ক্লিক ইভেন্ট বুদবুদ এবং ধরা পড়ে
    • অ্যাপ্লিকেশন উপাদানটি ব্যবহারকারীমেনু বিষয়ে একটি ইভেন্ট নির্গত করে
    • ড্রপডাউন উপাদান ধরা এই কর্ম userMenu এবং ড্রপডাউন লুকান।
    • শেষে ড্রপডাউনটি কখনই প্রদর্শিত হয় না।

এই সেট টাইমআউটটি বর্তমান জাভাস্ক্রিপ্ট কোড টার্নের সাবস্ক্রিপশনটিকে বিলম্ব করে যা সমস্যার সমাধান করে তবে আমার মতে খুব মার্জিত উপায়ে।

আপনি যদি ক্লিনার, আরও ভাল, স্মার্ট, দ্রুত বা শক্তিশালী সমাধানগুলি জানেন তবে দয়া করে আমাকে জানান :)!


: এই আপনি যে উত্তরগুলি কিছু ধারনা দিতে পারে stackoverflow.com/a/35028820/215945 , stackoverflow.com/questions/35024495#35024651
মার্ক Rajcok

উত্তর:


245

আপনি (document:click)ইভেন্টটি ব্যবহার করতে পারেন :

@Component({
  host: {
    '(document:click)': 'onClick($event)',
  },
})
class SomeComponent() {
  constructor(private _eref: ElementRef) { }

  onClick(event) {
   if (!this._eref.nativeElement.contains(event.target)) // or some similar check
     doSomething();
  }
}

আর একটি পদ্ধতি হ'ল নির্দেশ হিসাবে কাস্টম ইভেন্ট তৈরি করা। বেন নাদেল এই পোস্টগুলি দেখুন:


1
@ সাস্সা আপনাকে ধন্যবাদ, এবং সম্মত হয়েছে। আমি অনুধাবন করেছিলাম যদি কোনও অবচয়হীন এপিআই ডক থাকে, তবে এটি অনুসন্ধানে আমাকে এখানে নিয়ে যায়।
ডানলডুইগ

4
যদি ইভেন্ট.আরটিজেট এমন উপাদান হয় যা একটি [অভ্যন্তরীণ এইচটিএমএল] বাইন্ডিংয়ের মতো কোনও কিছুর মাধ্যমে গতিশীলভাবে যুক্ত হয়েছিল তবে উপাদানটিফের নেটিমেট এলিমেন্ট এতে থাকবে না।
প্যাট্রিক গ্রাহাম

8
এই কৌশলটির একমাত্র ক্ষতি হ'ল আপনার অ্যাপ্লিকেশনটিতে এখন একটি ক্লিক ইভেন্ট শ্রোতা রয়েছে যা আপনি যখনই ক্লিক করেন ততবার আগুন জ্বলে।
কোডেপিক

37
অফিসিয়াল অ্যাঙ্গুলার 2 স্টাইল গাইড অনুসারে আপনার সাজসজ্জার @HostListener('document:click', ['$event'])জায়গায় hostসম্পত্তি পরিবর্তে ব্যবহার করা উচিত Component
মাইচা মিসজিজিজিন

15
অথবা আপনি শুধু তার জন্য rxjs ব্যবহার করতে পারে, মত Observable.fromEvent(document, 'click').subscribe(event => {your code here}), ফলে আপনি সর্বদা সাবস্ক্রাইব করতে পারেন শুধুমাত্র যখন আপনি ড্রপডাউন খোলা, এবং যখন আপনি কি এটি বন্ধ আপনি সদস্যতামুক্ত উদাহরণস্বরূপ শুনতে হবে
ব্লাইন্ড নিরাশ হয়ো

42

মার্জিত পদ্ধতি

আমি এই clickOutনির্দেশটি পেয়েছি : https://github.com/chliebel/angular2- ক্লিক- আউটসাইড । আমি এটি পরীক্ষা করি এবং এটি ভাল কাজ করে (আমি কেবল clickOutside.directive.tsআমার প্রকল্পে অনুলিপি করি)। আপনি এটি এইভাবে ব্যবহার করতে পারেন:

<div (clickOutside)="close($event)"></div>

কোথায় closeআপনার ফাংশনটি যা কল করা হবে যখন ব্যবহারকারী বাইরের ডিভিতে ক্লিক করেন। প্রশ্নে বর্ণিত সমস্যা পরিচালনা করার জন্য এটি খুব মার্জিত উপায়।

আপনি যদি পপআপ উইন্ডোটি বন্ধ করতে উপরের নির্দেশিকাটি ব্যবহার করেন তবে যুক্ত করার আগে মনে রাখবেন event.stopPropagation() পপআপ খোলার ইভেন্ট হ্যান্ডলার বোতামে করার ।

বোনাস:

আমি নীচে ফাইল থেকে অরগিনাল ডাইরেক্টিভ কোডটি অনুলিপি করেছি clickOutside.directive.ts(যদি ভবিষ্যতে লিঙ্কটি কাজ করা বন্ধ করে দেয়) - লেখক হলেন ক্রিশ্চান লাইবল :


2
@ ভেগা আমার পুনঃসংশোধনটি হ'ল * এনজিআইফের সাথে কোনও উপাদানগুলিতে নির্দেশিকাটি ব্যবহার করা হবে, ড্রপডাউনগুলির ক্ষেত্রে এটি এমন কিছু হতে পারে<div class="wrap" *ngIf="isOpened" (clickOutside)="...// this should set this.isOpen=false"
গ্যাব্রিয়েল বালসা ক্যান্টে

19

আমি এইভাবে এটি সম্পন্ন করেছি।

দস্তাবেজে একটি ইভেন্ট শ্রোতা যুক্ত হয়েছে clickএবং সেই হ্যান্ডলারে আমার containerরয়েছে কিনা তা পরীক্ষা করেevent.target করে দেখানো হয়েছে - ড্রপডাউনটি লুকান।

এটি দেখতে এই মত হবে।

@Component({})
class SomeComponent {
    @ViewChild('container') container;
    @ViewChild('dropdown') dropdown;

    constructor() {
        document.addEventListener('click', this.offClickHandler.bind(this)); // bind on doc
    }

    offClickHandler(event:any) {
        if (!this.container.nativeElement.contains(event.target)) { // check click origin
            this.dropdown.nativeElement.style.display = "none";
        }
    }
}

ওহে. The.bind (এটি) প্রয়োজনীয়?
ড্রেনাই

1
@ ব্রায়ান এটি প্রয়োজনীয় বা নাও হতে পারে, তবে তিনি যদি this.offClickHandlerএকটি তীর ফাংশনটি গুটিয়ে রাখেন তবে অবশ্যই তা হবে না ।
ল্যানসানা কামারা

17

আমি মনে করি সাসকা গৃহীত উত্তর বেশিরভাগ লোকের পক্ষে কাজ করে। যাইহোক, আমার একটি পরিস্থিতি ছিল, যেখানে এলিমেটের সামগ্রীটি অফ-ক্লিক ইভেন্টগুলি শোনানো উচিত, গতিশীলভাবে পরিবর্তিত হয়েছিল। সুতরাং যখন উপাদানগুলি গতিশীলভাবে তৈরি করা হয়েছিল তখন এলিমেন্টস নেটিমেলে ইভেন্ট.আরগেট ধারণ করে না। আমি নিম্নলিখিত নির্দেশাবলী দিয়ে এটি সমাধান করতে পারে

@Directive({
  selector: '[myOffClick]'
})
export class MyOffClickDirective {

  @Output() offClick = new EventEmitter();

  constructor(private _elementRef: ElementRef) {
  }

  @HostListener('document:click', ['$event.path'])
  public onGlobalClick(targetElementPath: Array<any>) {
    let elementRefInPath = targetElementPath.find(e => e === this._elementRef.nativeElement);
    if (!elementRefInPath) {
      this.offClick.emit(null);
    }
  }
}

এলিমেন্টেফ-এ ইভেন্ট.আরগারেট রয়েছে কিনা তা যাচাই করার পরিবর্তে, আমি পরীক্ষা করে দেখি যে অ্যালিমিনআরফ ইভেন্টের পথে (ডিওএম টার্গেটের দিকে) রয়েছে কিনা। এইভাবে গতিশীলভাবে তৈরি এলিমেন্টগুলি পরিচালনা করা সম্ভব।


ধন্যবাদ - শিশু উপাদান উপস্থিত থাকলে এটি আরও ভাল কাজ করে
মাহসান

এটি আমার পক্ষে অনেক সহায়ক ছিল। উপাদানগুলির ক্লিকের বাইরের উত্তরগুলির সাথে কেন সনাক্ত করা হচ্ছে তা নিশ্চিত নয়।
জাভাকুয়েস্ট

13

আপনি যদি আইওএসে এটি করছেন তবে এটি ব্যবহার করুন touchstart ইভেন্টটিও :

কৌণিক 4 হিসাবে, HostListenerসাজানোর জন্য এটি করা পছন্দসই উপায়

import { Component, OnInit, HostListener, ElementRef } from '@angular/core';
...
@Component({...})
export class MyComponent implement OnInit {

  constructor(private eRef: ElementRef){}

  @HostListener('document:click', ['$event'])
  @HostListener('document:touchstart', ['$event'])
  handleOutsideClick(event) {
    // Some kind of logic to exclude clicks in Component.
    // This example is borrowed Kamil's answer
    if (!this.eRef.nativeElement.contains(event.target) {
      doSomethingCool();
    }
  }

}

10

আমরা আজ কাজের অনুরূপ ইস্যুতে কাজ করছি, ক্লিক করার পরে কীভাবে একটি ড্রপডাউন ডিভ অদৃশ্য করা যায় তা নির্ধারণের চেষ্টা করছি। আমাদের প্রাথমিক পোস্টারের প্রশ্নের চেয়ে কিছুটা আলাদা কারণ আমরা কোনও আলাদা উপাদান বা দিকনির্দেশনা থেকে দূরে ক্লিক করতে চাইনি , তবে কেবলমাত্র নির্দিষ্ট ডিভের বাইরে।

আমরা উইন্ডো: মাউসআপ) ইভেন্ট হ্যান্ডলারটি ব্যবহার করে এটি সমাধান করেছি।

পদক্ষেপ:
1.) আমরা পুরো ড্রপডাউন মেনু ডিভি একটি অনন্য শ্রেণীর নাম দিয়েছি।

২) অভ্যন্তরীণ ড্রপডাউন মেনুতে (মেনুটি বন্ধ না করার জন্য আমরা ক্লিকগুলি চেয়েছিলাম এমন একমাত্র অংশ), আমরা একটি (উইন্ডো: মাউসআপ) ইভেন্ট হ্যান্ডলার যুক্ত করে $ ইভেন্টে পাস করেছি।

দ্রষ্টব্য: এটি একটি সাধারণ "ক্লিক" হ্যান্ডলারের সাহায্যে করা যায়নি কারণ এটি প্যারেন্ট ক্লিক হ্যান্ডলারের সাথে বিরোধী।

৩) আমাদের নিয়ামকটিতে, আমরা সেই পদ্ধতিটি তৈরি করেছি যা আমরা ক্লিক আউট ইভেন্টে কল করতে চেয়েছিলাম এবং ক্লিক করা স্পটটি আমাদের টার্গেট-শ্রেণির ডিভের মধ্যে রয়েছে কিনা তা খুঁজে বের করার জন্য আমরা ইভেন্ট কলোস্ট ( ডক্স এখানে ) ব্যবহার করি ।

 autoCloseForDropdownCars(event) {
        var target = event.target;
        if (!target.closest(".DropdownCars")) { 
            // do whatever you want here
        }
    }
 <div class="DropdownCars">
   <span (click)="toggleDropdown(dropdownTypes.Cars)" class="searchBarPlaceholder">Cars</span>
   <div class="criteriaDropdown" (window:mouseup)="autoCloseForDropdownCars($event)" *ngIf="isDropdownShown(dropdownTypes.Cars)">
   </div>
</div>


হোস্ট ডেকরেটারের মধ্যে "উইন্ডো: মাউসআপ" ব্যবহার করা উচিত।
শিবাম

@ শিবম-- আমি নিশ্চিত না আপনি কী বোঝাতে চেয়েছেন "হোস্ট সাজসজ্জারের মধ্যে ব্যবহার করা উচিত।" আপনি সম্ভবত আরও ব্যাখ্যা করতে পারেন? ধন্যবাদ!
পাইগে বোল্ডুক

আমি বলতে চাইছি "উইন্ডো" অবজেক্টটি সরাসরি ব্যবহার করার পরিবর্তে, আপনাকে উপাদানটির সাজসজ্জার / "হোস্টলিস্টনার" সারণীর "হোস্ট" সম্পত্তি ব্যবহার করা উচিত। কৌণিক ২ তে "উইন্ডো" বা "ডকুমেন্ট" অবজেক্টের সাথে কাজ করার সময় এটি স্ট্যান্ডার্ড অনুশীলন
শিবাম

2
ব্রাউজারের সামঞ্জস্যের জন্য কেবল নজর রাখুন, .closest()আইই / এজ তে আজ ( ক্যানিয়াস ) সমর্থিত নয়
সুপারজাস

5

আপনি ড্রপডাউনে একটি ভাইবোন উপাদান তৈরি করতে পারেন যা পুরো পর্দাটি অদৃশ্য হয়ে যায় এবং কেবল ক্লিক ইভেন্টগুলি ক্যাপচারের জন্য সেখানে উপস্থিত থাকে covers তারপরে আপনি সেই উপাদানটির ক্লিকগুলি সনাক্ত করতে পারেন এবং ক্লিক করার পরে ড্রপডাউনটি বন্ধ করতে পারেন। আসুন আমরা বলতে পারি যে উপাদানটি সিল্কস্ক্রিনের, এটির জন্য এখানে কিছু স্টাইল রয়েছে:

.silkscreen {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 1;
}

জেড-সূচকটি আপনার ড্রপডাউন বাদে সমস্ত কিছুর positionর্ধ্বে অবস্থানের জন্য পর্যাপ্ত পরিমাণে হওয়া দরকার। এক্ষেত্রে আমার ড্রপডাউনটি জেড-ইনডেক্স 2 হবে।

অন্যান্য উত্তরগুলি আমার জন্য কিছু ক্ষেত্রে কাজ করেছিল, কখনও কখনও আমার ড্রপডাউনটি বন্ধ হয়ে যায় যখন আমি এর মধ্যে থাকা উপাদানগুলির সাথে যোগাযোগ করি এবং আমি তা চাই না। ইভেন্টের লক্ষ্য অনুসারে, আমি গতিশীলভাবে এমন উপাদান যুক্ত করেছি যারা আমার উপাদানগুলির মধ্যে অন্তর্ভুক্ত ছিল না, যেমনটি আমি প্রত্যাশা করেছিলাম। এই জগাখিচুড়ি বাছাইয়ের পরিবর্তে আমি বুঝতে পেরেছিলাম আমি এটি সিলস্ক্রিন উপায়ে চেষ্টা করব।


5

আমি কোনও কাজই করতে পারিনি। আমি সবেমাত্র নথিটি সংযুক্ত করেছি: আমার টগল ফাংশনটিতে ক্লিক করুন:

    @Directive ({
      নির্বাচক: '[অ্যাপড্রপডাউন]'
    })
    রফতানির ক্লাস ড্রপডাউনডাইরেক্টিভ ওনআইনিট ments

      @ হোস্টবাইন্ডিং ('class.open') is ওপেন: বুলিয়ান;

      কনস্ট্রাক্টর (প্রাইভেট ইলেমরফ: এলিমেন্টআরফ)}

      ngOnInit (): শূন্য {
        this.isOpen = মিথ্যা;
      }

      @ হোস্টলিস্টনার ('ডকুমেন্ট: ক্লিক করুন', ['$ ইভেন্ট'])
      @ হোস্টলিস্টনার ('ডকুমেন্ট: টাচস্টার্ট', ['$ ইভেন্ট'])
      টগল (ইভেন্ট) {
        যদি (this.elemRef.nativeElement.contains (event.target)) {
          this.isOpen =! this.isOpen;
        } অন্য {
          this.isOpen = মিথ্যা;
      }
    }

সুতরাং, যখন আমি আমার নির্দেশের বাইরে থাকি, তখন আমি ড্রপডাউনটি বন্ধ করি।


4
import { Component, HostListener } from '@angular/core';

@Component({
    selector: 'custom-dropdown',
    template: `
        <div class="custom-dropdown-container">
            Dropdown code here
        </div>
    `
})
export class CustomDropdownComponent {
    thisElementClicked: boolean = false;

    constructor() { }

    @HostListener('click', ['$event'])
    onLocalClick(event: Event) {
        this.thisElementClicked = true;
    }

    @HostListener('document:click', ['$event'])
    onClick(event: Event) {
        if (!this.thisElementClicked) {
            //click was outside the element, do stuff
        }
        this.thisElementClicked = false;
    }
}

ডাউনসাইড: - পৃষ্ঠাতে এই উপাদানগুলির প্রতিটির জন্য দুটি ক্লিক ইভেন্ট শ্রোতা। পৃষ্ঠাতে থাকা উপাদানগুলিতে এটি শত শত বার ব্যবহার করবেন না।


না, আমি কেবল এটি ডেস্কটপ ব্রাউজারে ব্যবহার করেছি।
অ্যালেক্স এগলি

3

আমি @ টনি উত্তরের পরিপূরক চাই, যেহেতু উপাদানটির বাইরে ক্লিক করার পরে ইভেন্টটি সরানো হচ্ছে না। সম্পূর্ণ প্রাপ্তি:

  • আপনার কনটেন্টারের সাথে মূল উপাদানটি চিহ্নিত করুন

    @ViewChild('container') container;
    
    _dropstatus: boolean = false;
    get dropstatus() { return this._dropstatus; }
    set dropstatus(b: boolean) 
    {
        if (b) { document.addEventListener('click', this.offclickevent);}
        else { document.removeEventListener('click', this.offclickevent);}
        this._dropstatus = b;
    }
    offclickevent: any = ((evt:any) => { if (!this.container.nativeElement.contains(evt.target)) this.dropstatus= false; }).bind(this);
  • ক্লিকযোগ্য উপাদানটিতে, ব্যবহার করুন:

    (click)="dropstatus=true"

এখন আপনি ড্রপস্ট্যাটাস ভেরিয়েবলের সাহায্যে আপনার ড্রপডাউন স্থিতিটি নিয়ন্ত্রণ করতে পারেন এবং [ngClass] সহ সঠিক ক্লাস প্রয়োগ করতে পারেন ...


3

আপনি নির্দেশিকা লিখতে পারেন:

@Directive({
  selector: '[clickOut]'
})
export class ClickOutDirective implements AfterViewInit {
  @Input() clickOut: boolean;

  @Output() clickOutEvent: EventEmitter<any> = new EventEmitter<any>();

  @HostListener('document:mousedown', ['$event']) onMouseDown(event: MouseEvent) {

       if (this.clickOut && 
         !event.path.includes(this._element.nativeElement))
       {
           this.clickOutEvent.emit();
       }
  } 


}

আপনার উপাদান:

@Component({
  selector: 'app-root',
  template: `
    <h1 *ngIf="isVisible" 
      [clickOut]="true" 
      (clickOutEvent)="onToggle()"
    >{{title}}</h1>
`,
  styleUrls: ['./app.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent {
  title = 'app works!';

  isVisible = false;

  onToggle() {
    this.isVisible = !this.isVisible;
  }
}

এই নির্দেশিকা নির্গত ইভেন্টটি যখন এইচটিএমএল উপাদানটি ডিওমে থাকে এবং যখন [ক্লিকআউট] ইনপুট সম্পত্তিটি 'সত্য' থাকে। উপাদানটি ডিওএম থেকে সরানো হওয়ার আগে এটি ইভেন্ট হ্যান্ডেল করার জন্য মোসডাউন ইভেন্টটি শুনবে।

এবং একটি দ্রষ্টব্য: ফায়ারফক্সে পথ তৈরিতে ফাংশনটি ব্যবহার করতে পারেন এমন ইভেন্টে সম্পত্তি 'পাথ' নেই:

const getEventPath = (event: Event): HTMLElement[] => {
  if (event['path']) {
    return event['path'];
  }
  if (event['composedPath']) {
    return event['composedPath']();
  }
  const path = [];
  let node = <HTMLElement>event.target;
  do {
    path.push(node);
  } while (node = node.parentElement);
  return path;
};

সুতরাং আপনার নির্দেশাবলীতে ইভেন্ট হ্যান্ডলারটি পরিবর্তন করা উচিত: ইভেন্ট.পথটি getEventPath (ইভেন্ট) প্রতিস্থাপন করা উচিত

এই মডিউল সাহায্য করতে পারেন। https://www.npmjs.com/package/ngx-clickout এটি একই যুক্তি ধারণ করে তবে উত্স এইচটিএমএল উপাদানটিতে এসকে ইভেন্ট পরিচালনা করে।


3

সঠিক উত্তরের একটি সমস্যা রয়েছে, যদি আপনার পপওভারে আপনার কাছে ক্লিকযোগ্য উপাদান থাকে তবে উপাদানটি আর containপদ্ধতিতে থাকবে না এবং বন্ধ হবে, @ জুহার্ম 89 এর উপর ভিত্তি করে আমি আমার নিজের তৈরি করেছি:

export class PopOverComponent implements AfterViewInit {
 private parentNode: any;

  constructor(
    private _element: ElementRef
  ) { }

  ngAfterViewInit(): void {
    this.parentNode = this._element.nativeElement.parentNode;
  }

  @HostListener('document:click', ['$event.path'])
  onClickOutside($event: Array<any>) {
    const elementRefInPath = $event.find(node => node === this.parentNode);
    if (!elementRefInPath) {
      this.closeEventEmmit.emit();
    }
  }
}

সাহায্যের জন্য ধন্যবাদ!


2

@ টনি দুর্দান্ত সমাধানের জন্য আরও ভাল সংস্করণ:

@Component({})
class SomeComponent {
    @ViewChild('container') container;
    @ViewChild('dropdown') dropdown;

    constructor() {
        document.addEventListener('click', this.offClickHandler.bind(this)); // bind on doc
    }

    offClickHandler(event:any) {
        if (!this.container.nativeElement.contains(event.target)) { // check click origin

            this.dropdown.nativeElement.closest(".ourDropdown.open").classList.remove("open");

        }
    }
}

একটি সিএসএস ফাইলে: // আপনি বুটস্ট্র্যাপ ড্রপ ডাউন ব্যবহার করেন না প্রয়োজন।

.ourDropdown{
   display: none;
}
.ourDropdown.open{
   display: inherit;
}

2

এর পরিবর্তে আপনি যদি মডেল ওভারলেতে ক্লিক করেন তবে খুব সহজ check

আপনার টেম্পলেট:

<div #modalOverlay (click)="clickOutside($event)" class="modal fade show" role="dialog" style="display: block;">
        <div class="modal-dialog" [ngClass]='size' role="document">
            <div class="modal-content" id="modal-content">
                <div class="close-modal" (click)="closeModal()"> <i class="fa fa-times" aria-hidden="true"></i></div>
                <ng-content></ng-content>
            </div>
        </div>
    </div>

এবং পদ্ধতি:

  @ViewChild('modalOverlay') modalOverlay: ElementRef;

// ... your constructor and other method

      clickOutside(event: Event) {
    const target = event.target || event.srcElement;
    console.log('click', target);
    console.log("outside???", this.modalOverlay.nativeElement == event.target)
    // const isClickOutside = !this.modalBody.nativeElement.contains(event.target);
    // console.log("click outside ?", isClickOutside);
    if ("isClickOutside") {
      // this.closeModal();
    }


  }

2

আমি এই একই সমস্যাটির সমাধান করার জন্য একটি নির্দেশিকা তৈরি করেছি এবং আমি বুটস্ট্র্যাপ ব্যবহার করছি। তবে আমার ক্ষেত্রে, বর্তমান খোলা ড্রপডাউন মেনুটি বন্ধ করার জন্য উপাদানটির বাইরে ক্লিক ইভেন্টের অপেক্ষা না করে আমি মনে করি যদি আমরা 'মাউসলেভ' ইভেন্টটি স্বয়ংক্রিয়ভাবে মেনুটি বন্ধ করে রাখি তবে এটি আরও ভাল।

এখানে আমার সমাধান:

নির্দেশিকা

import { Directive, HostListener, HostBinding } from '@angular/core';
@Directive({
  selector: '[appDropdown]'
})
export class DropdownDirective {

  @HostBinding('class.open') isOpen = false;

  @HostListener('click') toggleOpen() {
    this.isOpen = !this.isOpen;
  }

  @HostListener('mouseleave') closeDropdown() {
    this.isOpen = false;
  }

}

এইচটিএমএল

<ul class="nav navbar-nav navbar-right">
    <li class="dropdown" appDropdown>
      <a class="dropdown-toggle" data-toggle="dropdown">Test <span class="caret"></span>
      </a>
      <ul class="dropdown-menu">
          <li routerLinkActive="active"><a routerLink="/test1">Test1</a></li>
          <li routerLinkActive="active"><a routerLink="/test2/">Test2</a></li>
      </ul>
    </li>
</ul>

1

আপনি যদি বুটস্ট্র্যাপ ব্যবহার করে থাকেন তবে ড্রপডাউনস (বুটস্ট্র্যাপ উপাদান) এর মাধ্যমে আপনি এটি সরাসরি বুটস্ট্র্যাপের মাধ্যমে করতে পারেন।

<div class="input-group">
    <div class="input-group-btn">
        <button aria-expanded="false" aria-haspopup="true" class="btn btn-default dropdown-toggle" data-toggle="dropdown" type="button">
            Toggle Drop Down. <span class="fa fa-sort-alpha-asc"></span>
        </button>
        <ul class="dropdown-menu">
            <li>List 1</li>
            <li>List 2</li>
            <li>List 3</li>
        </ul>
    </div>
</div>

এখন (click)="clickButton()"বোতামে জিনিস রাখা ঠিক আছে । http://getbootstrap.com/javascript/#dropdowns


1

আমি আমার নিজের মতো করে একটু কাজ করেছি।

আমি একটি (ড্রপডাউন ওপেন) তৈরি করেছি ইভেন্ট তৈরি করেছি যা আমি আমার এনজি-সিলেক্ট উপাদান উপাদানটিতে শুনি এবং এমন একটি ফাংশন বলি যা বর্তমানে খোলা নির্বাচনী উপাদানটি বাদে অন্য সমস্ত সিলেক্ট কম্পোনেন্টের খোলা বন্ধ করে দেবে।

ইভেন্টটি নির্গত করতে আমি নীচের মতো সিলেক্ট.টিস ফাইলের ভিতরে একটি ফাংশন সংশোধন করেছি :

private open():void {
    this.options = this.itemObjects
        .filter((option:SelectItem) => (this.multiple === false ||
        this.multiple === true && !this.active.find((o:SelectItem) => option.text === o.text)));

    if (this.options.length > 0) {
        this.behavior.first();
    }
    this.optionsOpened = true;
    this.dropdownOpened.emit(true);
}

এইচটিএমএলে আমি এর জন্য একটি ইভেন্ট শ্রোতা যুক্ত করেছি (ড্রপডাউনওপেনড) :

<ng-select #elem (dropdownOpened)="closeOtherElems(elem)"
    [multiple]="true"
    [items]="items"
    [disabled]="disabled"
    [isInputAllowed]="true"
    (data)="refreshValue($event)"
    (selected)="selected($event)"
    (removed)="removed($event)"
    placeholder="No city selected"></ng-select>

এনজি 2-সিলেক্ট ট্যাগযুক্ত উপাদানটির ভিতরে ইভেন্ট ট্রিগারে এটি আমার কলিং ফাংশন:

@ViewChildren(SelectComponent) selectElem :QueryList<SelectComponent>;

public closeOtherElems(element){
    let a = this.selectElem.filter(function(el){
                return (el != element)
            });

    a.forEach(function(e:SelectComponent){
        e.closeDropdown();
    })
}

1

দ্রষ্টব্য: যারা ওয়েব কর্মী ব্যবহার করতে চান এবং আপনার ডকুমেন্ট এবং নেটিমেলেট ব্যবহার করা এড়াতে হবে এটি কাজ করবে।

আমি এখানে একই প্রশ্নের উত্তর দিয়েছি: /programming/47571144

উপরের লিঙ্কটি থেকে অনুলিপি / আটকান:

আমি যখন ড্রপ-ডাউন মেনু তৈরি করছিলাম তখন একটি একই বিষয় ছিল এবং বাইরে ক্লিক করার সময় আমি এগুলি খারিজ করতে চাইতাম confir

আমার চূড়ান্ত বাস্তবায়ন পুরোপুরি কার্যকর হয় তবে কিছু সিএস 3 অ্যানিমেশন এবং স্টাইলিং প্রয়োজন requires

বিঃদ্রঃ : আমি নীচের কোডটি পরীক্ষা করে দেখিনি, কিছু সিনট্যাক্স সমস্যা থাকতে পারে যা আপনার নিজের প্রকল্পের জন্য সুস্পষ্ট সমন্বয়গুলিও ইস্ত্রি করা দরকার!

আমি কি করেছিলাম:

আমি উচ্চতা 100%, প্রস্থ 100% এবং রূপান্তর: স্কেল (0) এর সাথে একটি পৃথক ফিক্সড ডিভ তৈরি করেছি, আপনি ব্যাকগ্রাউন্ডটি ব্যাকগ্রাউন্ডে করতে পারেন, আপনি এটি ব্যাকগ্রাউন্ড-রঙের সাথে স্টাইল করতে পারেন: rgba (0, 0, 0, 0.466); সুস্পষ্ট করতে মেনুটি খোলা আছে এবং পটভূমিটি ক্লিক-টু-ক্লোজ। মেনুটি সমস্ত কিছুর তুলনায় একটি জেড-সূচক পায়, তারপরে পটভূমি ডিভটি মেনুর চেয়ে কম জেড-সূচক পায় তবে সমস্ত কিছুর চেয়েও বেশি। তারপরে পটভূমিতে একটি ক্লিক ইভেন্ট রয়েছে যা ড্রপ-ডাউনটি বন্ধ করে দেয়।

এখানে এটি আপনার এইচটিএমএল কোড সহ।

<div class="dropdownbackground" [ngClass]="{showbackground: qtydropdownOpened}" (click)="qtydropdownOpened = !qtydropdownOpened"><div>
<div class="zindex" [class.open]="qtydropdownOpened">
  <button (click)="qtydropdownOpened = !qtydropdownOpened" type="button" 
         data-toggle="dropdown" aria-haspopup="true" [attr.aria-expanded]="qtydropdownOpened ? 'true': 'false' ">
   {{selectedqty}}<span class="caret margin-left-1x "></span>
 </button>
  <div class="dropdown-wrp dropdown-menu">
  <ul class="default-dropdown">
      <li *ngFor="let quantity of quantities">
       <a (click)="qtydropdownOpened = !qtydropdownOpened;setQuantity(quantity)">{{quantity  }}</a>
       </li>
   </ul>
  </div>
 </div>

এখানে সিএসএস 3 যা কিছু সাধারণ অ্যানিমেশনগুলির প্রয়োজন।

/* make sure the menu/drop-down is in front of the background */
.zindex{
    z-index: 3;
}

/* make background fill the whole page but sit behind the drop-down, then
scale it to 0 so its essentially gone from the page */
.dropdownbackground{
    width: 100%;
    height: 100%;
    position: fixed;
    z-index: 2;
    transform: scale(0);
    opacity: 0;
    background-color: rgba(0, 0, 0, 0.466);
}

/* this is the class we add in the template when the drop down is opened
it has the animation rules set these how you like */
.showbackground{
    animation: showBackGround 0.4s 1 forwards; 

}

/* this animates the background to fill the page
if you don't want any thing visual you could use a transition instead */
@keyframes showBackGround {
    1%{
        transform: scale(1);
        opacity: 0;
    }
    100% {
        transform: scale(1);
        opacity: 1;
    }
}

আপনি যদি ভিজ্যুয়াল কোনও কিছুর পরে না থাকেন তবে আপনি কেবল এই জাতীয় স্থানান্তর ব্যবহার করতে পারেন

.dropdownbackground{
    width: 100%;
    height: 100%;
    position: fixed;
    z-index: 2;
    transform: scale(0);
    opacity: 0;
    transition all 0.1s;
}

.dropdownbackground.showbackground{
     transform: scale(1);
}

1

আমি ফোকাস / অস্পষ্ট ইভেন্টের সাথে উদাহরণগুলি দ্বারা অনুপ্রাণিত হয়ে অন্য একটি সমাধানে পৌঁছেছি।

সুতরাং, যদি আপনি বিশ্বব্যাপী দস্তাবেজ শ্রোতাদের সংযুক্ত না করে একই কার্যকারিতা অর্জন করতে চান তবে আপনি নীচের উদাহরণটিকে বৈধ হিসাবে বিবেচনা করতে পারেন। এটি ওএসএক্সের সাফারি এবং ফায়ারফক্সেও কাজ করে, তাদের বোতাম ফোকাস ইভেন্টটির অন্য পরিচালনা করার পরেও: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#

কৌনিক 8 সহ স্ট্যাকবিজে কার্যকারী উদাহরণ: https://stackblitz.com/edit/angular-sv4tbi?file=src%2Ftoggle-roddown%2Ftoggle-roddown.directive.ts

এইচটিএমএল মার্কআপ:

<div class="dropdown">
  <button class="btn btn-secondary dropdown-toggle" type="button" aria-haspopup="true" aria-expanded="false">Dropdown button</button>
  <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
    <a class="dropdown-item" href="#">Action</a>
    <a class="dropdown-item" href="#">Another action</a>
    <a class="dropdown-item" href="#">Something else here</a>
  </div>
</div>

নির্দেশটি এর মতো দেখাবে:

import { Directive, HostBinding, ElementRef, OnDestroy, Renderer2 } from '@angular/core';

@Directive({
  selector: '.dropdown'
})
export class ToggleDropdownDirective {

  @HostBinding('class.show')
  public isOpen: boolean;

  private buttonMousedown: () => void;
  private buttonBlur: () => void;
  private navMousedown: () => void;
  private navClick: () => void;

  constructor(private element: ElementRef, private renderer: Renderer2) { }

  ngAfterViewInit() {
    const el = this.element.nativeElement;
    const btnElem = el.querySelector('.dropdown-toggle');
    const menuElem = el.querySelector('.dropdown-menu');

    this.buttonMousedown = this.renderer.listen(btnElem, 'mousedown', (evt) => {
      console.log('MOUSEDOWN BTN');
      this.isOpen = !this.isOpen;
      evt.preventDefault(); // prevents loose of focus (default behaviour) on some browsers
    });

    this.buttonMousedown = this.renderer.listen(btnElem, 'click', () => {
      console.log('CLICK BTN');
      // firefox OSx, Safari, Ie OSx, Mobile browsers.
      // Whether clicking on a <button> causes it to become focused varies by browser and OS.
      btnElem.focus();
    });

    // only for debug
    this.buttonMousedown = this.renderer.listen(btnElem, 'focus', () => {
      console.log('FOCUS BTN');
    });

    this.buttonBlur = this.renderer.listen(btnElem, 'blur', () => {
      console.log('BLUR BTN');
      this.isOpen = false;
    });

    this.navMousedown = this.renderer.listen(menuElem, 'mousedown', (evt) => {
      console.log('MOUSEDOWN MENU');
      evt.preventDefault(); // prevents nav element to get focus and button blur event to fire too early
    });
    this.navClick = this.renderer.listen(menuElem, 'click', () => {
      console.log('CLICK MENU');
      this.isOpen = false;
      btnElem.blur();
    });
  }

  ngOnDestroy() {
    this.buttonMousedown();
    this.buttonBlur();
    this.navMousedown();
    this.navClick();
  }
}

1

আপনি mouseleaveআপনার মতামত এই মত ব্যবহার করতে পারেন

কৌনিক 8 দিয়ে পরীক্ষা করুন এবং নিখুঁতভাবে কাজ করুন

<ul (mouseleave)="closeDropdown()"> </ul>

এটি মাউসটি ছেড়ে যাওয়ার পরে ধারকটি বন্ধ করে দেবে, তবে যাইহোক ভাগ করার জন্য আপনাকে ধন্যবাদ কারণ আমি এর অস্তিত্ব সম্পর্কে অবগত ছিলাম না।
বেন হ্যাওয়ার্ড

0

সবচেয়ে কার্যকর পদ্ধতি: ডি

এটি করার একটি সহজ উপায় আছে, এর জন্য কোনও দিকনির্দেশনার প্রয়োজন নেই।

"উপাদানটি-টগল-আপনার-ড্রপডাউন" বোতাম ট্যাগ হওয়া উচিত। (অস্পষ্ট) বৈশিষ্ট্যে যে কোনও পদ্ধতি ব্যবহার করুন। এখানেই শেষ.

<button class="element-that-toggle-your-dropdown"
               (blur)="isDropdownOpen = false"
               (click)="isDropdownOpen = !isDropdownOpen">
</button>

আপনি যদি ড্রপডাউন ক্লিকে খোলা রাখতে চান তবে এই কাজ করবে না, উদাহরণস্বরূপ কোনও ব্যবহারকারী একটি বোতাম ক্লিক করতে মিস করতে পারে
হ্যাঁ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.