[英]How to render data on view without having to refresh the page in Angular 9?
[英]Angular - Dynamically adding / removing multiple instances of a single component without having to refresh the page to update the view
這是我第三次嘗試提出這個問題。
這個問題會很長,因為我看不出有什么辦法可以縮短它。
我想要做的是有一個簡單的網絡應用程序,它有一個 header(我創建為HeaderComponent )和按鈕,一個頁面(我創建為LiveSummaryComponent )將顯示一個的多個實例將顯示不同數據的組件(我將其創建為StatusBoxComponent )。
header 將有一個按鈕,可以打開一個模式對話框(我將其創建為AddStatusBoxComponent ),其中有一個表單和一個提交按鈕。 提交表單時,表單數據將作為 map 數據結構保存到瀏覽器本地存儲中,而且此時我想創建一個StatusBoxComponent實例,它將顯示在LiveSummaryComponent頁面上。
然后,該特定StatusBoxComponent實例應檢索本地存儲中的值以顯示唯一值。 我還希望能夠通過單擊StatusBoxComponent的每個實例上的按鈕以及編輯按鈕來刪除StatusBoxComponent實例。
理想情況下,我還希望能夠在每次添加、編輯或刪除新的StatusBoxComponent實例時不必刷新頁面來更新LiveSummaryComponent頁面。
多虧了我前段時間對這個問題的回答,我現在確實可以部分工作,但它有局限性,因為我無法找到一種方法來刪除和編輯StatusBoxComponent的每個實例中的信息。 我只能在提交表單時添加。 此外,每次添加新的StatusBoxComponent實例時,您都必須刷新頁面以更新LiveSummaryComponent頁面,這很煩人。
其工作方式是,當提交AddStatusBoxComponent表單時,它僅將表單數據放入本地存儲中的 map 數據結構中,並賦予唯一的名稱/鍵。 StatusBoxComponent實例的創建方式是在 LiveSummaryComponent 的ngInit()
function 中迭代所有本地存儲 map 數據結構並傳遞給名為myConfigs
的數組。 然后在名為DynamicStatusBoxDirective
的指令中訪問myConfigs
數組中的每個 Map,該指令實際上使用ComponentFactoryResolver
創建StatusBoxComponent的實例。 然后,該特定StatusBoxComponent將使用傳入的配置變量中的數據填充,該config
變量來自LiveSummaryComponent中的myConfigs
數組。
這種做法意味着DynamicStatusBoxDirective
只需加載與本地存儲映射一樣多的StatusBoxComponent實例。 它在ngInit()
function 中執行此操作,因此它會立即加載所有內容,而不是在單擊按鈕時動態添加,這也不理想。
LiveSummaryComponent ts 代碼:
import { Component, OnInit,} from '@angular/core';
import { Subscription } from 'rxjs';
@Component({
selector: 'app-live-summary',
templateUrl: './live-summary.component.html',
styleUrls: ['./live-summary.component.css']
})
export class LiveSummaryComponent implements OnInit
{
subscription!: Subscription;
myConfigs: any[] = [];
localStorageKeys: string[] = ['Old', 'New', 'Current', 'Test']
constructor() { }
ngOnInit(): void
{
for (var key of this.localStorageKeys) // iterates though each type of device
for(let i = 1; i < 5; i++) // for each of those device types
if (localStorage.getItem(key+i+'Topics') != null) // if the device + topics string is not null in local storage
this.myConfigs.push(new Map(JSON.parse(localStorage.getItem(key+i+'Topics')!)))
else
console.log(key+i + ' currently not deployed');
}
}
LiveSummaryComponent html 代碼:
<div class='status-box-container'>
<ng-container *ngFor="let config of myConfigs; let i=index" appDynamicStatusBox [config]="config"></ng-container>
</div>
DynamicStatusBoxDirective ts代碼:
import { ComponentFactoryResolver, ComponentRef, Directive, Input, OnDestroy, OnInit, ViewContainerRef } from '@angular/core';
import { StatusBoxComponent } from '../components/status-box/status-box.component';
@Directive({selector: '[appDynamicStatusBox]'})
export class DynamicStatusBoxDirective implements OnInit, OnDestroy
{
@Input() config: any;
componentRef!: ComponentRef<StatusBoxComponent>;
constructor(private resolver: ComponentFactoryResolver, public viewContainerRef: ViewContainerRef) {}
ngOnInit(): void
{
const factory = this.resolver.resolveComponentFactory(StatusBoxComponent);
this.viewContainerRef.clear();
this.componentRef = this.viewContainerRef.createComponent(factory);
// set each StatusBoxComponent vars with values from myConfig
this.componentRef.instance.deviceId = this.config.get('deviceId')
this.componentRef.instance.infoExample1 = this.config.get('infoExample1')
this.componentRef.instance. infoExample2 = this.config.get('infoExample2')
this.componentRef.instance. infoExample3 = this.config.get('infoExample3')
}
}
我發現這段代碼使您能夠添加和刪除組件的實例,但它有一個限制,如果您不按順序刪除組件,它會弄亂它使用的索引 ID 系統。 這意味着您最終可能會得到兩個具有相同 ID 的組件實例。 為了解決這個問題,我寧願使用在每個本地存儲 Map 中設置的deviceID
值(它是一個字符串)來標識我的StatusBoxComponent的每個實例而不是索引。 (雖然我不確定這將如何工作)。
此代碼的另一個問題是調用createComponnent()
的按鈕都在一個組件中。 在我的例子中,我想讓我的LiveSummaryComponent定義createComponent()
function ,它與我當前的DynamicStatusBoxDirective
。 但是能夠從AddStatusBoxComponent中的表單提交按鈕調用/訪問createComponent()
。 顯然它們是兩個完全不同的組件。 從這個和我問的這個問題可以看出,在 LiveSummaryComponent 之外訪問createComponent()
function 會給我錯誤。 不幸的是,后一個問題的解決方案我無法開始工作。
我不確定我是否應該堅持使用DynamicStatusBoxDirective
的原始方法,或者我是否應該嘗試讓我鏈接的示例代碼工作以實現我的目標。 或者我應該做些不同的事情嗎?
當單擊組件上的刪除按鈕時,似乎也很難知道要刪除哪個StatusBoxComponent實例。 本地存儲中的每個 map 數據結構都有一個我想使用的字符串deviceID
值。 但我不知道如何將該deviceID
字符串與特定的StatusBoxComponent實例相關聯。
我完全堅持這一點。
我希望我想要達到的目標至少是清楚的。 請點擊我的其他問題的鏈接,因為這將提供更多背景信息。 由於敏感信息,創建我的代碼的 stackblitz 將非常困難。
謝謝。
您可以使用服務從 localStorage 和帶有當前值數組的 stream 存儲/讀取數據。
@Injectable()
export class SomeService {
constructor() {
this._initStream();
}
//your stream with statuses
public statuses$ = new BehaviorSubject([]);
private _initStream(){
// get data from localStorage
// transform Map to Array
this.statuses$.next(transformedDataToArray);
}
// add status, use it in your modal
addStatus(props) {
...your logic to add
this._updateDataInLocalStorage();
this._updateStream();
}
// use it in your StatusBoxComponent
removeStatus() {
...your logic to remove
this._updateDataInLocalStorage();
this._updateStream();
}
// use it in your StatusBoxComponent
updateStatus() {
...your logic to remove
this._updateDataInLocalStorage();
this._updateStream();
}
// set current value to stream
_updateStream() {
const statuses = localStorage.getItem();
this.statuses$.next(statuses)
}
// update data in localStroage
_updateDataInLocalStorage() {
...some logic here
}
LiveSummaryComponent html 文件
<app-status-box *ngFor="let status of SomeService.statuses$ | async; let i=index" [props]="status" [index]="index"></app-status-box>
把它想象成你有一個簡單的狀態數組和一個唯一的 id(映射鍵)並使用它。 在方法中使用本地存儲的所有工作是將數組轉換為 Map 並保存到本地存儲,反之亦然 - 將 Map 從本地存儲轉換為數組以顯示您的狀態。 *ngFor
將完成顯示組件的所有工作
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.