0

I have an Angular component, that subscribes to an observable, returned by an Angular Service.

Component: help.component.ts

import { WikiService } from '../../../services/wiki.service';

import { WikiTree } from '../../../interfaces/WikiTree';

export class HelpComponent implements OnInit {

    wikiTree$: Observable<WikiTree>

    public infoCards: Array<Object>;

    constructor(private wikiService: WikiService) {}

    ngOnInit() {
            this.wikiTree$ = this.wikiService.GetWikiHierarchy();
            this.wikiTree$.subscribe(()=>{
               //TODO: Create infoCards array by iterating through the results array inside the wikiTree observable.
            }
        }
}

The wikiTree$ Observable has the following JSON, converted to TypeScript:

{
    "page": {
        "results": [
            {
                "id": "123456789",
                "type": "page",
                "status": "current",
                "title": "Start here",
                "extensions": {
                    "position": 0
                },
                "_links": {
                    "webui": "/display/MYSPACE/Start+here",
                    "edit": "/pages/resumedraft.action?draftId=123456789",
                    "tinyui": "/x/BQD2Mw",
                    "self": "https://wiki.abc.com/rest/api/content/123456789"
                },
                "_expandable": {
                    "container": "/rest/api/space/MYSPACE",
                    "metadata": "",
                    "operations": "",
                    "children": "/rest/api/content/123456789/child",
                    "restrictions": "/rest/api/content/123456789/restriction/byOperation",
                    "history": "/rest/api/content/123456789/history",
                    "ancestors": "",
                    "body": "",
                    "version": "",
                    "descendants": "/rest/api/content/123456789/descendant",
                    "space": "/rest/api/space/MYSPACE"
                }
            },
            {
                "id": "567890123",
                "type": "page",
                "status": "current",
                "title": "FAQ",
                "extensions": {
                    "position": 1
                },
                "_links": {
                    "webui": "/display/MYSPACE/FAQ",
                    "edit": "/pages/resumedraft.action?draftId=567890123",
                    "tinyui": "/x/HQD2Mw",
                    "self": "https://wiki.abc.com/rest/api/content/567890123"
                },
                "_expandable": {
                    "container": "/rest/api/space/MYSPACE",
                    "metadata": "",
                    "operations": "",
                    "children": "/rest/api/content/567890123/child",
                    "restrictions": "/rest/api/content/567890123/restriction/byOperation",
                    "history": "/rest/api/content/567890123/history",
                    "ancestors": "",
                    "body": "",
                    "version": "",
                    "descendants": "/rest/api/content/567890123/descendant",
                    "space": "/rest/api/space/MYSPACE"
                }
            }
        ],
        "start": 0,
        "limit": 25,
        "size": 2,
        "_links": {
            "self": "https://wiki.abc.com/rest/api/content/998877665/child/page"
        }
    },
    "_links": {
        "base": "https://wiki.abc.com",
        "context": "",
        "self": "https://wiki.abc.com/rest/api/content/998877665/child"
    },
    "_expandable": {
        "attachment": "/rest/api/content/998877665/child/attachment",
        "comment": "/rest/api/content/998877665/child/comment"
    }
}

TypeScript: WikiTree.ts

export interface WikiTree {
    page: Page;
    _links: Links;
    _expandable: Expandable;
  }
  export interface Page {
    results?: (ResultsEntity)[] | null;
    start: number;
    limit: number;
    size: number;
    _links: Links1;
  }
  export interface ResultsEntity {
    id: string;
    type: string;
    status: string;
    title: string;
    extensions: Extensions;
    _links: Links2;
    _expandable: Expandable1;
  }
  export interface Extensions {
    position: number;
  }
  export interface Links2 {
    webui: string;
    edit: string;
    tinyui: string;
    self: string;
  }
  export interface Expandable1 {
    container: string;
    metadata: string;
    operations: string;
    children: string;
    restrictions: string;
    history: string;
    ancestors: string;
    body: string;
    version: string;
    descendants: string;
    space: string;
  }
  export interface Links1 {
    self: string;
  }
  export interface Links {
    base: string;
    context: string;
    self: string;
  }
  export interface Expandable {
    attachment: string;
    comment: string;
  }

I would like to iterate through "page" -> "results" array in the wikiTree$ observable in the subscribe method and create an array of objects called infoCards, as defined in the component with this JSON, with some of the values coming from wikiTree$ observable. :

[{
        "title": "Start here",
        "titleLink": "/page/wiki/123456789",
        "children": []
    },
    {
        "title": "FAQ",
        "titleLink": "/page/wiki/567890123",
        "children": []
    }
    ]

How do I do that?

Update:

InfoCard Component

import { Component, OnInit, Input } from '@angular/core';

@Component({
  selector: 'app-info-card',
  templateUrl: './info-card.component.html',
  styleUrls: ['./info-card.component.css']
})
export class InfoCardComponent implements OnInit {
  @Input('infoCard') infoCard: Array<Object>;

  constructor() { }

  ngOnInit() {
  }

}

2 Answers 2

1

The following subscription will create new objects based on the structure you had provided whenever new data comes in. I am assuming you only need title and titleLink in the specified format and children array is derived from another service ?

this.wikiTree$.subscribe( res => {
    const newInfoCards = res.page.results.map(result => ({
        "title": result.title,
        "titleLink": "/page/wiki/"+ result._links.self.split('/').pop(),
        "children": []
    }),
    this.infoCards.concat(newInfoCards);
})
Sign up to request clarification or add additional context in comments.

7 Comments

yes.. Children array will be a result of an observable from a different function in the WikiService array. Basically, it's a different API call to get the data.
I get an error: Block-scoped variable 'newInfoCards' used before its declaration.
are you sure you used the same code ? the order may be important since we used const. You can remove the error if you use var instead. I am assuming you used concat before the map statement ?
I think that concat doesn't work, because infoCards is defined as an array of objects. We may need some thing else there.
Since it is an array, concat should work fine regardless of the values inside, in any case, you could also try this.infoCards = [...this.infoCards,...newInfoCards]
|
1

If I would face this then I would solve this like below:

At first, I would create a Model (Class) like the models in your WikiTree.ts for InfoCard. I am making this a Class to create an Object of it inside the subscribe method-

export class InfoCard{
        title: string;
        titleLink: string;
        children: string;
  }

After that in the Component: help.component.ts I would declare infoCards like this-

infoCards: InfoCard[]=[];

Obviously, you have to import InfoCard from WikiTree.ts-

import { InfoCard} from '../../../interfaces/WikiTree';

Then inside the subscribe method, I would map the data coming as Observable-

    this.wikiTree$.subscribe(data =>{
      data.page.results.map(
       result=>{
          let newInfoCard = new InfoCard();
          newInfoCard.title = result.title;
          newInfoCard.children= result._expandable.children;
          newInfoCard.titleLink= result._links.self;
          this.infoCards = [this.infoCards, ...newInfoCard]
        }
       )
     }

As you've added the Component Part, so you can try this also-

Initialize the array-

infoCards: Array<Object>= new Array();

There may be more options to get it done. I am sharing mine. Let me know if you don't understand anything or have a question or the mistakes I have made.

    forkJoin(
        this.wikiService.GetWikiHierarchy(),
        this.wikiService.GetWikiChildren()
    ).subscribe(([data, children]) => {
        data.page.results.map(
            result => {
                this.infoCards.push({
                    'title': result.title,
                    'titleLink': result._links.self,
                    'children': children.whatEver
                });
            }
        )
    });

And, if the children call depends on previous service call you can try something like this-

  this.wikiService.GetWikiHierarchy().subscribe(
    data=>{
      data.page.results.map(
        result=>{
          this.wikiService.GetWikiChildren(result.id).subscribe(
            child=>{
                this.infoCards.push({
                  'title': result.title,
                  'titleLink': result._links.self,
                  'children': child.whatEver
                    });
            }
          )
        }
      )
    }
  )

4 Comments

In my code, I have a component called InfoCard, that generates some HTML based on the infoCard array. So, not sure about the model approach. I might just need a simple way to create an infoCards array in the subscribe method. Also, the children array needs to draw data from another observable not mentioned here. So, that is probably a call to a different function in the WikiService.
I have to see the implementation of the component of InfoCard then. And as you will call another service to get the children, you can use mergeMap or forkJoin.
added the InfoCard component to the question for your reference.
Added other options.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.