2016-09-27 4 views
3

У меня возникли серьезные проблемы с попыткой выполнить некоторую логику внутри функции обратного вызова событий (click) в Угловом 2 без запуска обнаружения изменений.Угловой 2-обратный вызов события вызова без срабатывания обнаружения изменений

Почему я не хочу, чтобы вызвать обнаружение изменения

Функцию обратного вызова выполняет простые анимированные прокрутки к началу. Это не влияет на другие компоненты, и поэтому мне не нужно менять обнаружение, чтобы стрелять в каждом компоненте, на самом деле я действительно не хочу, чтобы он срабатывал! Поскольку обнаружение изменений срабатывает в каждом компоненте, производительность анимации на мобильных устройствах крайне низок.

То, что я пытался

Я знаю, что я могу запустить код за пределами зоны с использованием

this._zone.runOutsideAngular(() => { 
    someFunction(); 
}) 

Это хорошо работает, когда код, который вы хотите запустить вне зоны не вызывается по событию click, keyup, keydown и т.д.

Потому что мой компонент выглядит ...

<button (click)="doThing()">Do that thing outside the zone!</button>

doThing() { 
    this._zone.runOutsideAngular(() => { 
     myFunction(); 
    }) 
} 

... myFunction будет работать вне зоны, но click событие вызовет обнаружение изменений.

Я уже реализовал OnPush стратегию обнаружения изменений во многих моих компонентах, насколько это возможно.

Важно, что обнаружение изменений не запускается здесь, но я не могу найти способ предотвратить его.

Редактировать Смотрите эту plnk с обнаружением изменений, установленным в OnPush во всех компонентах. Щелчок по кнопке компонента субстроя запускает компакт-диск в компонентах подземелья, ряда и приложений.

+0

Вы пытались использовать 'changeDetection: ChangeDetectionStrategy.OnPush' в' @Component ({}) 'декодера этого компонента ??? – micronyks

ответ

4

Как уже отмечалось, даже установив компонент, в котором происходит событие click к OnPush будет по-прежнему приводить к обнаружения изменения, которые инициированы.

Out-оф-бокс обработки

@Component({ 
    selector: 'test' 
    template: `<button (click)="onClick($event)">Click me</button>`, 
    changeDetection: ChangeDetectionStrategy.OnPush 
}) 
export class MyComponent { 

    onClick(e:Event) { 
     e.preventDefault(); 
     e.stopPropagation(); 

     this._zone.runOutsideAngular(() => { 
      // gets run outside of Angular but parent function still triggers change detection 
     }); 

     return false; 

     /* 
     * change detection always triggered 
     * regardless of what happens above 
     */ 
    } 

} 

Большую часть времени это не может быть проблемой, но при визуализации и производительности картины для выполнения определенных функций имеет важное значение я беру подход события полностью обходя встроенную обработку событий Angular. Из моих собственных экспериментов следующее, кажется, самый простой и удобный способ приблизиться к этому.

Байпас вне коробки обработки событий

Идея заключается в том, чтобы использовать RxJS вручную привязать к тому, что события, я хочу, в этом случае щелчок, используя Observable.fromEvent. Этот пример также демонстрирует практику очистки подписки на события.

import {Component, ElementRef, OnInit, OnDestroy, NgZone} from '@angular/core'; 
import {Observable} from 'rxjs/Observable'; 
import {Subscription} from 'rxjs/Subscription'; 

@Component({ 
    selector: 'test' 
    template: `<button #myButton>Click me</button>`, 
    changeDetection: ChangeDetectionStrategy.OnPush 
}) 
export class MyComponent implements OnInit { 

    private _subs:Subscription[] = []; 

    // reference to template variable 
    @ViewChild('myButton') myButton:ElementRef; 

    constructor(private _zone:NgZone){} 

    ngOnInit() { 
     this.manuallyBindToViewEvents(); 
    } 

    manuallyBindToViewEvents() { 
     this.subscribeToMyButton() 
    } 

    subscribeToMyButton() { 
     let sub:Subscription; 

     this._zone.runOutsideAngular(() => { 
      sub = Observable.fromEvent(this.myButton.nativeElement, 'click').subscribe(e => { 
       console.log('Yayyyyy! No change detection!'); 
      }) 
     }); 

     this._subs.push(sub); 
    } 

    ngOnDestroy() { 
     // clean up subscriptions 
     this._subs.forEach(sub => sub.unsubscribe()); 
    } 

} 

Надеюсь, это поможет вам в аналогичной ситуации.

1

Если вы используете OnPush

@Component({ 
    changeDetection: ChangeDetectionStrategy.OnPush, 
}) 

затем изменить обнаружение должно быть ограничено компонентом, где происходит событие щелчка.

Вы можете отделить обнаружение изменений ChangeDetectorRef

constructor(private ref: ChangeDetectorRef, private dataProvider:DataProvider) { 
    ref.detach(); 
    } 

не будет работать для этого компонента до тех пор, пока не будет повторно подключить.

+0

Я не уверен, что это так. Я отредактирую исходный пост с плохо отформатированным plnk! – garethdn

+0

'detatch()' похоже, предотвращает обнаружение изменений https://plnkr.co/edit/wVjjGhcZkqVbtsVjvZyi?p=preview. –

+0

Я также пытался 'preventDefault()' и 'stopPropagation()' в событии, но это не мешало обнаружению изменений для всех компонентов. –

1

Я могу показать один общий взлом, но кажется, что он работает.

подстрока.TS

constructor(private zone: NgZone, private app: ApplicationRef) {} 

rowClick() { 
    console.log('rowClick'); 
    var a = 4; 

    let originalTick = (<any>this.app).constructor.prototype.tick; 
    (<any>this.app).constructor.prototype.tick =() => console.info('tick tick tick :)'); 
    const subscriber = this.zone.onMicrotaskEmpty.subscribe({ 
    next:() => { 
     console.info('tick has been stopped. So we can return everything in its place'); 
     subscriber.unsubscribe(); 
     (<any>this.app).constructor.prototype.tick = originalTick; 
    }}); 
} 

Demo Plunker

Смежные вопросы