[] vs [{…}] in browser tools, while both having sa

2020-04-20 07:41发布

问题:

If you look at the picture both arrays consist of same kind of object. first I create it with empty data as placeholder, but second one I create it with data coming from server.

  writeValue(v: any) {
    console.log('aaa');
    console.log(v);
    console.log('aaa');
    this.form = new FormArray([]);
    for (const value of v) {
      console.log('bbb');
      console.log(value);
      console.log('bbb');
      this.form.push(new FormControl(value));
    }
    this.form.valueChanges.subscribe(res => {
      if (this.onChange) {
        this.onChange(this.form.value);
      }
    });
  }

for first case it goes through all of the writeValue code, for second one it doesn't go through the for(const values of v) code. why is this happening? when I print them out they seem to be the same other than one difference [{...}] vs [] in browser tools.

If you want to see how I create them. the first one is routes and the second one is routeslocal. I put them in angular formcontrol, and thats how it gets to writeValue via controlvalueaccessor. If you want to know how it works you could check my previous question here. there is more code, but it doesn't include the service.

ngOnInit() {

    const routes: any[] = [];
    routes.push({ ...dataI });

    this.requestForm = this.fb.group({
      statusId: null,
      requestVehicles: this.fb.array([
        this.fb.group({
          garageId: 0,
          routes: new FormControl(routes),
          endDateTime: 0,
        })
      ])
    });

    if (this.data.isEdit) {
      this.Title = 'Edit';
      this.data.fService.getRequest(this.data.requestId).subscribe(thisRequest => {
        this.requestForm = this.fb.group({
          statusId: thisRequest.status,
          requestVehicles: this.fb.array([
          ])
        });
        thisRequest.requestVehicles.forEach((element, index) => {

          const routeslocal: any[] = [];
          element.routes.forEach((elementt, indexx) => {
            this.data.fService.getAddressPoint(elementt).subscribe(sbed => {
              const newRoute = {
                addressPointId: sbed.addressPointId,
                municipalityId: sbed.municipalityId,
                regionId: sbed.regionId,
                rvId: element.rvId,
                sequenceNumber: indexx,
                settlementId: sbed.settlementId,
                regionName: sbed.regionName,
                municipalityName: sbed.municipalityName,
                settlementName: sbed.settlementName,
                description: sbed.description,
              };
              routeslocal.push({...newRoute});
            });
          });

          this.requestVehicles.push(this.fb.group({
            endDateTime: new Date(element.endDateTime),
            garageId: element.garageId,
            routes: new FormControl(routeslocal),
          }));
            });
          });
        });
      });
    }
  }

回答1:

The opening line, [] or [{}], is immediately drawn in the console.

In the case of [], there was nothing in the array at logging time, so the browser draw it as an empty array. But the data was present when you looked at it and clicked on the small triangle, later.

You can reproduce this behavior with this code in your console:

;(function(){ let arr=[]; setTimeout(()=>{ arr[0] = {b:3}; }); return arr;})()

So the difference you saw is related to the (a)synchronicity of array filling.



回答2:

Vato, you has two functions in your service:getRequest(requestId) and getAddressPoint(requestVehicles). The idea is return a whole object. You can create the function in the own service or in the component. I'd like in the service, and that return an objservable. You must use forkJoin and swithMap So . It's for me impossible check if work

**Update, see the stackblitz

  getFullRequest(id): Observable<any> {
    return this.getRequest(id).pipe(
      switchMap((request: any) => {
        //here you has the request. We create an array of observables
        return forkJoin(
          request.requestVehicles.map(
            (r: any) => this.getAddressPoint(r))).pipe(map((res: any[]) => {
              res.forEach((x: any, index: number) => {
                x.sequenceNumber = index
              })
              return {
                statusId: request.statusID,
                routes: res
              }
            })
            )
      }))
 }

then, in your component

if (this.data.isEdit) {
      this.Title = 'Edit';
      this.data.fService.getFullRequest(this.data.requestId).subscribe(thisRequest => {
        this.requestForm = this.fb.group({
          statusId: thisRequest.status,
          requestVehicles: thisRequest.routes
        });

Update 2 briefly explain about switchMap and forkJoin.

When we make this.getRequest(id) we received in request an object. In this object we has in requestVehicles an array (can be an array of objects or an array of numbers -or strings-). With each element of this array we can make a call, But instead of make the calls one to one, we want to make all these together. For this we use forkJoin. forkJoin received an array of observables and, in subscribe received the response in an array

//if we has an observable like:
getValue(id:number):Observable<any>{
   return of({one:id})
}
//and an array like
myArray=[1,2]
//and an array of response whe we can store the responses
response:any[]

//we can do
for (let id of myArray)
{
     this.getValue(id).susbcribe(res=>{
         this.response.push(res)
     })
}
//or
observables:any[]
for (let id of myArray)
{
     this.observables.push(this.getValue(id))
}
forkJoin(this.observables).subscribe((res;any[])=>{
  //in res[0] we have the result of this.getValue(1)
  //in res[1] we have the result of this.getValue(2)
  //so, simply
  this.response=res
})

//or in a compact way
//with each element of the array
observables=myArray.map(x=>this.getValues(x))

forkJoin(this.observables).subscribe((res;any[])=>{
  this.response=res
})

Well, there are two problems more. We want add a new propertie "sequenceNumber" to all the response. So we use res.forEach(...) to add the property. And we want return an object with somes properties of our original request (statusID) and in "routes" the array with the response. So we use map to transform the response. In our simple example above

//not return simple {one:1}
//return {id:1,one:1}
getResponse(2).pipe.map(res=>{
    return {
        id:1,
        one:res.one
    }
}