Parent 组件和 Children 组件之间的服务值不一致

Service Value Isn't Persistent Between Parent Component and Children Component

我正在尝试从一个组件在服务中设置一个值并从另一个组件读取它。

我的组件的层次结构是:parent => child => grandchild

如果我在第一个 child 组件中设置服务值,则 parent 从服务中获取正确的值,而如果我在 child 中设置值,则更内部 child parent 组件没有得到正确的值。

代码如下:

service.ts

 @Injectable()
    export class ConfirmationDialogService {
        componentHasDirtyForm: boolean;// value to set
        constructor(private confirmationDialogReferenceService: ConfirmationDialogReferenceService,
                    private dialog: MatDialog) { }

parentComponent.ts

constructor(private confirmService: ConfirmationDialogService) {
}

ngOnInit() {
}

isDirty(): boolean {
    console.log(this.confirmService.componentHasDirtyForm)
    return this.confirmService.componentHasDirtyForm;
}

ChildComponent.ts

constructor(private confirmService: ConfirmationDialogService) { }

ngAfterViewChecked(){
    this.confirmService.componentHasDirtyForm = this.generalInfoForm.dirty;
}

Grandchild组件(在 child 组件内呈现)

constructor(private confirmationService: ConfirmationDialogService) { }
    ngAfterViewChecked(){
        this.checkForDirtyForm();
    }

    checkForDirtyForm(){
        for(var i = 0; i < this.ContactFormArr.length; i++){
            if(this.ContactFormArr.at(i).dirty){
                this.confirmationService.componentHasDirtyForm = true;
                break;
            }
        }
    }

基本上,在 grandchild 组件中,我试图设置 ConfirmationDialogService 的 componentHasDirtyForm 道具。如果我从 child 而不是 grandchild 设置它,它会在 parent 中正确读取。

我已将服务作为提供者包含在 app.module.ts

如果您的服务声明为

@Injectable(
{
  provide:root
})

(Wand Maker 评论)该服务对所有应用程序通用

否则,您在主模块中将 de service 声明为 providers:[](并且该服务对所有应用程序都是通用的)或在模块 中声明为 providers:[] 具有所有组件.

如果您将服务声明为每个组件的提供者或使用 Injector 注入,则每个组件的服务是不同的

您应该将 componentHasDirtyForm 作为可观察对象包装在您的服务中,然后 link 将其包装到您的所有组件(父、子、孙)。这样所有三个(或更多)都始终共享相同的值。

// service
private readonly _componentHasDirtyForm = new BehaviorSubject<any>({});
public readonly $componentHasDirtyForm = this._data.asObservable();

// component
public componentHasDirtyForm: Observable<any>;

ngAfterViewChecked() {
   this.componentHasDirtyForm = confirmationService.$componentHasDirtyForm;
}    

// template
<div>{{ componentHasDirtyForm | async }}</div>

我设法找到了问题所在。 Grandchildren/Children 组件正确设置了服务的值。问题是 Parent/Child 组件的 ngAfterViewChecked() 挂钩是 运行 在 Grandchildren/Children 中的挂钩之后。

这导致服务的值基本上总是反映父组件状态(链中较高的组件)。我通过在父组件中设置脏检查以根据其当前值有条件地修改服务来解决这个问题。

例如

isDirty(): boolean {
    if(!this.confirmService.componentHasDirtyForm)
        this.confirmService.componentHasDirtyForm = formStatus;
}