गतिशीलভাবে ইভেন্ট শ্রোতা যুক্ত করুন


143

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

আমি একটি উপাদান সেট আপ আছে। যখন টেম্পলেটটিতে একটি নির্দিষ্ট উপাদান ক্লিক করা হয় আমি mousemoveএকই টেমপ্লেটের অন্য একটি উপাদানের জন্য শ্রোতা যুক্ত করতে চাই । তৃতীয় উপাদানটি ক্লিক করা হলে আমি এই শ্রোতাকে সরাতে চাই।

আমি একদম সরল জাভাস্ক্রিপ্ট ব্যবহার করে এই কাজটি পেয়েছি উপাদানগুলি ধরতে এবং তারপরে স্ট্যান্ডার্ডকে কল করে addEventListener()তবে আমি ভাবছিলাম যে এটি করার আরও একটি " অ্যাঙ্গুলার ২.০ " উপায় আছে যা আমার সন্ধান করা উচিত।

উত্তর:


262

রেন্ডারার অ্যাঙ্গুলার ৪.০.০-আরসি .১ এ অবহেলা করা হয়েছে, নীচের আপডেটটি পড়ুন

Angular2 উপায় ব্যবহার করা listenবা listenGlobalথেকে পেশকারী

উদাহরণস্বরূপ, আপনি যদি কোনও কম্পোনেন্টে ক্লিক ইভেন্ট যুক্ত করতে চান তবে আপনাকে রেন্ডারার এবং এলিমেন্টরিফ ব্যবহার করতে হবে (এটি আপনাকে ভিউচিল্ড ব্যবহার করার বিকল্প দেয় বা এটি পুনরুদ্ধার করে এমন কিছু দেয় nativeElement)

constructor(elementRef: ElementRef, renderer: Renderer) {

    // Listen to click events in the component
    renderer.listen(elementRef.nativeElement, 'click', (event) => {
      // Do something with 'event'
    })
);

আপনি ব্যবহার করতে পারেন listenGlobalযা আপনার কাছে অ্যাক্সেস করার অনুমতি দেবে document, bodyইত্যাদি

renderer.listenGlobal('document', 'click', (event) => {
  // Do something with 'event'
});

মনে রাখবেন যে বিটা ২. উভয় থেকেই listenএবং listenGlobalশ্রোতাদের অপসারণ করার জন্য একটি ফাংশন ফিরে আসুন ( বিটা ২ এর চেঞ্জলগ থেকে পরিবর্তনগুলি ভাঙ্গা দেখুন )। এটি বড় অ্যাপ্লিকেশনগুলিতে মেমরি ফাঁস এড়ানোর জন্য ( # 6686 দেখুন )।

সুতরাং শ্রোতা আমরা পরিবর্তনশীল যোগ আমরা দায়িত্ব অর্পণ আবশ্যক মুছে ফেলার জন্য listenবা listenGlobalএকটি পরিবর্তনশীল যে ফাংশন ফিরে রাখা হবে, এবং তারপর আমরা এটা চালানো।

// listenFunc will hold the function returned by "renderer.listen"
listenFunc: Function;

// globalListenFunc will hold the function returned by "renderer.listenGlobal"
globalListenFunc: Function;

constructor(elementRef: ElementRef, renderer: Renderer) {
    
    // We cache the function "listen" returns
    this.listenFunc = renderer.listen(elementRef.nativeElement, 'click', (event) => {
        // Do something with 'event'
    });

    // We cache the function "listenGlobal" returns
    this.globalListenFunc = renderer.listenGlobal('document', 'click', (event) => {
        // Do something with 'event'
    });
}

ngOnDestroy() {
    // We execute both functions to remove the respectives listeners

    // Removes "listen" listener
    this.listenFunc();
    
    // Removs "listenGlobal" listener
    this.globalListenFunc();
}

এখানে কাজ করার একটি উদাহরণ সহ এক জনসাধারণ k উদাহরণস্বরূপ ব্যবহার রয়েছে listenএবং listenGlobal

কৌণিক 4.0.0-rc.1 + সহ রেন্ডারারভি 2 ব্যবহার করে (4.0.0-আরসি.3 থেকে রেন্ডারার 2)

  • 25/02/2017 : Rendererঅবচিত করা হয়েছে, এখন আমাদের ব্যবহার করা উচিত RendererV2(নীচের লাইনটি দেখুন)। দেখুন কমিট

  • 10/03/2017 : এ RendererV2নতুন নামকরণ করা হয়েছিল Renderer2। দেখুন ভঙ্গ পরিবর্তন

RendererV2listenGlobalবৈশ্বিক ইভেন্টগুলির জন্য আর কোনও কার্য নেই (ডকুমেন্ট, দেহ, উইন্ডো)। এটিতে কেবল একটি listenফাংশন রয়েছে যা উভয় কার্যকারিতা অর্জন করে।

রেফারেন্সের জন্য, আমি ডম রেন্ডারার বাস্তবায়নের উত্স কোডটি অনুলিপি করে আটক করছি কারণ এটি পরিবর্তন হতে পারে (হ্যাঁ, এটি কৌনিক!)।

listen(target: 'window'|'document'|'body'|any, event: string, callback: (event: any) => boolean):
      () => void {
    if (typeof target === 'string') {
      return <() => void>this.eventManager.addGlobalEventListener(
          target, event, decoratePreventDefault(callback));
    }
    return <() => void>this.eventManager.addEventListener(
               target, event, decoratePreventDefault(callback)) as() => void;
  }

আপনি দেখতে পাচ্ছেন, এখন এটি যাচাই করে যদি আমরা কোনও স্ট্রিং (ডকুমেন্ট, দেহ বা উইন্ডো) পাস করি, তবে এটি কোনও অভ্যন্তরীণ addGlobalEventListenerফাংশন ব্যবহার করবে । অন্য যে কোনও ক্ষেত্রে, আমরা যখন কোনও উপাদান (নেটিমেটমেন্ট) পাস করি তখন এটি একটি সাধারণ ব্যবহার করবেaddEventListener

শ্রোতাদের অপসারণ করতে এটি Rendererকৌনিক ২.x এর সাথে একই ছিল। listenএকটি ফাংশন প্রদান করে, তারপরে সেই ফাংশনটি কল করে।

উদাহরণ

// Add listeners
let global = this.renderer.listen('document', 'click', (evt) => {
  console.log('Clicking the document', evt);
})

let simple = this.renderer.listen(this.myButton.nativeElement, 'click', (evt) => {
  console.log('Clicking the button', evt);
});

// Remove listeners
global();
simple();

রেন্ডারারভি 2 ব্যবহার করে কৌণিক 4.0.0- rc.1 সহ plnkr

plnkr সঙ্গে কৌণিক 4.0.0-rc.3 ব্যবহার Renderer2


এটি Angular2 এর সাথে আমার দ্বিতীয় দিন এবং আমি সবেমাত্র আমার মাথাটি ভি 1 এর কাছাকাছি পেতে শুরু করেছি যাতে এটি অনেকটা নতুন বিভ্রান্তিকর। আপনি আমাকে পড়ার জন্য খুব ভাল স্টাফ দিয়েছেন তবে আমি এটিকে বন্ধ করে দিচ্ছি এবং নিঃসন্দেহে অনেক বেশি সম্পর্কিত প্রশ্নাবলীর সাথে শীঘ্রই ফিরে আসব। বিস্তারিত প্রতিক্রিয়ার জন্য চিয়ার্স :)
পপক্লিংরাপ

3
@popClingwrap আপনি না পরীক্ষা করতে HostListener পাশাপাশি। দস্তাবেজগুলিতে, কীভাবে কীভাবে ব্যবহৃত হয় তা দেখতে ব্যবহারকারীর ক্রিয়াকলাপের প্রতিক্রিয়া অনুসারে অ্যাট্রিবিউটের নির্দেশিকা দেখুন । host
এরিক মার্টিনেজ

@ এরিকমার্টিনিজ শোনার বা শোনা গ্লোবাল শুনা বন্ধ করার কি উপায় আছে? (অপসারণওয়ের তালিকা হিসাবে একই)
নিক

3
@ user1394625 হ্যাঁ, আপনি উত্তর দেখতে পারেন যেমন ngOnDestroyকোড, উভয় listenএবং listenGlobalএকটি ফাংশন যে যখন বলা / শ্রোতা মুছে ফেলা হবে মৃত্যুদন্ড কার্যকর ফিরে যান। আপনি যেমন দেখতে পাচ্ছেন তাই this.funcফাংশনটি ফিরিয়ে দেওয়া হয়েছে renderer.listenএবং যখন আমি করব তখন আমি this.func()শ্রোতাকে অপসারণ করব। একই জন্য যায় listenGlobal
এরিক মার্টিনেজ

@ এরিক মার্টিনিজ আপনার জন্য আরও একটি প্রশ্ন পেয়েছে ... ডিফল্ট () বা স্টপপ্রোপেশন () থামাতে আমি কীভাবে ফাংশনের অভ্যন্তরে 'ইভেন্ট' এ প্রবেশ করতে পারি
নিক

5

আমি এটিকে অত্যন্ত বিভ্রান্ত মনে করি। @ এরিকমার্টিনিজ যেমন রেন্ডারার 2 শুনুন () শ্রোতার অপসারণ করার জন্য ফাংশনটি ফিরিয়ে দেয়:

ƒ () { return element.removeEventListener(eventName, /** @type {?} */ (handler), false); }

যদি আমি শ্রোতা যুক্ত করি

this.listenToClick = this.renderer.listen('document', 'click', (evt) => {
    alert('Clicking the document');
})

আমি আমার ফাংশনটি কী উদ্দেশ্যে চেয়েছিলাম তা কার্যকর করতে আশা করবো, শ্রোতাদের অপসারণের সম্পূর্ণ বিপরীতে নয়।

// I´d expect an alert('Clicking the document'); 
this.listenToClick();
// what you actually get is removing the listener, so nothing...

প্রদত্ত দৃশ্যে, এটি প্রকৃতপক্ষে এর মতো নামকরণ করতে আরও বোধ করতে পারে:

// Add listeners
let unlistenGlobal = this.renderer.listen('document', 'click', (evt) => {
    console.log('Clicking the document', evt);
})

let removeSimple = this.renderer.listen(this.myButton.nativeElement, 'click', (evt) => {
    console.log('Clicking the button', evt);
});

এর অবশ্যই একটি ভাল কারণ থাকতে হবে তবে আমার মতে এটি খুব বিভ্রান্তিকর এবং স্বজ্ঞাত নয়।


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

@ সহিহ এই সঙ্গীটি সত্যিই বিভ্রান্তিকর, এটি দেখানোর জন্য ধন্যবাদ!
Godblessstrawberry

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

1

আমি একটি স্ট্যাকব্লিটজ উদাহরণ এবং @ টিহিচের উত্তরে একটি মন্তব্য যুক্ত করব।

রিটার্ন মানটি ইভেন্ট শ্রোতা যুক্ত করার পরে এটি সরিয়ে ফেলার জন্য একটি ফাংশন। আপনার যখন আর প্রয়োজন হবে না তখন ইভেন্ট শ্রোতাদের সরানো ভাল অনুশীলন হিসাবে বিবেচিত হয়। সুতরাং আপনি এই রিটার্ন মানটি সংরক্ষণ করতে পারেন এবং আপনার ngOnDestroyপদ্ধতির অভ্যন্তরে এটি কল করতে পারেন ।

আমি স্বীকার করি যে এটি প্রথমে বিভ্রান্তিকর মনে হতে পারে তবে এটি আসলে একটি খুব দরকারী বৈশিষ্ট্য। নিজের পরে আর কীভাবে পরিষ্কার করতে পারবেন?

export class MyComponent implements OnInit, OnDestroy {

  public removeEventListener: () => void;

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

  public ngOnInit() {
    this.removeEventListener = this.renderer.listen(this.elementRef.nativeElement, 'click', (event) => {
      if (event.target instanceof HTMLAnchorElement) {
        // Prevent opening anchors the default way
        event.preventDefault();
        // Your custom anchor click event handler
        this.handleAnchorClick(event);
      }
    });
  }

  public ngOnDestroy() {
    this.removeEventListener();
  }
}

অ্যাঙ্কর উপাদানগুলিতে ক্লিক করার জন্য এটি কীভাবে কাজ করতে পারে তা দেখানোর জন্য আপনি এখানে স্ট্যাকব্লিটজ খুঁজে পেতে পারেন ।

আমি ইমেজযুক্ত একটি বডি নিম্নরূপ যুক্ত করেছি:
<img src="x" onerror="alert(1)"></div>
এটি দেখানোর জন্য যে স্যানিটাইজার তার কাজ করছে।

এখানে এই ঝাঁকুনিতে আপনি একই শরীরের কোনও সংস্থাগুলি innerHTMLছাড়াই সংযুক্ত দেখতে পাবেন এবং এটি সমস্যাটি প্রকাশ করবে।


0

এখানে আমার কার্যনির্বাহী:

আমি কৌণিক 6 দিয়ে একটি লাইব্রেরি তৈরি করেছি আমি একটি সাধারণ উপাদান যুক্ত করেছি commonlib-headerযা বাহ্যিক অ্যাপ্লিকেশনটিতে এরূপ ব্যবহৃত হয়।

পদ্ধতিটি ধারণ করে serviceReferenceকোন শ্রেণিটি (উপাদানটি constructor(public serviceReference: MyService)ব্যবহার করে এমন উপাদানগুলিতে ইনজেকশনের commonlib-header) নোট করুন stringFunctionName:

<commonlib-header
    [logo]="{ src: 'assets/img/logo.svg', alt: 'Logo', href: '#' }"
    [buttons]="[{ index: 0, innerHtml: 'Button', class: 'btn btn-primary', onClick: [serviceReference, 'stringFunctionName', ['arg1','arg2','arg3']] }]">
    </common-header>

লাইব্রেরির উপাদানটি এইভাবে প্রোগ্রাম করা হয়েছে। গতিশীল ইভেন্টটি পদ্ধতিতে যুক্ত করা হয়েছে onClick(fn: any):

export class HeaderComponent implements OnInit {

 _buttons: Array<NavItem> = []

 @Input()
  set buttons(buttons: Array<any>) {
    buttons.forEach(navItem => {
      let _navItem = new NavItem(navItem.href, navItem.innerHtml)

      _navItem.class = navItem.class

      _navItem.onClick = navItem.onClick // this is the array from the component @Input properties above

      this._buttons[navItem.index] = _navItem
    })
  }

  constructor() {}

  ngOnInit() {}

  onClick(fn: any){
    let ref = fn[0]
    let fnName = fn[1]
    let args = fn[2]

    ref[fnName].apply(ref, args)
  }

পুনরায় ব্যবহারযোগ্য header.component.html:

<div class="topbar-right">
  <button *ngFor="let btn of _buttons"
    class="{{ btn.class }}"
    (click)="onClick(btn.onClick)"
    [innerHTML]="btn.innerHtml | keepHtml"></button>
</div>
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.