Home > Back-end >  Mapping an observable response as an array of custom interfaces in Angular
Mapping an observable response as an array of custom interfaces in Angular

Time:10-17

I have an Observable keyValue(): Observable<{[id: number]: string;}>;

The Observable's argument is:

{
    [id: number]: string;
}

As you can see the second argument haven't name

Now one result of my previous Observable was:

{1: 'Bad', 2: 'Good', 3: 'Worst', 4: 'Best', 5: 'Mean'}

I need to translate as an array of:

interface NumberKeyValue {
   id: number;
   value: string;
 }

I was trying with:

.keyValue()
  .pipe(
    map((kv) => {
      console.log(kv);
      const jsonObject = JSON.parse(JSON.stringify(kv));
      console.log(jsonObject);
      const nkvArray: NumberKeyValue[] = [];
      for (const item of jsonObject) {
        console.log(item);
        const nkv: NumberKeyValue = {
          id: 8,                                        //How to catch the id number?
          value: 'empty',                               //How to catch the string?
        };
        nkvArray.push(nkv);
      }
      return nkvArray;
    })
  )
  .subscribe((response) => {
    console.log(response);
  });

After of previous code I got:

TypeError: jsonObject is not iterable
    at MapSubscriber.project (template-sms.facade.ts:295)
    at MapSubscriber._next (map.js:29)
    at MapSubscriber.next (Subscriber.js:49)
    at TapSubscriber._next (tap.js:46)
    at TapSubscriber.next (Subscriber.js:49)
    at SwitchMapSubscriber.notifyNext (switchMap.js:70)
    at InnerSubscriber._next (InnerSubscriber.js:11)
    at InnerSubscriber.next (Subscriber.js:49)
    at MapSubscriber._next (map.js:35)
    at MapSubscriber.next (Subscriber.js:49)

First and mainly Question:How I can to translate to one Array of my NumberKeyValue interface?

Secondly: Is there a name for this type representation {[id: number]: string;}?

CodePudding user response:

The object type is indeed not iterable, but you can use Object.keys to get an array of keys that you can then use to project the data in the desired form:

.keyValue()
  .pipe(
    map((kv) => {
      // use object destructuring to get a new reference instead of
      // JSON.parse(JSON.stringify(something))
      const jsonObject = { ...kv };
      return Object.keys(jsonObject).map(key => ({ id: key, value: jsonObject[key] });
    }),
  ).subscribe((response) => {
    console.log(response);
  });

CodePudding user response:

According to the Octavian Answer, as you can see, a cast is needed, using key instead of key; and an Array of NumberKeyValue Interface.

  .keyValue()
  .pipe(
    map((kv) => {
      const jsonObject = { ...kv };

      return Object
        .keys(jsonObject)
        .map((key) => {
          const nkv: NumberKeyValue = { id:  key, value: jsonObject[ key] };

          return nkv;
        });
    }),
  )
  .subscribe((response) => {
    console.log(response);
  });
  
  

Previously, I was thinking in archaic form.

  .keyValue()
  .pipe(
    map((kv) => {
      const numberKVArray: NumberKeyValue[] = [];
      let response = JSON.stringify(kv);
      response = response.replace(/[{}]/g, '');
      const pairs = response.split('",');
      for (const pair of pairs) {
        const property = pair.split(':"');
        property[0] = property[0].replace(/(^"|"$)/g, '');
        property[1] = property[1].replace(/(^"|"$)/g, '');
        const nkv: NumberKeyValue = {
          id:  property[0],
          value: property[1],
        };
        numberKVArray.push(nkv);
      }

      return numberKVArray;
    }),
    takeUntil(this.destroy$),
  )
  .subscribe((response) => {
    console.log(response);
  });

But, The first answer is best oriented.

  • Related