簡體   English   中英

檢測深度嵌套 object 中的更改,以使用 Angular 從服務修改 NgStyle

[英]Detect changes in a deeply nested object to modify NgStyle from a service using Angular

我有一個 HTML 元素,我需要使用[ngStyle]修改樣式屬性。 為此,我創建了一個名為templateStyle的組件變量,並將其設置為 object 中的一個值,該值由我創建的名為componentStyles的服務提供,如下所示:

基礎.component.ts

ngOnInit() {
  // returns a nested object of styles from my database
  var componentStyles = await this.styleService.componentStyles$.pipe(first()).toPromise();

  // I check to see if the style I need to set exists on the object, if it does, I add it
  this.templateStyle = {
    'min-height': componentStyles.customAttributes.sectionHeight != null ? `${componentStyles.customAttributes.sectionHeight}px` : null;
  }
}

這個templateStyle變量像這樣分配給我的div

<div [ngStyle]="templateStyle"></div>

現在問題來了:

用戶可以在彈出窗口中使用 slider 修改sectionHeight屬性。 因此,在我的彈出組件中,我訪問styleService.componentStyles$以獲取對樣式 object 的引用,然后我可以根據 slider 的值修改sectionHeight ,如下所示:

ngOnInit ngOnInit()中的 popup.component.ts

// call the same service to get reference to styles
var componentStyles = await this.styleService.componentStyles$.pipe(first()).toPromise();

this.slider.subscribe((change) => {
  // emits current value of slider (from 1 to 100)
  // this is the same property that is being assigned in the templateStyle variable in the
  // base component
  componentStyles.customAttributes.sectionHeight = change.detail.value;
})

由於componentStyles是一個 object 並通過引用傳遞,實際數據值確實發生了變化,但它不會導致 Angular 在基本組件中運行變化檢測,因為沒有重新分配templateStyle的新 object,(只有componentStyles.customAttributes.sectionHeight正在更改)。 這導致[ngStyle] object 沒有更新,並且min-height屬性沒有改變。

由於我當前的上下文在彈出窗口中,我如何強制將templateStyle object 返回到我的基本組件中以檢查更改? 我明白我能做到:

this.templateStyle = Object.assign({}, this.templateStyle) ,但是 slider 在popup.component.ts中並且無權訪問基本組件中的templateStyle變量。

go 的最佳方式是什么?


臨時解決方案

簡單的方法是直接從服務 object 直接分配 css,如下所示:

<div [ngStyle]="{
    'min-height': `${componentStyles.customAttributes.sectionHeight}px`
}"

有效,但它使我的 HTML 看起來很草率,我寧願將它設置為一個組件變量。 謝謝!

我個人認為這是具有“風格狀態”的情況。 我將使用的方法不是讓這些組件訪問服務中的 object(因為我看不到 subscribe()),而是使用 SUBJECT (rxjs) 來管理您的 styles,並在特別是BehaviorSubject

在這種情況下,您要做的是在您的服務中創建一個 BehaviorSubject,通過一些數據庫調用為其提供初始值,然后在您的彈出窗口和基本組件中訂閱它。 當您想發出由彈出窗口引起的更改時,您可以使用 subjectname.next(styleObject)。 如果它是對現有樣式 object 的簡單修改,您可以在 popup.ts 文件中保留一個本地副本,以便在發出之前進行引用和更改。

如果發生這種情況時您的模板仍然沒有更新,請提前 go 並進行手動更改檢測: https://angular.io/api/core/ChangeDetectorRef

只需注入服務並在發生更改的地方調用 cdref.detectChanges()

編碼愉快!

您應該使用共享或公共服務在組件之間進行通信。 這在子組件嵌套很深時特別有用。 我喜歡使用BehaviorSubject作為交流的手段。

在 CommonService 中,設置一個BehaviorSubject Subject/Observable:

export class CommonService {

  private heightBehavior = new BehaviorSubject<number>(20);
  height$ = this.heightBehavior.asObservable();

  setHeight(value: number) {
    this.heightBehavior.next(value);
  }
}

在 ChildComponent 中,注入服務並使用它來設置和發出新值,在本例中為滑塊值更改時的高度:

export class ChildComponent {

  constructor(private commonService: CommonService) { }

  changeValue(value: number) {
    this.commonService.setHeight(value);
  }
}

在父組件中注入服務並訂閱公開的 Observable。 (您也可以在 ngOnInit 中執行此操作,但為簡單起見,我們將其放在構造函數中):

export class AppComponent {
  divStyle = { height: "20px" };

  constructor(private commonService: CommonService) {
    this.commonService.height$.subscribe(val => 
      this.divStyle = { height: val + "px" }
    )
  }
}

在模板中,正如您所建議的,您可以使用 ngStyle 設置高度:

<div [ngStyle]="divStyle"></div>

檢查這個 Stackblitz 演示: https://stackblitz.com/edit/angular-kynfwa

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM