2017-06-07 36 views
0

如果事件通常會導致變化檢測運行(setTimeout,setInterval,瀏覽器事件,ajax調用等等),是否有辦法完全禁用Angular的變化檢測器。 )來自特定的類(服務或組件)?Angular:爲整個班級(服務或組件)禁用變化檢測器

也就是說,它似乎完全錯誤的我,當我發現我的服務註冊的setInterval導致全局改變檢測運行每秒..

我知道我可以換裏面的NgZone.runOutsideAngular我的代碼方法的回調,但我更喜歡這樣的解決方案,即可以爲整個類禁用更改檢測器,因爲我在服務中還有其他不必要的代碼運行檢測。

感謝您的幫助。

+0

你檢查:https://stackoverflow.com/questions/43108155/angular-2-how-to-keep-event-from-triggering-digest-loop? ' – echonax

+0

'錯誤:沒有提供ChangeDetectorRef!'。似乎ChangeDetectorRef的提供者不可用於服務。 –

+0

你爲什麼要在服務中運行變更檢測?它沒有看法。 – echonax

回答

2
未來的任何其他方法

一個可能的解決方案可能是您的服務如下@RunOutsideAngular裝飾:

declare let Zone: any; 

export function RunOutsideAngular(target: any) { 
    Object.getOwnPropertyNames(target.prototype) 
    .filter(p => typeof target.prototype[p] === 'function') 
    .forEach(p => { 
     let originalMethod = target.prototype[p]; 
     target.prototype[p] = function (...args) { 
     let self = this; 
     Zone.root.run(() => originalMethod.apply(self, args)); 
     } 
    }); 

    let ctor: any = function (...args) { 
    let self = this; 
    return Zone.root.run(() => target.apply(self, args)); 
    }; 
    ctor.prototype = target.prototype; 
    return ctor; 
} 

Plunker Example

如果你只想setTimeoutsetInterval一些類中的禁用就可以修補這些功能

function patchTimers(timers: any[]) { 
    timers.forEach((timer) => { 
     let originalMethod = window[timer]; 
     window[timer] = function (...args) { 
      let self = this; 
      if (Zone.current['__runOutsideAngular__'] === true && Zone.current.name === 'angular') { 
       Zone.root.run(() => originalMethod.apply(self, args)); 
      } else { 
       originalMethod.apply(this, arguments); 
      } 
     }; 
    }) 
} 
patchTimers(['setTimeout', 'setInterval']); 

,創造裝飾這樣

export function RunOutsideAngular(target: any) { 
    Object.getOwnPropertyNames(target.prototype) 
     .filter(p => typeof target.prototype[p] === 'function') 
     .forEach(p => { 
      let originalMethod = target.prototype[p]; 
      target.prototype[p] = function (...args) { 
       Zone.current['__runOutsideAngular__'] = true; 
       originalMethod.apply(this, args); 
       delete Zone.current['__runOutsideAngular__']; 
      } 
     }); 

    let ctor: any = function (...args) { 
     Zone.current['__runOutsideAngular__'] = true; 
     let instance = target.apply(this, args); 
     delete Zone.current['__runOutsideAngular__']; 
     return instance; 
    }; 
    ctor.prototype = target.prototype; 
    return ctor; 
} 

然後你就可以按如下方式使用它

@RunOutsideAngular 
export class Service { 
    constructor() { 
    setInterval(() => { 
     console.log('ctor tick'); 
    }, 1000); 
    } 

    run() { 
    setTimeout(() => { 
     console.log('tick'); 
    }, 1000); 

    setInterval(() => { 
     console.log('tick interval'); 
    }, 1000) 
    } 
} 

Plunker Example

+0

方便的解決方案,感謝您的努力^^ –

0

更改檢測從組件樹的頂部開始,由zone.js觸發。 像setTimeout這樣的異步操作被zone.js拾取,它通知角度可能發生的變化。然後Angular在組件樹上自上而下運行變化檢測。 從變化檢測器中分離單個類將會從變化檢測中刪除該類(即指令),但不會停止在組件樹的其餘部分上運行變化檢測。 爲了您的需要,ngZone.runOutsideAngular(...)是要走的路,因爲它會阻止zone.js通知有關您的異步操作的角度,從而完全阻止運行變更檢測。

0

您可以通過以下更改各個部件的檢測策略:

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

@Component({ 
    selector: 'ws-layout-page', 
    templateUrl: './layout-page.component.html', 
    styleUrls: ['./layout-page.component.css'], 
    changeDetection: ChangeDetectionStrategy.OnPush 
}) 
export class LayoutPageComponent { 

} 

我不知道怎麼會archieve一些選擇性的開啓/視的哪裏是信息從

+1

它只會停止檢查當前組件的視圖 – yurzui