Home > Back-end >  Convert Dictionary object to another Dictionay object rxjs Angular typescript
Convert Dictionary object to another Dictionay object rxjs Angular typescript

Time:07-02

I have the below dictionary which has the return type as { [key: string]: QueryBuilderFieldsDto }

{
    "2221": {
        "label": "Risk Domain",
        "name": "2221",
        "type": "dropdown",
        "typeLabel": "Dropdown",
        "isStandardField": false,
        "fieldEntityType": 2,
        "fieldEntityTypeLabel": "Risk",
        "options": [{
            "uniqueId": null,
            "id": 2636,
            "name": "Unassigned",
            "isOrganizationUnit": false
        }]
    },
    "2222": {
        "label": "Number Field",
        "name": "2222",
        "type": "number",
        "typeLabel": "Number",
        "isStandardField": false,
        "fieldEntityType": 2,
        "fieldEntityTypeLabel": "Risk"
    }
}

Properties of QueryBuilderFieldsDto describe below

export interface QueryBuilderFieldsDto {
    name: string;
    label: string;
    value?: string;
    type: string;
    nullable?: boolean;
    options?: Option[] | FieldOptionsDto[];
    operators?: string[];
    defaultValue?: any;
    defaultOperator?: any;
    isStandardField: boolean;
    fieldEntityType: number;
    fieldEntityTypeLabel?: string;
    typeLabel?: string;
    validator?: (rule: Rule, parent: RuleSet) => any | null;
}

Now I want to add an extra property over the dictionary object

   validator: (rule) => {
     if (rule.value == undefined || rule.value == "") {
       return {
         age: {
           rule: rule,
           message: 'Value cannot be empty'
         }
       }
     }
   }
 }

Example

"2222": {
            "label": "Number Field",
            "name": "2222",
            "type": "number",
            "typeLabel": "Number",
            "isStandardField": false,
            "fieldEntityType": 2,
            "fieldEntityTypeLabel": "Risk",
            validator: (rule) => {
            if (rule.value == undefined || rule.value == "") {
             return {
             age: {
               rule: rule,
               message: 'Value cannot be empty'
               }
             }
           }
         }
       }
    }

I am subscribing to the Observable

this.metricCreateConfigureStore.queryBuilderFields$.subscribe(item => {
      this.fields = item as { [key: string]: QueryBuilderFieldsDto };
    })

This returns the value without validator property, I know we use pipe and map to return the desired value, but not sure how to do it, the return type from the map should be

{ [key: string]: QueryBuilderFieldsDto }

The return type of queryBuilderFields is queryBuilderFields$: Observable<{ [key: string]: QueryBuilderFieldsDto; }>

Tried something like below but got an error on vscode

enter image description here

CodePudding user response:

The question is basically how to map a key/value pair in rxjs. As far as I know map cannot do that, instead I would use reduce. This is how I would go about it:

from(Object.entries(data)) // convert object to [key, value]
  .pipe(
    reduce((obj, item) => {
      item[1].validator = validatorFn; // add the validator function to the value
      obj[item[0]] = item[1]; // convert [key, value] back to object
      return obj;
    }, {})
  )
  .subscribe((result) => {
    console.log(result);
  });

working example

EDIT: If you are expecting an asynchronous stream of data you can replace reduce with scan (docs)

CodePudding user response:

The error you see in vscode has following reason:

Map functions can be defined in full or short

map(foo => bar)

map(foo => { return bar; })

In your screenshot the curly brackets belong to the 2nd variant, which means to the map function. They do NOT belong to the object you try to return.

Either add () around {}

map(foo => ({ bar: 'baz'}))

Or add the return statement

map(foo => { return { bar: 'baz' } })

CodePudding user response:

This works for me

    this.metricCreateConfigureStore.queryBuilderFields$
      .map((data) => {
        var mapValue: { [key: string]: Field; } = {};
        Object.keys(data).forEach(key => {
          mapValue[key] = this.mapField(data[key]);
        });
        return mapValue;
      })
      .subscribe(item => {
        this.fields = item as { [key: string]: Field };
      })
  }




private mapField(field: QueryBuilderFieldsDto): Field {
    const fields =
      {
        name: field.name,
        label: field.label,
        type: field.type,
        typeLabel: field.typeLabel,
        options: field.options,
        isStandardField: field.isStandardField,
        fieldEntityTypeLabel: field.fieldEntityTypeLabel,
        fieldEntityType: field.fieldEntityType,
        validator: (rule) => {
          if (rule.value == undefined || rule.value == "") {
            return {
              'required': {
                rule: rule,
                message: 'Value cannot be empty'
              }
            }
          }
        }
      } as Field;
    return fields;
  }
  • Related