skip to Main Content

In Angular, I have two arrays,

internal = [
 {"name": 123, "doName": cityA, "dataType": string},
 {"name": 345, "doName": cityB, "dataType": string},
 {"name": 567, "doName": cityC, "dataType": string},
 {"name": 789, "doName": cityD, "dataType": string},
]

and

plans = [
 {"user": personA, "idData": 111, "datatype": string},
 {"user": personB, "idData": 222, "datatype": string},
 {"user": personC, "idData": 333, "datatype": string},
 {"user": personD, "idData": 123, "datatype": string}
]

The goal is that inside of a cell renderer, id.cell-renderer.ts, to return the value of either 1) the doName of the user from plans array if the "name" from the internal array and "idData" from the plans array match, and if not, just return the "idData" from the plans array. For example, the table would show

enter image description here

All the data comes from the plans array except for the last row idData which gets replaced by the doName from internal array because the name of 123 from the internal matched the 123 of the idData from the plans array.

Inside of a cell renderer, I have

this.params = params;
newData = this.params.idData;

agInit(params): void {
  this.subs.sink  = combineLatest([
    this.api.plans(),
    this.api.internal()
  ]).subscribe([plans, internal]) => {
    if (!plans || !internal) return;
      ? <-- wonder what to do here -->
  }
});

The next step would be to compare the two arrays plans and internal on the key values of ‘idData’ and ‘name’ and where the two values are the same, replace ‘idData’ from the plans array with the value of the ‘doName’ from the internal array but I am unsure of how to proceed. Do I use a intersection, map the arrays based on the values and then use a for / if statement or use a filter on the data internal array. Would like to return the value in newData.

2

Answers


  1. One possible solution here is to create a map first, and then access it by id. This reduces complexity from O(n) to O(1) while searching by id.

    // create map of internal items by their id
    // can be memoized, for example in react useMemo can be used
    const internalById = internal.reduce((r, x) => {
      r[x.name] = x
      return r
    }, {})
    
    const renderCell = (plan) => {
      // try to get internal doName by id, use plan.idData if not found
      const name = internalById[plan.idData]?.doName ?? plan.idData
    
      ...
    }
    
    Login or Signup to reply.
  2. The key concept will be you need to iterate each item in the plans array and override the idData value if the associated external object.

    plans.map((x: any) => ({
      ...x,
      idData:
        internal.find((y: any) => y.name == x.idData)?.doName ?? x.idData,
    }));
    

    Unsure what is your subs.sink type:

    If subs.sink is an array, you shouldn’t assign the Subscription to it

    combineLatest([this.plans$, this.internal$]).subscribe(
      ([plans, internal]: any) => {
        if (!plans || !internal) return;
        this.subs.sink = plans.map((x: any) => ({
          ...x,
          idData:
            internal.find((y: any) => y.name == x.idData)?.doName ?? x.idData,
        }));
      }
    );
    

    If subs.sink is an Observable:

    this.subs.sink = combineLatest([this.plans$, this.internal$]).pipe(
      map(([plans, internal]) => {
        //if (!plans || !internal) return;
    
        return plans.map((x: any) => ({
          ...x,
          idData:
            internal.find((y: any) => y.name == x.idData)?.doName ?? x.idData,
        }));
      })
    );
    

    And you should subscribe the Observable via async pipe:

    <table class="table">
      <tr *ngFor="let sink of (subs$.sink | async)">
        <td>{{ sink.idData }}</td>
        <td>{{ sink.user }}</td>
        <td>{{ sink.datatype }}</td>
      </tr>
    </table>
    

    Demo @ StackBlitz

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search