Angular 表达式ChangedTerithasBeenCheckedError-针对角度v4求解

Angular 表达式ChangedTerithasBeenCheckedError-针对角度v4求解,angular,observable,Angular,Observable,这里的问题是:我的应用程序是否有更好的架构,这样我就可以避免Angular Docs中的解决方案,这看起来像是一个黑客。(对不起,我爱你!) 这个错误让程序员们发疯,作为一名编程新手,我一天中的大部分时间都很迷茫。有很多建议和奇怪的黑客让它消失,至少对noobs来说很奇怪。因此,我将在一个比我了解得多的人的要求下发布我的解决方案 对于我发现的这个错误,最好的解释是Maxim Koretskyi: 然而,我被甩出了轨道,损失了更多的时间。如果你向下滚动到“可能的修复”,他似乎建议不要使用这两种解

这里的问题是:我的应用程序是否有更好的架构,这样我就可以避免Angular Docs中的解决方案,这看起来像是一个黑客。(对不起,我爱你!)

这个错误让程序员们发疯,作为一名编程新手,我一天中的大部分时间都很迷茫。有很多建议和奇怪的黑客让它消失,至少对noobs来说很奇怪。因此,我将在一个比我了解得多的人的要求下发布我的解决方案

对于我发现的这个错误,最好的解释是Maxim Koretskyi:

然而,我被甩出了轨道,损失了更多的时间。如果你向下滚动到“可能的修复”,他似乎建议不要使用这两种解决方案,我们应该重新设计我们的应用程序。虽然我同意他的观点,但我不知道该怎么做,因为我找不到具体的重新架构解决方案,所以我最终选择了他提到的两个“可能的修复”的“异步更新”

这是可行的,但确实感觉像是一个黑客。这是在Angular文档中作为解决方案的,尽管我很难弄清楚这个例子是如何应用到我的应用程序中的

重新设计似乎更专业,但我在网上找不到有用的例子。许多堆栈溢出帖子不包含整个组件,只包含noob难以学习的神秘部分。我常常不得不猜测这些部件是什么。令人困惑

下面是我的应用程序组件和解决方案的相关部分。我希望它能为其他新手节省很多时间

所有项目.component.html在html中,当用户想要编辑项目时,会出现一个单击事件

<md-list-item class="items" *ngFor="let project of projects">
    <li fxFlex="30" class="badge" (click)="goToDetailPage(project)">
         <span> {{ project.projectName }} </span>
    </li>
    <li fxFlex="20" class="item"> {{ project.projectOwner }} </li>
...
编辑project.component.ts在ngOnInit中,这就是问题所在。我试过ngAfterViewInit,但没用。马克西姆解释了这个问题是如何在Angular的生命周期钩子中出现的。在setTimeout中包装函数调用给了计算机更多的时间来处理更改并修复了问题

import { Component, AfterViewInit, ViewChild } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';

import { ProjectsAdminService } from './project-admin.service';
import { Project } from './project-admin.model';
import { AddEditFormComponent } from './add-edit-form.component';

import { SuccessService } from '../../../shared/success.service';

@Component({
  selector: 'app-edit-project',
  templateUrl: './edit-project.component.html'
})

export class EditProjectComponent implements AfterViewInit {

  project: Project;

  @ViewChild(AddEditFormComponent)
  private addEditForm: AddEditFormComponent;

  private projectId: string;
  private projectData;

  private success() {
    this.successService
        .openDialog('Database updated as you wished!');
  }


  constructor(
      private projectsAdminService: ProjectsAdminService,
      private successService: SuccessService,
      private route: ActivatedRoute,
      private router: Router
  ) {}

// Need to load the data after the form is rendered so ngOnInit didn't work.

  ngAfterViewInit() {
    setTimeout(() => {
      this.fetchProject();
    });
  }


  // Parse the URL for the project id number or $key.

  fetchProject() {
    this.route.params.forEach((urlParameters) => {
      this.projectId = urlParameters['id'];
    });

    // Display the data retrieved from the data model to the form model.

    this.projectsAdminService.getProjectById(this.projectId)

        .subscribe(dataLastEmittedFromObserver => {
          this.projectData = dataLastEmittedFromObserver;

          this.addEditForm.addEditProjectForm.setValue({
            projectOwner: this.projectData.projectOwner,
            projectOwnerKey: this.projectData.projectOwnerKey,
            setupDate: this.projectData.setupDate,
           ...
          });
        });
  }


// Add error handling and success message linked to Firebase results.

  update() {
    this.project = this.prepareSaveProject();
    this.projectsAdminService.updateProject(this.projectId, this.project);
    this.reset();
    this.success();
    this.router.navigate(['/loggedin/admin/projectsAdmin/searchProjects']);
  }

  prepareSaveProject(): Project {
    const formModel = this.addEditForm.addEditProjectForm.value;

    // return updated `Project` object

    const updatedProject: Project = {
      projectOwner: formModel.projectOwner as string,
      projectOwnerKey: formModel.projectOwnerKey as string,
      setupDate: formModel.setupDate as string,
      ...
    };
    return updatedProject;
  }

  reset() {
    this.addEditForm.addEditProjectForm.reset();
  }

  cancel() {
    this.router.navigate(['/loggedin/admin/projectsAdmin/searchProjects']);
  }

}
每个请求的edit.project.component.html,于2017年7月24日添加:

<md-card class="form-card">
        <h2 fxLayoutAlign="space-around center">Edit Project Form</h2><br>
        <app-add-edit-form></app-add-edit-form>

        <div fxLayout="row" fxLayoutAlign="space-around center">
            <button [disabled]="!addEditForm.addEditProjectForm.valid" md-raised-button (click)="update(addEditForm.addEditProjectForm.value)">Save Edits</button>
            <button md-raised-button (click)="cancel()">Cancel Edit</button>
        </div>
</md-card>
 <section>
    <H4>Search members to add owners</H4>
    <app-add-owner
            (onSelected)="onSelected($event)">
    </app-add-owner>
  </section>


  <form [formGroup]="addEditProjectForm"
        (ngSubmit)="onSubmit(addEditProjectForm.value)"
        [class.error]="!addEditProjectForm.valid && addEditProjectForm.touched">

    <ul class="items">

      <li>
        <label>Project owner: </label><br><br>
        <input class="inputField" type="text" id="projectOwner" formControlName="projectOwner"  required>
      </li>

      <li class="hiddenField">
        <label>Project owner key: </label><br><br>
        <input class="inputField" type="text" id="projectOwnerKey" formControlName="projectOwnerKey"  required>
      </li>

      <li>
        <label>Setup Date (Year/Month/Day):</label><br><br>
        <input class="inputField" type="text" id="setupDate" formControlName="setupDate"  required>
      </li>

      <div>
      <li>
        <label>Check if new project - 95% equity available: </label><br><br>
        <input #newProject type="checkbox" id="newProject" formControlName="newProject">
      </li>

      <li *ngIf="newProject.checked == false">
        <label>If partially complete project, percent of project equity available: </label><br><br>
        <input class="percentField" type="text" id="percentAvailable" formControlName="percentAvailable"> %
      </li>
      </div>

      <li>
        <label>Project name: </label><br><br>
        <input class="inputField" type="text" id="projectName" formControlName="projectName" required>
      </li>

      <li><label>Put project in stealth mode?</label><br><br>
        <label><input type="radio" formControlName="stealthMode" [value]="true"/>  Yes</label><br>
        <label><input type="radio" formControlName="stealthMode" [value]="false"/>  No</label>
      </li>
(...)

编辑项目表单
保存编辑结果 取消编辑
为每个请求添加编辑表单.component.html,于2017年7月24日添加:

<md-card class="form-card">
        <h2 fxLayoutAlign="space-around center">Edit Project Form</h2><br>
        <app-add-edit-form></app-add-edit-form>

        <div fxLayout="row" fxLayoutAlign="space-around center">
            <button [disabled]="!addEditForm.addEditProjectForm.valid" md-raised-button (click)="update(addEditForm.addEditProjectForm.value)">Save Edits</button>
            <button md-raised-button (click)="cancel()">Cancel Edit</button>
        </div>
</md-card>
 <section>
    <H4>Search members to add owners</H4>
    <app-add-owner
            (onSelected)="onSelected($event)">
    </app-add-owner>
  </section>


  <form [formGroup]="addEditProjectForm"
        (ngSubmit)="onSubmit(addEditProjectForm.value)"
        [class.error]="!addEditProjectForm.valid && addEditProjectForm.touched">

    <ul class="items">

      <li>
        <label>Project owner: </label><br><br>
        <input class="inputField" type="text" id="projectOwner" formControlName="projectOwner"  required>
      </li>

      <li class="hiddenField">
        <label>Project owner key: </label><br><br>
        <input class="inputField" type="text" id="projectOwnerKey" formControlName="projectOwnerKey"  required>
      </li>

      <li>
        <label>Setup Date (Year/Month/Day):</label><br><br>
        <input class="inputField" type="text" id="setupDate" formControlName="setupDate"  required>
      </li>

      <div>
      <li>
        <label>Check if new project - 95% equity available: </label><br><br>
        <input #newProject type="checkbox" id="newProject" formControlName="newProject">
      </li>

      <li *ngIf="newProject.checked == false">
        <label>If partially complete project, percent of project equity available: </label><br><br>
        <input class="percentField" type="text" id="percentAvailable" formControlName="percentAvailable"> %
      </li>
      </div>

      <li>
        <label>Project name: </label><br><br>
        <input class="inputField" type="text" id="projectName" formControlName="projectName" required>
      </li>

      <li><label>Put project in stealth mode?</label><br><br>
        <label><input type="radio" formControlName="stealthMode" [value]="true"/>  Yes</label><br>
        <label><input type="radio" formControlName="stealthMode" [value]="false"/>  No</label>
      </li>
(...)

搜索成员以添加所有者
  • 项目负责人:

  • 项目所有者密钥:

  • 设置日期(年/月/日):

  • 检查新项目-95%股权是否可用:

  • 如果部分完成项目,可用项目股权的百分比:

    %
  • 项目名称:

  • 将项目置于隐藏模式?


  • (...)
project admin.service.ts因此,我不会让任何人猜测这个问题的另一部分,我将包括我的相关服务,用于对数据库进行CRUDing

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';

import { ProjectsAdminService } from './project-admin.service';
import { ConfirmService } from '../../../shared/confirm.service';
import { Project } from './project-admin.model';

@Component({
  selector: 'app-all-projects',
  templateUrl: './all-projects.component.html'
})

export class AllProjectsComponent implements OnInit {

  projects: Project[];
  private selectedId: number;
  private result: boolean;
  allProjects: Project[];


  constructor(
      private projectsAdminService: ProjectsAdminService,
      private router: Router,
      private confirmService: ConfirmService
  ) {}

  ngOnInit() {
    this.projectsAdminService.getProjects()
        .subscribe(
            projects => this.allProjects = this.projects = projects
        );
  }


  // Create the URL param key to be parsed in the edit-project     component.

  goToDetailPage(selectedProject) {
    this.router.navigate(['/loggedin/admin/projectsAdmin/editProject',        selectedProject.$key]);
  };


  deleteProject(selectedProject) {
    // Call the confirm dialog component
    this.confirmService
        .confirm('Confirm Delete', 'This action is final. Gone forever!')
        .do(res => {if (res === true)   {this.projectsAdminService.deleteProject(selectedProject.$key);
        }})
        .subscribe(res => this.result = res, err => err);
  }

}
import { AngularFireDatabase, FirebaseListObservable } from 'angularfire2/database';
import { FirebaseApp } from 'angularfire2';

import { Inject, Injectable } from '@angular/core';

import { Project } from './project-admin.model';
import { SuccessService } from '../../../shared/success.service';


@Injectable()
export class ProjectsAdminService {

  private projects$: FirebaseListObservable<Project[]>;

  constructor(
      private af: AngularFireDatabase,
      private successService: SuccessService,
      @Inject(FirebaseApp) fb) {
        this.projects$ = af.list('Projects');
  }


  // Get all projects.

  public getProjects(): FirebaseListObservable<any> {
    return this.af.list('Projects', {
      query: {
        orderByChild: 'projectName'
      }
    });
  }


  // Fetch project detail for project list from click event.

  public getProjectById(projectId: string) {
    return this.af.object('Projects/' + projectId);
  }

  // Create new project

  public addProject(newProject: Project): void {
    this.projects$.push(newProject)
        .catch(error => this.handleError(error));
  }

  // Update an existing project

  public updateProject(key: string, value: any): void {
    this.projects$.update(key, value)
        .catch(error => this.handleError(error));
  }

  // Deletes a single project and calls for success modal window.

  public deleteProject(key: string): void {
    this.af.object('/Projects/' + key).remove()
        .catch(error => this.handleError(error))
        .then(_ => this.success());
  }

  private success() {
    this.successService
        .openDialog('Database updated as you wished!');
  }

  // Default error handling for all actions

  private handleError(error) {
    console.log(error)
  }

}
从“angularfire2/数据库”导入{AngularFireDatabase,FirebaseListObservable};
从“angularfire2”导入{FirebaseApp};
从“@angular/core”导入{Inject,Injectable};
从“./Project admin.model”导入{Project};
从“../../../shared/success.service”导入{SuccessService};
@可注射()
导出类ProjectsAdminService{
私人项目$:FirebaseListObservable;
建造师(
私人af:AngularFireDatabase,
私人成功服务:成功服务,
@注入(FirebaseApp)fb){
this.projects$=af.list('projects');
}
//获取所有项目。
public getProjects():FirebaseListObservable{
返回此.af.list('Projects'{
查询:{
orderByChild:“项目名称”
}
});
}
//从单击事件获取项目列表的项目详细信息。
公共getProjectById(projectId:string){
返回此.af.object('Projects/'+projectd);
}
//创建新项目
公共添加项目(新建项目:项目):无效{
此.projects$.push(newProject)
.catch(error=>this.handleError(error));
}
//更新现有项目
公共更新项目(键:字符串,值:任意):void{
此.projects$.update(键,值)
.catch(error=>this.handleError(error));
}
//删除单个项目并调用成功模式窗口。
公共删除项目(键:字符串):无效{
this.af.object('/Projects/'+key).remove()
.catch(错误=>此.handleError(错误))
.然后(=>this.success());
}
私人成功(){
这是成功服务
.openDialog('数据库已按您的意愿更新!');
}
//所有操作的默认错误处理
私有句柄错误(错误){
console.log(错误)
}
}

就这样。也许有办法重新设计这个设置,但我看不到。欢迎任何讨论和更好的解决方案

嘿,你能发布
项目编辑组件.ts
AddEditFormComponent
代码和模板的模板以及准确的错误描述吗<代码>所有项目。组件在这里似乎是不相关的,因为我知道您正在远离它,它正在被破坏。我添加了html组件Maximus.:-)很好,但我们还需要
AddEditFormComponent
代码和精确的错误描述:)