Managing null values in RxJS map function

I'm facing a scenario where my Angular service retrieves values from an HTTP GET request and maps them to an Observable object of a specific type. Sometimes, one of the properties has a string value, while other times it's null, which I want to default to an empty string.

Is there a more elegant solution for this issue than the current approach I'm using?

I have attempted passing a boolean parameter for the specific field of interest, in this case, template.AreaId attribute. However, I am worried that as more attributes encounter similar problems over time with the creation of more template objects.

getTaskFromTemplate(extraChildTask:string, hasArea: boolean) : Observable<Task>{
    if (hasArea){
      return this.templateService.getTemplateByName(extraChildTask).pipe(
        map(template => {
          return {
            WorkItemId:'',
            WorkItemType:'Task',
            Title: template.Title,
            Description: template.Description,
            AssignedTo: '',
            TeamProject: template.TeamProjectName,
            AreaPathId: template.AreaId ? template.AreaId.toString() : '',
            IterationPathId: '',
            Application:'',
            State:'',
            TargetDate: null,
            OriginalEstimate: 0,
            CompletedWork: 0,
            RemainingWork: 0,
            BusinessPriority: '',
            CreatedBy:'',
            CreatedDate: null,
            Priority:'',
            Notes:'',
            AreaPathName:'',
            IterationPathName:'',
          }; 
        }),
        catchError((error: HttpErrorResponse) => { return throwError(error); })
      )
    }
    return this.templateService.getTemplateByName(extraChildTask).pipe(
      map(template => {
        return {
          WorkItemId:'',
          WorkItemType:'Task',
          Title: template.Title,
          Description: template.Description,
          AssignedTo: '',
          TeamProject: template.TeamProjectName,
          AreaPathId: '',
          IterationPathId: '',
          Application:'',
          State:'',
          TargetDate: null,
          OriginalEstimate: 0,
          CompletedWork: 0,
          RemainingWork:0,
          BusinessPriority: '',
          CreatedBy:'',
          CreatedDate: null,
          Priority:'',
          Notes:'',
          AreaPathName:'',
          IterationPathName:'',
        }; 
      }),
      catchError((error: HttpErrorResponse) => { return throwError(error); })
    )
  }

}

The above implementation is functional, but I seek a more efficient way to handle cases where a field is null or lacks a string value.

Here is how I initially structured the code before encountering issues with the null value of template.AreaId:

getTaskFromTemplate(extraChildTask:string) : Observable<Task>{
return this.templateService.getTemplateByName(extraChildTask).pipe(
    map(template => {
      return {
        WorkItemId:'',
        WorkItemType:'Task',
        Title: template.Title,
        Description: template.Description,
        AssignedTo: '',
        TeamProject: template.TeamProjectName,
        AreaPathId: template.AreaId ? template.AreaId.toString() : '',
        IterationPathId: '',
        Application:'',
        State:'',
        TargetDate: null,
        OriginalEstimate: 0,
        CompletedWork: 0,
        RemainingWork: 0,
        BusinessPriority: '',
        CreatedBy:'',
        CreatedDate: null,
        Priority:'',
        Notes:'',
        AreaPathName:'',
        IterationPathName:'',
      }; 
    }),
    catchError((error: HttpErrorResponse) => { return throwError(error); })
  )
}

Answer №1

It occurred to me that utilizing the ternary operator could enhance the functionality of this code snippet:

getTaskFromTemplate(extraChildTask:string) : Observable<Task>{
return this.templateService.getTemplateByName(extraChildTask).pipe(
    map(template => {
      return {
        WorkItemId:'',
        WorkItemType:'Task',
        Title: template.Title,
        Description: template.Description,
        AssignedTo: '',
        TeamProject: template.TeamProjectName,
        // Utilizing a ternary operation avoids calling `toString()` unnecessarily
        AreaPathId: template.AreaId != null ? template.AreaId.toString() : '',
        IterationPathId: '',
        Application:'',
        State:'',
        TargetDate: null,
        OriginalEstimate: 0,
        CompletedWork: 0,
        RemainingWork:0,
        BusinessPriority: '',
        CreatedBy:'',
        CreatedDate: null,
        Priority:'',
        Notes:'',
        AreaPathName:'',
        IterationPathName:'',
      }; 
    }),
    catchError((error: HttpErrorResponse) => { return throwError(error); })
  )
}

Furthermore, regarding dynamically mapping properties as mentioned earlier, here is an illustration of a potential solution:

const { of } = rxjs;
const { map } = rxjs.operators;

const baseTask = {
    Title: '',
    Description: '',
    TeamProjectName: '',
    AreaPathId: '',
    WorkItemId: '',
    WorkItemType: 'Task',
    // ...
};

function getTaskFromTemplate(extraChildTask, hasArea) {
  return getTemplateByName(extraChildTask).pipe(
    map(template => {
      // Merging properties from the template with those in the base task
      // Template properties take precedence
      return Object.assign({}, baseTask, template);
    }),
  );
}

// Simple implementation returning a fixed template
function getTemplateByName(extraChildTask) {
  return of({
    Title: 'Title',
    Description: 'Description',
    TeamProjectName: 'Team Project Name',
    AreaPathId: 'Area Path ID',
    // ...
  });
}

// Example usage
getTaskFromTemplate('something').subscribe(task => {
  console.log(task);
});
<script src="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="592b21332a196f776c776b">[email protected]</a>/bundles/rxjs.umd.min.js"></script>

A point worth mentioning is that if there are mismatches between task property names and those in the template, additional mapping steps may be required.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

(Typescript) The 'window' property is not present in the 'Global' type

Currently, I am utilizing Mocha/Chai for unit testing and have decided to mock the window object like so: global.window = { innerHeight: 1000, innerWidth: 1000 }; As expected, TSLint is raising an issue stating: Property 'window' does not ex ...

Uploading multiple strings to an Amazon S3 bucket using Node.js by piping a string

Suppose I have a simple loop similar to the one shown below: for (const i=0; i<3; i++) { to(`This incrementer is ${i}`) } At the end of the loop, I expect my file to contain: This counter is 0 This counter is 1 This counter is 2 I at ...

Encountering Typescript errors while compiling an Angular module with AOT enabled

I am currently in the process of manually constructing an Angular module with Webpack, opting not to use the CLI. While a normal build is functioning without any issues, encountering errors during an AOT build! Here's how my tsconfig.aot.json file ...

Struggling to dynamically update array values by comparing two arrays

I am faced with a scenario where I have two arrays within an Angular framework. One of the arrays is a regular array named A, containing values such as ['Stock_Number', 'Model', 'Type', 'Bill_Number'] The other arr ...

The TypeScript reflection system is unable to deduce the GraphQL type in this case. To resolve this issue, it is necessary to explicitly specify the type for the 'id' property of the 'Address'

import { ObjectType, ID, Int, Field } from 'type-graphql'; @ObjectType() export default class Address { @Field(type => ID) id: String; @Field() type: string; @Field() title: string; @Field() location: string; } More informa ...

Crafting a Retro Style

I have an interface called Product which includes properties such as name, and I want to track changes to these products using a separate interface called Change. A Change should include the original Product as well as all of its properties prefixed with t ...

React Hook Form is flagging missing dependencies in the useEffect function

Before posting this question, I made an effort to search for a solution on Google. However, I am puzzled by the warning that the linter is giving me regarding my code. The warning message reads: ./components/blocks/Contact.tsx 119:6 Warning: React Hook us ...

Guide to implementing ion-toggle for notifications with Ionic 2 and Angular 2

Currently, I am using a toggle icon to set the notification as active or inactive. The response is obtained from a GET call. In the GET call, the notification value is either 0 or 1, but in my TypeScript file, I am using noteValue as boolean, which means w ...

@ngrx effects ensure switchmap does not stop on error

Throughout the sign up process, I make 3 http calls: signing up with an auth provider, creating an account within the API, and then logging in. If the signup with the auth provider fails (e.g. due to an existing account), the process still tries to create ...

Exploring the most effective strategies for creating a brand-new type in TypeScript?

In the execution environment I'm working with, there are several global constants that represent different directions: TOP = 1 TOP_RIGHT = 2 RIGHT = 3 BOTTOM_RIGHT = 4 BOTTOM = 5 BOTTOM_LEFT = 6 LEFT = 7 TOP_LEFT = 8 These constants are not just ran ...

Integrate a fresh global JSX attribute into your React project without the need for @types in node_modules

It is crucial not to mention anything in tsconfig.json. Error Type '{ test: string; }' cannot be assigned to type 'DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>'. Property 'test' does not exi ...

What are some ways to utilize tuples in TypeScript along with generics?

My mission is to create a type safe mapping object where I can define key/value pairs just once. I've managed to achieve this with the code below: const myPropTuple = [ [0, "cat"], [1, "dog"], [2, "bird"] ] a ...

What methods exist for creating visual representations of data from a table without relying on plotting libraries?

Is there a way to plot graphs directly from a Data Table without the need for external graph libraries like plotly or highcharts? Ideally, I am looking for a solution similar to ag-grid where the functionality comes built-in without requiring manual code ...

The click event triggered by the onclick clone/function may not always activate the click handler

As a newcomer in the JavaScript domain, I am encountering an issue where the first clone created after clicking 'add more' does not trigger my click me function. However, every subsequent clone works perfectly fine with it. What could be causing ...

Creating, editing, and deleting data in Ng2 smart table is a seamless process that can greatly enhance

While working on my Angular 2 project, I utilized [ng2 smart table]. My goal was to send an API request using the http.post() method. However, upon clicking the button to confirm the data, I encountered the following error in the console: ERROR TypeErro ...

Managing animations with multiple components in Angular 2+

I am currently developing an Angular application that will utilize a series of Modals in a wizard-style setup. For this project, I am utilizing the Angular-cli tool. Below is the code snippet showing how I have set up my animations: animations:[ t ...

Can a constant be utilized as the property name within routerLink when specifying queryParams?

I am currently trying to update the current page by modifying or adding the query parameter "categoryId". When I attempt: <a [routerLink]="" [queryParams]="{ categoryId: category!.id }" queryParamsHandling="mer ...

Illustrative demonstration of Vue with TypeScript

I am currently working on developing a HelloWorld application using Vue.js and TypeScript. index.html <script data-main="app.js" src="node_modules/requirejs/require.js"></script> <div id="app">{{text}}</div> app.ts import Vue f ...

Modifying the user interface (UI) through the storage of data in a class variable has proven to be

If I need to update my UI, I can directly pass the data like this: Using HTML Template <li *ngFor="let post of posts; let i = index;"> {{i+1}}) {{post.name}} <button (click)="editCategory(post)" class="btn btn-danger btn-sm">Edit</butto ...

Assign object properties to a constant variable while validating the values

When receiving the features object, I am assigning its values to constants based on their properties. const { featureCode, featureSubType, contentId, price, family: { relationCountsConfig: { motherCount, fatherCount, childrenCount }, max ...