【问题标题】:Set reactive form after data loaded (async) - Angular 5加载数据后设置反应形式(异步) - Angular 5
【发布时间】:2018-07-19 01:29:18
【问题描述】:

我正在尝试在从 API 加载值后更新表单值。我尝试使用*ngIf 技术,但即使设置了表单,表单也不可见。

我无法分享整个项目,但这里是组件模板和控制器

模板

<div class="page-title">
  <h3> Edit news </h3>
</div>
<div class="partner-add-form">
  <ng-container *ngIf='newsForm'>
    <form action="" [formGroup]='newsForm' (ngSubmit)="onSubmit()">
      <div class="row  ">
        <div class="input-field col s12 tooltip">
          <input formControlName='title' [id]="'title'" [type]="'text'">
          <label [for]="'title'">Title</label>
          <validator-errors [control]='newsForm.get("title")'></validator-errors>
        </div>
        <div class="input-field col s12 tooltip">
          <textarea class="materialize-textarea" formControlName='content' [id]="'content'"></textarea>
          <label [for]="'content'">Content</label>
          <validator-errors [control]='newsForm.get("content")'></validator-errors>
        </div>
        <div class="input-field col s12 margin-reset">
          <mat-form-field class="full-width">
            <mat-select [formControl]='newsForm.controls["partner_id"]'>
              <mat-option disabled selected>Categories</mat-option>
              <mat-option *ngFor="let partner of partners.data" [value]="partner.id">
              {{ partner.name }} </mat-option>
            </mat-select>
          </mat-form-field>
          <validator-errors [control]='newsForm.controls["partner_id"]'></validator-errors>
        </div>
        <div class="file-field col s12 input-field">
          <div class="btn">
            <span>File</span>
            <input (change)="fileChangeListener($event)" type="file"> </div>
          <div class="file-path-wrapper">
            <input class="file-path validate" type="text" placeholder="Upload one or more files"> </div>
        </div>
        <div class="col s12">
          <div class="flex flex-middle flex-center crop-area">
            <img-cropper #cropper [image]="data" [settings]="cropperSettings"></img-cropper>
            <i class="material-icons">arrow_forward</i>
            <div class="result rounded z-depth-1">
              <img [src]="data.image " *ngIf="data.image " [width]="cropperSettings.croppedWidth"
                [height]="cropperSettings.croppedHeight"> </div>
          </div>
        </div>
        <div class="col s12 form-bottom">
          <div class="left">
            <button type="button" onclick='window.history.back()' class='btn btn-large waves-effect waves-light '>
              <i class="material-icons">keyboard_arrow_left</i>
              <span>Back</span>
            </button>
          </div>
          <div class="right">
            <button [ngClass]="{'disabled':(newsForm['invalid']) || isSubmitting || !data.image }" type="submit" class='btn btn-large waves-effect waves-light '>
            Submit </button>
          </div>
        </div>
      </div>
    </form>
  </ng-container>
</div>

控制器

  partners;

  news = {};
  newsForm: FormGroup;

  ngOnInit() {
    setTimeout(() => {
      this._dashboardService.routeChangeStarted();
    }, 0);
    this._activatedRoute.params.subscribe(params => {
      this.news["id"] = params["id"];
      this.getPartners().then(data => {
        this.getNews().then(data=>{
          this.setForm();
        })
      });
    });
  }

  setForm() {
    this.newsForm = this._formBuilder.group({
     title: [this.news['title'], [Validators.required]],
     content: [this.news['content'], [Validators.required]],
     partner_id: [this.news['partner']['id'], [Validators.required]]
    });
    console.log(new Boolean(this.newsForm));
  }

  getPartners() {
    return Promise((res, rej) => {
      setTimeout(() => {
        this._dashboardService.progressStarted();
        this._dashboardService.routeChangeStarted();
      }, 0);
      this._partnerService.getPartners().subscribe(
        partners => {
          if (partners.status == 200) {
            this.partners = partners;
            res(partners.data);
          } else {
            this._errorActions.errorHandler(partners.status);
          }
          setTimeout(() => {
            this._dashboardService.progressFinished();
            this._dashboardService.routeChangeFinished();
          }, 0);
        },
        error => {
          this._notificationService.warning("Ups, something went wrong");
        }
      );
    });
  }

  getNews() {
    setTimeout(() => {
      this._dashboardService.routeChangeStarted();
      this._dashboardService.progressStarted();
    }, 0);

    return Promise((res, rej) => {
      this._newsService.getNews(this.news["id"]).subscribe(
        data => {
          if (data["status"] == 200) {
            Object.assign(this.news, data["data"]);
            res(this.news);
          } else {
            this._errorActions.errorHandler(data["status"]);
          }
          setTimeout(() => {
            this._dashboardService.progressFinished();
            this._dashboardService.routeChangeFinished();
          }, 0);
        },
        error => {
          this._notificationService.error("Ups, something went wrong");
        }
      );
    });
  }

有什么问题?设置表单后,它甚至不显示表单本身。从 API 加载数据后,还有其他方法可以设置表单值吗?

【问题讨论】:

    标签: angular typescript angular2-forms angular-reactive-forms


    【解决方案1】:

    您可以创建一个单独的函数来用数据填充表单。您可以在从 API 获取数据后调用此函数。

    变体 1:setValue

    官方角度文档:setValue

    使用 setValue,您可以通过传入其属性与 FormGroup 后面的表单模型完全匹配的数据对象来一次分配每个表单控件值。

    例子:

    updateValues(dataObject: any) {
      this.heroForm.setValue({
        name:    this.hero.name,
        address: this.hero.addresses[0] || new Address()
      });
    }
    

    变体 2:patchValue

    官方角度文档:patchValue

    使用 patchValue,您可以通过为感兴趣的控件提供键/值对对象来为 FormGroup 中的特定控件分配值。

    例子:

    updateValues(dataObject: any) {
      this.heroForm.patchValue({
        name: this.hero.name
      });
    }
    

    【讨论】:

    • 嗯更好的解决方案,下次遇到这个异步问题时我会这样做
    【解决方案2】:

    我遇到过这个问题,我不知道我的解决方案是否是最好的,但它确实有效。该技术是使用loaded: boolean,您启动到false,一旦您的数据在您的组件中完全接收,您将其设置为true

    这是一个例子:

    .html:

    <div *ngIf="loaded == false">
        <h2>loading ...</h2>
    </div>
    <div *ngIf="loaded == true">
       // your template goes here
    </div>
    

    在你的 .ts 中:

    loaded: boolean = false;
    
    // your code ....
    
    ngOnInit() {
      setTimeout(() => {
        this._dashboardService.routeChangeStarted();
      }, 0);
      this._activatedRoute.params.subscribe(params => {
        this.news["id"] = params["id"];
        this.getPartners().then(data => {
          this.getNews().then(data=>{
            this.setForm();
    
            // here is the important part!
            this.loaded = true
          })
        });
      });
    }
    

    【讨论】:

      【解决方案3】:

      您可以使用setValuepatchValue 为您提供异步数据FormGroup

      private initForm(): void {
          // For update product
          if (this.isUpdate) {
            this.productService.getProduct(this.id)
              .subscribe((product: Product) => {
                this.productForm.patchValue({
                  name: product.name,
                  price: product.price,
                  description: product.description,
                  image: product.image
                });
              });
          }
          // For create product
          this.productForm = new FormGroup({
            name: new FormControl(null, [
              Validators.required,
              Validators.minLength(8),
              Validators.maxLength(35)
            ]),
            price: new FormControl(null, [
              Validators.required,
              Validators.min(5000),
              Validators.max(50000000),
            ]),
            description: new FormControl(null, [
              Validators.required,
              Validators.minLength(8),
              Validators.maxLength(500)
            ]),
            image: new FormControl(null, Validators.required)
          });
        }
      

      【讨论】:

      • 很好...谢谢:)
      • 他们来了
      【解决方案4】:

      为了从 Promise 订阅更新表单,我需要手动运行更改检测。这可以通过导入来实现

      constructor(private changeDetectorRef: ChangeDetectorRef) {
      }
      

      正在运行

      this.changeDetectorRef.detectChanges();
      

      【讨论】:

        猜你喜欢
        • 2018-12-05
        • 2019-09-11
        • 2018-10-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-03
        • 2017-10-16
        • 1970-01-01
        相关资源
        最近更新 更多