Utilizing the adapter design pattern in Angular with TypeScript for enhancing a reactive form implementation

I've been struggling to understand how to implement the adapter pattern in Angular6. Despite reading numerous articles and tutorials, I still can't quite grasp the concept. Could someone provide some insights on this topic? Essentially, I have a service that fetches data which needs to be used in a component with a different model. I need to modify it before sending it back to the service in the correct format. My main question is whether we should create an interface to manage HTTP calls. If so, how do we store and utilize the data in my adapter class considering that the resources I consulted emphasize keeping data models and view models separate?

Below is a JSON object returned from the server (assets/mocks/quote.json)

{
    "quote": {
        "quoteId": 123,
        "commenseDate": "12/15/2018",
        "quoteType": "Small",
        "count": 10,
        "customerInfo": {
            "customerName": "ABC",
            "address": "xxxx xxx xxx",
            "city": "Philadelphia",
            "state": "Philadelphia ",
            "zip": "xxxxx",
            "county": "PA",
            "phone": "",
            "eligibles": 2,
            "employeeCount": 2
        }

    }
}

I'm unsure about using models and interfaces when connecting to a web service. After consulting the Angular docs, I learned that using interfaces for our data models is essential when connecting to a web service. Therefore, I created an interface to handle my data model.

export interface Quote{
    quoteId: number;
    commenseDate: string;
    count: number;
    quoteType: string;
    customerInfo: CustomerInfo
}
export interface CustomerInfo {
    customerName: string;
    address: string;
    city: string;
    state: string;
    zip: number;
    county: string;
    phone: number;
    eligibles: number;
    employeeCount: number;
}

In my service call, I utilized this interface. Below is my quote-search-service.ts file:

export class QuoteSearchListService {

/* ApiService- is just a wrapper class to hold the http logic. This class imports HttpClient and uses its get
  * and post methods
*/
  constructor(private apiService:ApiService) { }

  /** Get a quote item */
  getQuoteItem(quoteId:number):Observable<Quote>{

    return this.apiService.get<Quote>('assets/mocks/quote.json')
    .pipe(map((data) => data));
  }
}

I'm utilizing a reactive form in my component along with the following form model:

export class QuoteComponent implements OnInit {

    private form: FormGroup;

    constructor(private router: Router, private fb: FormBuilder, private quoteService: QuoteSearchListService) {
        this.form = this.fb.group({
            customerName: [null, Validators.required]
            address: this.fb.group({
                `enter code here`
                address1: ['', Validators.required],
                address2: ['']
            })
            addressDetails: this.fb.group({
                state: [null, Validators.required],
                city: [null, Validators.required],
                zip: [null, Validators.required]
            }),
            county: [''],
            phone: ['', [Validators.required, Validators.minLength(10)],

            contact: this.fb.group({
                contactFirstName: [null, Validators.required],
                contactLastName: [null, Validators.required],
            }),
            eligibles: [null, Validators.required],
            empCount: [null, Validators.required],
            fteCount: [null, Validators.required]
        })

    }

    ngOnInit() {
        this.getQuoteItem(this.quoteId);
    }

    getQuoteItem() {
        this.quoteService.getQuoteItem(quoteId).subscribe(response => {
            this.form.setValue(response.quote);
        })
    }

}

Here are my specific questions:

  1. How can I incorporate the adapter pattern in this scenario to maintain independence between my data model and form model?
  2. Do I need to create additional models/classes specifically for my component apart from the form model? For instance, 'addressDetails' differs from the data model.
  3. How should the conversion from data-model to form-model (for GET calls) and vice versa (for POST/PUT calls) be handled? Should I develop a separate service to facilitate this model transformation?

Resources I've consulted:

When to use Interface and Model in TypeScript / Angular2

Answer №1

When it comes to Javascript, there are no typings involved. Variables in Javascript are dynamically typed based on the value they receive or the operations performed on them.

However, in Typescript, you have the option to explicitly type your variables. Keep in mind that once the code is compiled, these types are stripped away. They mainly serve as a way to enforce behavior during pre-compilation and assist with intellisense.

Addressing your query:

1 - The form model should align with the data model. If you intend to modify and send back information, their structures should match. You can choose between template-driven forms (dependent on your model) and reactive forms (based on your implementation), with the former being more suitable in this scenario.

2 - If the payload sent and received have similar models, there's no need for separate classes or interfaces specific to the form. It is advisable to keep the models aligned in such cases.

3 - The process should be seamless without requiring any additional steps on your part.

Answer №2

From my perspective, the form-model and data-model are fundamentally different. Therefore, it is necessary to convert between the form-model and data-model as needed.

Where should this conversion take place? For simple and common values, I find it convenient to use a service. For example, when we receive a date in String format and need to convert it to a Date Object, or when we receive a string with city names separated by "|" and want to convert it to an array.

service.getList().pipe(map(list=>{
   list.forEach(item=>
      {
        item.date=new Date(item.date); //now "date" is a Date Object
        item.cities=item.cities.split('|');  //now cities is an array of Strings
   }))

In this way, our saveData function within the service will look like:

saveData(data)
{
     data.date=data.date.getFullYear()+"-"+
            ("0"+(data.date.getMonth()+1)).slice(-2)+"-"+
            "0"+(data.date.getDate()).slice(-2)
     data.cities=data.cities.join("|");
     this.httpClient.post("....",data)
}

However, for more complex conversions, I would prefer to handle them within the component itself.

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

Disabling an anchor using the 'disabled' property is proving to be a challenge for me

I'm attempting to dynamically enable or disable an anchor element based on the user's role. So far, I've tried a few different methods: document.getElementById('myBtn').disabled = true; However, this returns an error: The propert ...

Raycaster in Three.js fails to recognize clicks on objects

Having trouble detecting clicks on Three.js objects using a raycaster in Angular? Here's the code I'm working with: @Component({ selector: 'app-viewer-3d', templateUrl: './viewer3d.component.html', styleUrls: ['./vi ...

Are MobX Observables interconnected with RxJS ones in any way?

Is the usage of RxJs observables in Angular comparable to that in React and MobX? I'm struggling to find information on this topic. ...

Ways to adjust the ngx-pagination color scheme?

I am looking to customize the background color of ngx-pagination Here is my current code: <pagination-controls class="custom-pagination" id="indicadorPaginationResults" (pageChange)="p=$event" maxSize="9" directionLinks="true" autoHide="true" previ ...

How can I display JSON values without revealing the parent in Angular 5 and Ionic 3?

I am trying to extract values from JSON without the parent keys. Here is the JSON structure I have: [ { "companies": [{ "id": 1, "name": "Prueba", "company_number": "23423423A", "latitude": 241241.12, "lo ...

What is the correct way to define types for higher-order class components in TypeScript?

I have developed a utility function that currently has an unused options parameter, and it returns a higher-order component wrapping function. How can I effectively define types on the component so that users of the wrapped component can visualize the typ ...

The child user interface component is failing to respond to keypress events within the parent component in an Angular project

I am facing a challenge in adding a keyboard shortcut to open a nested child UI Tab component through a keypress event. However, the Child nested tab can only be loaded after the Parent component is loaded first. Below is the structure of the UI tree: |-- ...

Trigger a class method in an event using Angular with Typescript

I am completely new to TypeScript and Angular, and I am attempting to create a basic drawing component on a canvas. However, I have reached a point where I feel lost and confused about my code. The concept of "this" in TypeScript has been a major stumbling ...

Accessing object properties on the fly in TypeScript

I'm currently working on a TypeScript game that features an inventory system with various values, like so: export const Inventory = { food: 0, medicine: 0, rifleAmmo: 0, pistolAmmo: 0 } At the moment, I have a function in place to man ...

Angular routing is showing an undefined ID from the snapshot

When a user attempts to update a student, I pass in the student ID. The update successfully redirects to the updateStudent page and displays the student ID in the browser link. However, within my app component, it shows as undefined. Student View componen ...

Working with Typescript: Defining the return type of a function that extracts a subset of an object

Currently, I am attempting to create a function that will return a subset of an object's properties. However, I’m facing some issues with my code and I can't pinpoint the problem. const initialState = { count: 0, mounted: false, } type St ...

Transforming two child arrays within an object into a single array using Ramda

I am looking to transform an object into an array. The object I have is structured like this: const data = { t1: [ {"a": 1, "a1": 2}, {"b": 3, "b1": 4}, {"c": 5, "c1": 6} ], t2: [ {" ...

Angular4 and jQuery working together for effective navigation and pagination

Trying to implement pagination in angular 4 and jQuery, but encountering an issue where clicking on the next button causes it to skip through multiple pages at once (2, then 3, then 5)... Component code: addClass(x) { $(".page-item").click(function () ...

Can you clarify the meaning of "int" in this code snippet?

What does the ?: and <I extends any[] = any[]> signify in this context, and how is it utilized? export interface QueryConfig<I extends any[] = any[]> { name?: string; text: string; values?: I; types?: CustomTypesConfig; } ...

Looking to categorize and sum the values within an array of objects using JavaScript?

I'm looking to optimize this response data within my Angular application. res=[ { "url": "/page1", "views": 2 }, { "url": "/page2", "views": 1 }, { "url": "/page1", "views": 10 }, { "url": "/page2", "views": 4 }, { "url": "/page3", "views": 1 }, ...

Encountered an unhandled promise rejection: TypeError - The Form is undefined in Angular 6 error

Whenever I attempt to call one .ts file from another using .Form, I encounter the following error: Uncaught (in promise): TypeError: this.Form is undefined The file that contains the error has imported the .ts file which I intend to pass values to. ...

TS7030: In Angular13, ensure that all code paths within the guard and canActivate methods return a value

Having trouble using guards for an unlogged user and constantly facing errors. Error: TS7030 - Not all code paths return a value. Below is my auth.guard.ts file: import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree} from &a ...

Remove the user along with all of their associated documents from Firestore

When a user wants to delete their account, I need to ensure that the 'documents' they created in Firebase are deleted as well. After some research online, I came across the following code snippet: deleteAccount() { const qry: firebase. ...

Bringing in a feature within the Vue 3 setup

At the moment, I am attempting to utilize a throttle/debounce function within my Vue component. However, each time it is invoked, an error of Uncaught TypeError: functionTD is not a function is thrown. Below is the code snippet: useThrottleDebounce.ts imp ...

Splitting Angular Components with Angular as-split

Having trouble adding a "title" to my angular as-split-area. The titles are appearing together rather than above the as-split-area. <div style="width: 800px; height: 400px; background: yellow;"> <as-split direction="vertical&q ...