What steps can be taken to eliminate redundancy in this code and improve its efficiency?

Here I have two methods, create and update, that send data to an API. I am looking to enhance the createUser and updateUser methods as they are very similar.

Additionally, if you have any suggestions on a better way to directly set the id property as nullable from the router and differentiate between editing and creating a client without using this.isAddMode.

export class ClientFormComponent implements OnInit {
  registerForm: FormGroup = new FormGroup({});
  isAddMode = false;
  constructor(
    private formBuilder: FormBuilder,
    private snackBar: MatSnackBar,
    private route: ActivatedRoute,
    private router: Router,
    private clientService: ClientService
  ) {}

  ngOnInit(): void {
    console.log(this.route.snapshot.params["id"]);
    this.isAddMode = !this.route.snapshot.params["id"];
    console.log(this.isAddMode);

    //  [...]

    if (!this.isAddMode) {
      this.clientService
        .getById(this.route.snapshot.params["id"])
        .pipe(first())
        .subscribe((x) => this.registerForm.patchValue(x));
    }
  }

  onSubmit(): void {
    // stop here if form is invalid
    if (this.registerForm.invalid) {
      return this.openSnackBar("Invalid form");
    }
    console.log(this.registerForm.value);
    if (this.isAddMode) {
      this.createUser();
    } else {
      this.updateUser();
    }
  }

  // [...]

  private createUser() {
    const data = {
      name: this.registerForm.value.name,
      organization: this.registerForm.value.organization,
      location: {
        address: this.registerForm.value.address,
        zipCode: this.registerForm.value.zipCode,
        city: this.registerForm.value.city,
      },
      contacts: {
        phone: "+33" + this.registerForm.value.phone,
        email: this.registerForm.value.email,
        site: this.registerForm.value.site,
      },
    };
    this.clientService
      .create(data)
      .pipe(first())
      .subscribe({
        next: () => {
          this.openSnackBar("Successfully added");
          this.router.navigate([""], {
            relativeTo: this.route,
          });
        },
        error: () => {
          this.openSnackBar("Invalid form");
        },
      });
  }

  private updateUser() {
    const data = {
      name: this.registerForm.value.name,
      organization: this.registerForm.value.organization,
      location: {
        address: this.registerForm.value.address,
        zipCode: this.registerForm.value.zipCode,
        city: this.registerForm.value.city,
      },
      contacts: {
        phone: "+33" + this.registerForm.value.phone,
        email: this.registerForm.value.email,
        site: this.registerForm.value.site,
      },
    };
    this.clientService
      .update(this.route.snapshot.params["id"], data)
      .pipe(first())
      .subscribe({
        next: () => {
          this.openSnackBar("Successfully updated");
          this.router.navigate([""], {
            relativeTo: this.route,
          });
        },
        error: () => {
          this.openSnackBar("Invalid form");
        },
      });
  }
}

Answer №1

Sure! It's possible to enhance its efficiency by extracting the addUser and updateUser methods into a dedicated service class, then invoking that service function within this context.

Answer №2

To improve the code, consider refactoring in this manner:
You can extract the form information gathering process and also place the pipe/subscribe method after the httpCall:

  private createUser() {
    const data = this.getDataFromForm();
    const httpCall$ = this.clientService
                          .create(data)
    this.subscribeToCreateUpdate(httpCall$, true);
  }

  private updateUser() {
    const data = this.getDataFromForm();
    const httpCall$ = this.clientService
                          .update(this.route.snapshot.params["id"], data);
    this.subscribeToCreateUpdate(httpCall$, false);
  }
  
  private getDataFromForm() {
    return {
      name: this.registerForm.value.name,
      organization: this.registerForm.value.organization,
      location: {
        address: this.registerForm.value.address,
        zipCode: this.registerForm.value.zipCode,
        city: this.registerForm.value.city,
      },
      contacts: {
        phone: "+33" + this.registerForm.value.phone,
        email: this.registerForm.value.email,
        site: this.registerForm.value.site,
      },
    };
  }
  
  private subscribeToCreateUpdate(httpCall: Observable<any>, isCreate: boolean) {
    httpCall
      .pipe(first()) // This line appears unnecessary as HTTP calls typically occur only once
      .subscribe({
        next: () => {
          const msg = "Successfully" + (isCreate ? "updated" : "updated")
          this.openSnackBar(msg);
          this.router.navigate([""], {
            relativeTo: this.route,
          });
        },
        error: () => {
          this.openSnackBar("Invalid Form");
        },
      });
  }

Answer №3

Ensure that your component focuses solely on the user interface, and move any logic to the service layer. This approach enhances the maintainability and testability of your code.

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

Resolve the problem in Angular 6 related to an unused type and the absence of a certain property

I recently watched a video tutorial (link: https://www.youtube.com/watch?v=z4JUm0Bq9AM) and encountered some errors in my CLI. The specific errors are as follows: ERROR in sidebar.component.ts(12,5): error TS7028: Unused label. sidebar.component.ts(14,56 ...

Exploring the nuances between Angular and Svelte in change detection mechanisms

In my daily work, I rely on Angular but also am taking the time to learn Svelte. As far as I know, neither Angular nor Svelte utilize a virtual dom and diffing process for change detection. Instead, they both have their own mechanisms for detecting chang ...

Access the Ionic2 App through the Slider option

Trying out Ionic 2 and facing an issue. Created a default side-menu app from CLI with a slider. Need to start the actual side-menu app from the last slide on button click or anchor link. My app.ts: @Component({ templateUrl: 'build/app.html' }) ...

Is there a way to remove a dynamically rendered component from a list?

Whenever I click a button, the same component is dynamically rendered on top of the list. But now, I need to implement a feature where users can delete any component from the list by clicking a cancel button associated with each component. Here's my ...

Error message: The element state is invalid. It must be editable by the user in order to be cleared. This error occurred while attempting to click and input a date on a dropdown

I'm facing an issue while trying to automate the insertion of a date in a calendar using selenium. The error message I received is as follows: invalid element state: Element must be user-editable in order to clear it. Here's the relevant HT ...

The use of findDOMNode has been marked as outdated in StrictMode. Specifically, findDOMNode was utilized with an instance of Transition (generated by MUI Backdrop) that is contained

I encountered the following alert: Alert: detectDOMNode is now outdated in StrictMode. detectDOMNode was given an instance of Transition which resides within StrictMode. Instead, attach a ref directly to the element you wish to reference. Get more inform ...

The significance of zone.js and rxjs within the context of Angular 2

As a newcomer to Angular2, I recently learned about zone.js and rxjs. I'm curious to know if they both serve the same purpose for handling asynchronous tasks, or if each has its own specific role. Can someone explain to me the exact reasons why zone.j ...

Utilizing Enum Lowercase as Index Key Type in TypeScript

Is there a way in TypeScript to use the lower case of an enum as an index key type? I have an enum defined as: export enum NameSet { Taxi = 'Taxi', Bus = 'Bus', Empty = '', } I want to define an object with keys based o ...

The error "UncaughtReferenceError __decorate is not defined" occurs when trying to run Angular2 with

When attempting to transition a functional Angular2 Typescript app to webpack, a runtime error is encountered: app.js:38016Uncaught ReferenceError: __decorate is not defined The problematic code snippet causing the issue is as follows: NpnPortalService ...

Setting limits to disable or remove specific times from the time picker input box in Angular

I'm having trouble with a time input box. <input type="time" min="09:00" max="18:00" \> Even though I have set the min and max attributes to values of 09:00 and 18:00 respectively, it doesn't seem to be working properly. I want to ...

Passing a type as an argument in Typescript

How can I pass a type as a parameter in Typescript? type myType = {} const passingType = (t: Type) => { const x : t = {} } passingType(myType); I keep receiving TypeScript errors. 't' is referencing a value, but it is being used as a t ...

Node.js and mongoose provide a powerful tool for filtering documents dynamically by leveraging a variable that is dependent on another document. Want to learn

I've hit a bit of a roadblock here... I'm trying to add a new property to a document that will change based on the values in that document as well as another document. Let me provide an example to clarify. First, I have a Candidate Schema: const ...

What is the best way to optimize a search for objects with extensive field arrays?

Recently, I've been working with an object schema that includes an array field to store ids for objects from a separate collection. This array has the potential to contain thousands of ids. Up until now, I have been excluding this field using .select( ...

Encountering unexpected null values post-service invocation in Angular 2

I have encountered an issue in Angular 2 where a variable is returning undefined. The problem arises when a function calls a service to initialize a variable, which is then used in another function to make a get HTTP request. However, the get request fails ...

Inquired about the installation of Typescript in the Docker image building process despite it already being installed

I am in the process of creating a docker image for a Next.js/React application that utilizes Typescript. Typescript is installed and I can successfully generate a local build without docker. However, during the docker image creation, I encounter the foll ...

Unit testing in Angular 2+ involves testing a directive that has been provided with an injected window object

Currently, I am faced with the challenge of creating a test for a directive that requires a window object to be passed into its constructor. This is the code snippet for the directive: import { Directive, ElementRef, Input, OnChanges, OnDestroy, OnInit ...

Error message "Cannot find children property on type IntrinsicAttributes & RefAttributes<unknown>" occurring in a React component due to a Typescript issue

Issue: The specified type '{ children: string; severity: string; sx: { width: string; }; }' is not compatible with the type 'IntrinsicAttributes & RefAttributes'. The property 'children' is missing in the type 'Intri ...

Ways to update a component upon becoming visible in Angular

Within my Angular 4.3.0 project, the header, left panel, and right panels are initially hidden on the login page until a successful login occurs. However, once they become visible, the data is not pre-loaded properly causing errors due to the ngOnInit meth ...

How to manually implement a scrollspy feature in Angular

I am facing an issue with implementing scrollspy inside a MatDialog. The event activate.bs.scrollspy doesn't appear to be triggering as expected. It seems like it might be firing at a window level and not highlighting the anchors on my navbar as I scr ...

Angular 9 TestBed RouterTestingModule: Exploring the router.url Readonly Property

While transitioning from Angular 8 to Angular 10 in stages, I encountered an issue when upgrading to version 9. All of my TestBed.get(Router).url calls started throwing errors because the property had become read-only. For instance, the code TestBed.get(R ...