简体   繁体   English

创建JSON对象多次调用Angular 2 RXJS

[英]Create JSON Object multiple calls Angular 2 RXJS

I´ma little bit confused about this, but here I go: 我对此有些困惑,但是我去了:

I have information about two characters, which I get from multiple endpoints. 我有关于两个字符的信息,这些信息是从多个端点获得的。 This information is just single data that is not organised from the backend, so instead of receiving something like this: 这些信息只是未从后端组织的单个数据,因此不要接收如下内容:

character{
    character1{
        name: "Name of Character",
        age: "21",
        jobs: {
                job1: {
                    position:
                    company:
                },
                job2: {
                    position:
                    company;
                }
        }
    },
    character2{
        name: "Name of Character",
        age: "21",
        jobs: {
                job1: {
                    position:
                    company:
                },
                job2: {
                    position:
                    company;
                }
        }
    }   
}

I receive character name from one endpoint, character age in another and so on, for example: 我从一个端点接收字符名称,在另一个端点接收字符年龄,依此类推,例如:

.../Characters/Character_1
../Characters/Character_1/age
../Characters/Character_1/name
../Characters/Character_1/job1
../Characters/Character_1/job1/position
../Characters/Character_1/job1/company

..and separated endpoints for character 2... ..并分隔字符2的端点...

../Characters/Character_2
../Characters/Character_2/age
../Characters/Character_2/name
...

From my point of view, this organisation process should be done from the backend, but sadly it is not, and that´s the way I have to collect the data. 从我的角度来看,该组织过程应该从后端完成,但遗憾的是,它不是,这就是我必须收集数据的方式。

I must not only displaying information, but sometimes I also have to count how many jobs a character has. 我不仅必须显示信息,而且有时我还必须计算一个角色有多少工作。

REMOVED FIRST EXAMPLES AS THEY WON´T WORK 删除了第一个无法使用的示例


STEP 1 第1步

So, as suggested I started to use forkJoin 因此,按照建议,我开始使用forkJoin

with .../Characters/ I get the number of characters. 与... /字符/我得到的字符数。 This endpoint contains a list of endpoints urls where I need to return only those that include the word Character in theirs URL. 该终结点包含一个终结点URL列表,在这些URL中,我仅需要返回在URL中包含单词Character的URL。

Note: All Endpoints return information in the next format: 注意:所有端点均以以下格式返回信息:

{"children":["../pathOfCurrentEndpoint/path_1","../pathOfCurrentEndpoint/path_2","../pathOfCurrentEndpoint/path_3","../pathOfCurrentEndpoint/path_4"],"path":"../pathOfCurrentEndpoint","type":"Folder"}

//Component //零件

  public characterVariable: any;

  constructor(private _service: Service) {    
    this.getCharacters();
  }

  getCharacters() {
    this._service.getAllCharacters().subscribe(
      characters => { this.characterVariable = characters;
        console.log("Json Object", this.characterVariable);
      },
      error => this.errorMessage = <any>error
    );
  }

//Service //服务

    /**
   * This method obtains the number of characters and all the data from each one of them
   * @returns {Array} Observable array witth each Character data
   */
  getAllCharacters(): Observable<String[]> {

    let url = '../Characters';
    let subString = 'Character';
    return this.http.get(url)
      .map(this.extractPath)
      .map(data => data.filter(data => data.includes(subString)))
      //Send the two founded characters URL
      .concatMap((data) => this.getCharactersEndpoints(data))
      .catch(this.handleError);
  }

  getCharactersEndpoints(data): Observable<String[]> {
    let observables: any = [];
    let subString = 'Job';


    for (let i = 0; i < data.length; i++) {
      let url = 'urlPath/' + data[i];

      observables.push(this.http.get(url)
        .map(this.extractPath)

        //Send the "children" from each character: age, job_1, job_2, etc..
        .concatMap((data) => this.getCharactersValues(data))
        .catch(this.handleError));
    }
    return Observable.forkJoin(observables);
  }

  getCharactersValues(data): Observable<String[]> {
    let observables: any = [];

    //Get Age Value
    for (let i = 0; i < data.length; i++) {
      let url = 'urlPath/' + data[i];

      if (url.includes('Age')) {
        observables.push(this.http.get(url)
          .map(this.extractValue)
          .catch(this.handleError));
      }

      //Get Jobs Endpoints
      if (url.includes('Job')) {
        let url = 'urlPath/' + data[i];
        observables.push(this.http.get(url)
          .map(this.extractPath)
          //Send the "children" from each Job: position, company, etc..
          .concatMap((data) => this.getJobsValues(data))
          .catch(this.handleError));

      }
    }
    return Observable.forkJoin(observables);
  }


  getJobsValues(data): Observable<Number[]> {
    let observables: any = [];
    for (let i = 0; i < data.length; i++) {
      let url =  'urlPath/' + data[i];
      observables.push(this.http.get(url).map(this.extractValue).catch(this.handleError));
    }
    return Observable.forkJoin(observables);
  }


  private extractPath(res: Response) {
    let body = res.json().children;
    return body;
  }

  private extractValue(res: Response) {
    let body = res.json().value;
    return body;
  }


  private handleError(error: any) {
    let errMsg = error.message || 'Server error';
    console.error(errMsg); 
    return Observable.throw(errMsg);
  }

When I print characterVariable I get: 当我打印characterVariable时,我得到:

  Json Object 
  0:  Array[5]
      0:  21 //This is the age
      1 : Array[2]
        0 : "current position" //Current job position
        1 : "current company" //Current company
      2 : Array[2]
        0 : "previous position" //Previous job position
        1 : "previous company" //Previous company       
        ....
   1:  Array[5]
      0:  32 //This is the age
      1 : Array[2]
        0 : "current position" //Current job position
        1 : "current company" //Current company
      2 : Array[2]
        0 : "previous position" //Previous job position
        1 : "previous company" //Previous company       
        ....

I don´t know if this is the best way to organise the data. 我不知道这是否是组织数据的最佳方法。 Any suggestions would be appreciated. 任何建议,将不胜感激。

The next question is, where should I define that array[0][0] is the age of the first character in order to create the json Object similar to the one defined at the beginning. 下一个问题是,我应该在哪里定义array [0] [0]是第一个字符的年龄,以便创建类似于开头定义的json对象。

Thanks. 谢谢。

I've made a sample with your code, seems everything fine but: 我用您的代码制作了一个示例,看起来一切都很好,但是:

1) Are you sure that somebody called getCharacters() and getCharactersAge() methods on component 1)您确定有人在组件上调用了getCharacters()和getCharactersAge()方法

2) You can easily transform JSON data structure to array using map operator 2)您可以使用地图运算符轻松地将JSON数据结构转换为数组

3) Somebody should call unsubscribe. 3)有人应致电退订。 Below you can find an example of using async pipe - in that case unsubscribe will be called automatically on component destroy stage 您可以在下面找到使用异步管道的示例-在这种情况下,取消订阅将在组件销毁阶段自动调用

A component in nutshell: 概括地说:

  @Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
  })
  export class AppComponent {
    title = 'app';

    character: any;
    character$: Observable<any>;

    errorMessage: any;

    constructor(private _service: MyNewServiceService) {
      this.getCharacters();

      // Better way - with auto usubscribe
      this.character$ = this._service.getCharacters();
    }

    getCharacters() {
      // here problem - no unsubscription !
      this._service.getCharacters().subscribe(
        (characters) => {
          this.character = characters;
        },
        (error) => {
        },
        () => {
        }
      );
    }
  }

template: 模板:

    <ul>
      {{character | json}}

      <p *ngFor="let person of character">
        <span>{{person.name}}</span>
      </p>

      <p *ngFor="let person of (character$|async)">
        <span>{{person.name}}</span>
      </p>

    </ul>

Service stub: 服务存根:

  import {Injectable} from '@angular/core';
  import {Observable} from 'rxjs';

  @Injectable()
  export class MyNewServiceService {

    constructor() {
    }

    getCharacters() {

      const x = {
        character1: {
          name: 'Name of Character 1',
          age: '21',
          jobs: {
            job1: {
              position: '',
              company: ''
            },
            job2: {
              position: '',
              company: ''
            }
          }
        },
        character2: {
          name: 'Name of Character 2',
          age: '21',
          jobs: {
            job1: {
              position: '',
              company: ''
            },
            job2: {
              position: '',
              company: ''
            }
          }
        }
      };

      // debugger
      // const z = Observable.of(false);
      return Observable.from([x]).map( (data) => {
        const result = [];
        Object.keys(data).forEach( key => {
          result.push(data[key]);
        });
        return result;
      });
    }
  }

You could use Observable.forkJoin to combine the data of many requests. 您可以使用Observable.forkJoin组合许多请求的数据。

Single Item 单项

const numbersObs = Observable.from(['1', '2', '3', '4']);
const lettersObs = Observable.from(['a', 'b', 'c', 'd']);
const booleanObs = Observable.from([true, true, false, false]);

Observable.forkJoin(numbersObs, lettersObs, booleanObs)
  .subscribe(result => {
    console.log("result", result);
    this.singleResult = {
        id: result[0],
        name: result[1],
        selected: result[2]
      }
  })

This will create an object: 这将创建一个对象:

{
  "id": "4",
  "name": "d",
  "selected": false
}

From the last emitted item of each observable. 从每个可观察到的最后一个发射项目开始。

Live plunker example 现场演奏的例子

Array of items 项目数组

If you wanted to create an array of objects from arrays returned from fork join you could do that as well (included in plunker example and code below) This code assumes the order is correct and that all the property arrays are the same length (each item has every property) 如果您想从fork join返回的数组中创建对象数组,您也可以这样做(包含在plunker示例和下面的代码中) 此代码假定顺序正确,并且所有属性数组的长度相同(每个项目拥有所有财产)

// If you can guarantee all the results in the correct order
Observable.forkJoin(numbersObs.toArray(), lettersObs.toArray(), booleanObs.toArray())
  .subscribe(result => {
    console.log("result", result);
    this.results = result[0].map((item, index) => {
      return {
        id: result[0][index],
        name: result[1][index],
        selected: result[2][index]
      }
    })
  })

This will create 这将创建

[
  {
    "id": "1",
    "name": "a",
    "selected": true
  },
  {
    "id": "2",
    "name": "b",
    "selected": true
  },
  {
    "id": "3",
    "name": "c",
    "selected": false
  },
  {
    "id": "4",
    "name": "d",
    "selected": false
  }
]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM