【问题标题】:Angular patch observable data to reactive form fields响应式表单字段的角度补丁可观察数据
【发布时间】:2021-12-28 15:05:38
【问题描述】:

我有一个响应式表单,我正在像这样初始化 oninit(),以及我用来从 URL 中获取传递的 id 并判断表单是否正在使用的其他几个属性在 mysql 表中更新或创建新条目。我遇到的问题是使用 patchValue 将从我的服务返回的数据传递到我的表单中:

组件.ts

    export class formComponent implements OnInit, AfterViewInit {
    
    constructor(
       private dataService: dataService,
       private route: ActivatedRoute,
       private router: Router,
       private formBuilder: FormBuilder,
       private ticketModel: ticketModel,
     ) {}

    Form!: FormGroup;
    isNewMode!: boolean;
    id!: string;
    ticket!: ticketModel[];

    ngOnInit(){    
        this.id = this.route.snapshot.params['id'];
        this.isNewMode = !this.id;

    this.Form = this.formBuilder.group({
    field1: ['', Validators.required],
    field2: ['', Validators.required],
    field3: ['', Validators.required],
    field4: ['', Validators.required] 

    });
}

ngAfterViewInit(){
  if(!this.isNewMode){
  this.sub = this.dataService.getById(this.id)
  .pipe(first())
  .subscribe({
    next: ticketData => {
    this.ticket = ticketData;
  },
});

this.Form.patchValue({
field1: this.ticket.field1, //error, "Property 'field1' does not exist on type 'ticketModel[]'"
field2: this.ticket.field2, //error, "Property 'field2' does not exist on type 'ticketModel[]'"
field3: this.ticket.field3, //error, "Property 'field3' does not exist on type 'ticketModel[]'"
field4: this.ticket.field4, //error, "Property 'field4' does not exist on type 'ticketModel[]'"

});

    }
  }
}

ticketModel.ts

export class ticketModel {
    id: string = '';
    field1: string = '';
    field2: string = '';
    field3: string = '';
    field4: string = '';
}

service.ts

export class dataService {
constructor(private errorHandlerService: errorHandlerService, private http: HttpClient) {}

private url = "/api/tickets";

httpOptions:{ headers: HttpHeaders } = {
      headers: new HttpHeaders({ "Content-Type": "application/json" }),
  };

getById(id: string): Observable<ticketModel[]> {
        return this.http
        .get<ticketModel[]>(`${this.url}/${id}`, {responseType: "json"})
        .pipe(tap((_) => console.log('returned by service: ', JSON.stringify(_))),
        catchError(
          this.errorHandlerService.handleError<ticketModel[]>("fetchAll", [])
        )
        );
    }

以防万一,这是我在运行此方法时得到的响应 json 示例

[{"id":18,"field1":"string data","field2":"data is here","field3":"another string goes here","field4":"this is another example string"}]

如果没有传入的 id,isNewMode 为真,并且表单使用空白值初始化,从那里可以正常工作。当传入 id 时,我将其传递给数据服务中的方法以查询数据库并仅返回该行。这似乎也可以正常工作,因为我能够将 json 格式的数据记录到控制台。 在尝试了几种不同的方法后,我只是不知道如何将数据修补到表单中

目前,我认为这应该起作用的方式是这段代码的一个例子,在 patchValue() 中,编译器会抛出一个错误,“property field1 在类型 ticketModel[] 上不存在" 当它绝对作为该模型的属性存在时。

我觉得我可能遗漏了一些非常小的东西,以及任何帮助弄清楚什么会受到广泛赞赏,谢谢!

【问题讨论】:

    标签: javascript angular typescript angular-reactive-forms


    【解决方案1】:

    您已将ticket!: ticketModel[] 声明为数组类型。

    你的响应也是一个数组 -

    [{"id":18,"field1":"string data","field2":"data is here","field3":"another string goes here","field4":"this is another example string"}]
    

    那你为什么不把this.ticket 当作一个数组呢?

    field1: this.ticket.field1,
    

    以这种方式使用它 - field1: this.ticket[0].field1 或在其上使用 for 循环以从中获取 field1 和其他值。

    而且您需要在订阅块内修补表单,因为它是一个异步操作。

    【讨论】:

    • 这帮助了很多!它并没有直接解决它,但它有助于帮助我解决这个问题,我最终将 patchValue 方法包装在同一个 subscribe next 方法块中,这样我就可以直接引用票证参数(我认为,不需要设置this.ticket=ticket) 然后以ticket: ticket[0].field1, 的方式修补这些值。不确定以这种方式访问​​数据的后果是什么,但它确实有效,再次感谢您!
    • @Cosmic 很高兴知道,它可以帮助你!快乐编码...
    【解决方案2】:

    确实,您的服务 getById 应该返回一个“TicketModel”,也不是一组 TicketModel。比在组件中管理好,在服务中使用地图管理

    //see that is an observable of "ticketModel"
    getById(id: string): Observable<ticketModel> {
        //you needn't use {responseType:'json'}, by defect Angular expect a Json
        return this.http
        .get<ticketModel[]>(`${this.url}/${id}`)
        .pipe(
             //just return the uniq element of the array
             map(res=>res.length?res[0]:null),
             tap((_) => console.log('returned by service: ', JSON.stringify(_))),
        catchError(
          this.errorHandlerService.handleError<ticketModel>("fetchAll", [])
        )
        );
    }
    

    此外,您需要使用“patchValue”inside订阅函数,并且您可以使用patchValue而不创建新对象,因为具有相同的属性

    if(!this.isNewMode){
      this.sub = this.dataService.getById(this.id)
      .pipe(first())
      .subscribe({
        next: ticketData => {
        this.ticket = ticketData; //<--really you needn't use ticketData
                                  //unless you want compare old and new Values
        //here you make the patchValue
        this.form.patchValue(ticketData);
      })
    }
    

    (你也可以用 ngOnInit 代替 ngAfterViewInit)

    更新另一种解决“经典”问题的方法来创建一个组件来编辑/创建一个元素。

    如果你有类似的功能

    getForm(data:TicketModel=null){
      data=data || {} as TicketModel
      return new FormGroup({
        id: new FormControl(data.id,Validators.required),
        field1: new FormControl(data.field1,Validators.required),
        field2: new FormControl(data.field2,Validators.required),
        field3: new FormControl(data.field3,Validators.required),
        field4: new FormControl(data.field4,Validators.required)
      })
    }
    

    你可以在 ngOnInit 中做一些喜欢

       ngOnInit(){
         this.id = this.route.snapshot.params['id'];
         this.isNewMode = !this.id;
         if (this.isNewMode)
            this.Form=this.getForm()
         else
         {
            this.sub = this.dataService.getById(this.id)
            .pipe(first())
            .subscribe(res=>{
              this.Form=this.getForm(res)
            })
          }
       }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-16
      • 1970-01-01
      • 2019-07-04
      • 2016-09-25
      • 2019-06-20
      • 1970-01-01
      • 2018-10-20
      • 1970-01-01
      相关资源
      最近更新 更多