[英]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.