Reputation: 1439
I have an angular service that gets values from an http get, and then maps the values to an Observable of a specific object type as it returns. Sometimes the value of one of the properties is a string, and sometimes it is a null value that I want to set to a default empty string.
Is there a more elegant way to do this than what I have?
I have tried passing in a boolean value for the specific field that is of interest to me, the template.AreaId attribute, but I am concerned as more attributes may have this issue over time as there are more template objects created.
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.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); })
)
}
}
This works, but I would prefer to have a way to better handle situations where a field is null, or does not have a string value.
Here is what I had before I had an issue with the template.AreaId value being null.
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.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); })
)
}
Upvotes: 0
Views: 3508
Reputation: 3664
Expanding out from my comment, my suggestion about using the ternary operator would look like the following:
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,
// Just use a ternary to prevent the `toString()` call if the property
// does not exist on the template
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); })
)
}
Also expanding on what I said about the potential to dynamically map properties (i.e. to avoid explicitly specifying the mapping of each property in involved), a demonstration of a possible solution might look like the following:
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 => {
// Merges properties the acquired template with those in the base task
// with the properties in the template taking precedence
return Object.assign({}, baseTask, template);
}),
);
}
// Stub implementation that just returns a fixed template
function getTemplateByName(extraChildTask) {
return of({
Title: 'Title',
Description: 'Description',
TeamProjectName: 'Team Project Name',
AreaPathId: 'Area Path ID',
// ...
});
}
// Example usage in action
getTaskFromTemplate('something').subscribe(task => {
console.log(task);
});
<script src="https://unpkg.com/[email protected]/bundles/rxjs.umd.min.js"></script>
As I noted, if some task property names don't match names from the template you need to map from, this can be solved by setting up some additional mapping steps.
Upvotes: 1