3

How should I write the PATCH method that allows me to add and remove items of an array inside an array?

ItemClass:

export class ItemClass {
constructor(public person: string, public name: string, public quantity: number, public price: number){}
}

MenuModel:

    import { ItemClass } from './item.model';

    export class MenuModel {


    id: number;
    name: string;
    items: ItemClass[];

    constructor( id: number,  name: string, items: ItemClass[]){

         this.id = id;
         this.name = name;
         this.items = items;
    }
}

I have a menu component and a menu service. I need a patch method that adds elements to the ItemClass[] array inside Menu and is able to remove them as well.

The API method looks like :

   @PATCH
   @Path("/add/{menuId}")
   public void removeMenuItem(
            @PathParam("menuId") final int menuId,
            final Item item) {  // Item represents the Request Body
      final List<Item> items = this.menuRepository.get(menuId).getItems();
      items.add(item);
   }

(from https://stackoverflow.com/a/54679303/479251)

Pac0
  • 21,465
  • 8
  • 65
  • 74
soulzap
  • 69
  • 1
  • 1
  • 7
  • Not clear to me what you're asking – Prashant Pimpale Feb 14 '19 at 07:09
  • I need a PATCH API method that can add and remove elements of the ItemClass[] array, which is a parameter of the Menu. – soulzap Feb 14 '19 at 07:11
  • 1
    I think you need to go back to the person who instructed you to do this, and ask for some more explanation. – Davy Feb 14 '19 at 07:27
  • I should probably provide more data. It's already a big code base, i've got tons of things working (GET, POST, DELETE requests) I've got more classes but they aren't relevant to this. – soulzap Feb 14 '19 at 07:34
  • An array is an array everywhere. The only you need is check if is null before use push, or slice, e.g. if (!mymenu.items) {mymenu.items=[]} – Eliseo Feb 14 '19 at 07:35
  • Why is everyone confused by this? I thought it was just me because i don't have experience – soulzap Feb 14 '19 at 07:35
  • Are you asking how to manipulate arrays in JavaScript? – zmag Feb 14 '19 at 07:54
  • I'm more confused about the PATCH method itself. I see how POST and GET are working, but I just can't grasp the PATCH concept. It's kinda new and I can't find any examples that would help me. I just need to get it right once, so I know how to use it in the future, as this is my very first Angular project. – soulzap Feb 14 '19 at 07:57
  • @soulzap PATCH, as well as GET, POST, PUT etc... are HTTP methods to communicate with your server. Basically, there isn't anything "special" except that the HTTP packet will be named "PATCH" instead of "POST" or "PUT". How to *treat* these messages by the backend is not something Angular should be concerned. Angular is (I suppose), your *cleint* application. What you would (maybe) need from Angular is to *send* a PATCH request, if and only if your backend API understands it. Some API are designed to make use of PATCH, some may choose to use PUT instead, there some room for choice. – Pac0 Feb 14 '19 at 08:31
  • I get that, I've resolved the back-end issue (almost) with the help of good people here. I've got the code for the back-end, i'm just facing some issues on the front, hence why I asked for help here. – soulzap Feb 14 '19 at 08:39
  • What you will send exactly depends on what your API expects. Without more info about that, I can just say that you can use the `patch()` method from `HttpClient`, exactly like you would use the `post()` or `put()` method. : `import {HttpClient} from '@angular/common/http'; /* ... */ constructor(private http: HttpClient) {} /* ...*/ public sendPatch() { this.http.patch('url', 'body of the patch request').subscribe(res => { console.log('received response from patch request'))` – Pac0 Feb 14 '19 at 08:43
  • @Pac0 here's the backend issue I had, with the solution in the comments. That's the patch method I'm using. https://stackoverflow.com/questions/54678946/removing-a-specific-element-of-a-list-which-is-an-element-of-another-list-using/54679303?noredirect=1#comment96159744_54679303 – soulzap Feb 14 '19 at 08:48
  • @soulzap, ok , I edited your question with the `add` patch method from the answer in the linked method. I'll see if I can write an answer now, but not sure – Pac0 Feb 14 '19 at 08:53
  • @Pac0 alright, thanks man – soulzap Feb 14 '19 at 09:02

1 Answers1

4

After the additional details on the backend's patch method, here's a (crude) example of how you could do it.

You haven't specified a version for Angular, so I will suppose you are using last version (7), and HttpClient .

import { HttpClient } from '@angular/common/http'; 
/* ... */ 
export class YourComponentOrService {

  // note : you will need to add HttpClientModule to the application module 'imports' and 'providers' sections
  constructor(private http: HttpClient) {} 

  /* ...*/ 

  // call this method when you want to add an item
  public addItem(menuID: number, itemToAdd: ItemClass): void { 
    console.log('sending patch request to add an item');

    this.http.patch(`example.com/add/{menuId}`, itemToAdd).subscribe(
      res => { 
        console.log('received ok response from patch request');
      },
      error => {
        console.error('There was an error during the request');
        console.log(error);
      });

    console.log('request sent. Waiting for response...');

  }

  // as I could see on the linked Q&A, the delete method will be very similar
  // only the url will use 'remove' instead of 'add', along with the item name, and no body.

  /* .... */
}     

Of course, this is the basic "Proof of concept" to get you started, to adapt to your need and the overall architecture of your Angular app.

As you can see, all I did was read the API endpoints, and use the patch method from the HttpClient Angular service accordingly, with the expected url and content.

Now, you have to add the logic to send the request with the correct parameters.

Pac0
  • 21,465
  • 8
  • 65
  • 74
  • alright, I'll try that one out. What should my menu component method look like? The one that i'll bind to the (click)? Thanks for this, I'll try it out as soon as i get the answer about the final method for the component. Yes, I'm using the latest version. – soulzap Feb 14 '19 at 09:10
  • @soulzap I don't really know how to answer this, I don't how what your page is suppose to look like, what is the behavior, etc... That depends on your specifications. Basically, you should have a method that, when clicked, create / read the 'item' object to add, and call the method I wrote above. Also, you may want to refresh the list of displayed item once the request is ended. – Pac0 Feb 14 '19 at 09:12
  • maybe you can use [StackBlitz](https://stackblitz.com) to create something that looks like to what you want to do – Pac0 Feb 14 '19 at 09:16
  • i simply need to create a function that's going to activate whenever a button is clicked. The function implements the PATCH method. Hopefully you understand what I'm trying to say. For example, this is my getMenu GET method: getMenu(id: number): Observable{ const url = `${this.menusUrl}/${id}`; return this.http.get(url) } ____ getMenu(): void { const id = +this.route.snapshot.paramMap.get('id'); this.menuService.getMenu(id) .subscribe(menu => this.menu = menu); } _____ The latter is the function for the button click event. – soulzap Feb 14 '19 at 09:20
  • ok, then you can put my above `addItem` method in the same class, and make it *return* the `http.patch` result (instead of subscribing directly). That would be the equivalent of your `getMenu(id: number)` method – Pac0 Feb 14 '19 at 09:27
  • here's what I did: patchIt(item: ItemClass): void { const id = +this.route.snapshot.paramMap.get('id'); this.menuService.patchRemove(id, item) .subscribe(item => this.item = item); } and this in service: patchRemove(menu: MenuModel | number, itemToAdd: ItemClass): Observable { const name = typeof menu === 'string' ? menu: itemToAdd.name; const id = typeof menu === 'number' ? menu: menu.id; const url = `${this.menusUrl}/remove/${id}/${name}`; return this.http.patch(url, itemToAdd).pipe () } Seems to be working, but im having CORS issue – soulzap Feb 14 '19 at 09:30
  • Then, you can create another method, equivalent to `getMenu()`, that will read whatever value of your component from a textbox or anything you want, call the above method with the correct parameters and subsrcribe to the result. In the suscribe callback, refresh the list by reading it again (call your getMenu), yo you can see if it refreshes. – Pac0 Feb 14 '19 at 09:30
  • Access to XMLHttpRequest at 'http://localhost:8080/menu/remove/1/Item%201' from origin 'http://localhost:4200' has been blocked by CORS policy: Method PATCH is not allowed by Access-Control-Allow-Methods in preflight response. It's doing exactly what I wanted it to do, except that CORS is screwing with me. I have the CORS extension, and get/post are working without any problems. – soulzap Feb 14 '19 at 09:31
  • Maybe there is some configuration you need to add to your server to make PATCH requests allowed. I think this is a server issue, not related to Angular. – Pac0 Feb 14 '19 at 09:34
  • you can have a look here : https://stackoverflow.com/a/47933410/479251, maybe it will help solve your CORS issue. – Pac0 Feb 14 '19 at 09:38
  • maybe your server expect some headers to the request. – Pac0 Feb 14 '19 at 09:39
  • omg, it freaking works! Should I create a separate PATCH request on the front-end for adding? I guess that's the way to go. – soulzap Feb 14 '19 at 09:45
  • @soulzap, yes, I think so too. How did you solve your CORS issue, out of curiosity ? Was it just some issue with code, or with server configuration ? – Pac0 Feb 14 '19 at 09:49
  • 1
    google-chrome --disable-web-security --user-data-dir launching the chrome that way, solved it. It's for development purposes only so that's good enough for me. Thanks for everything man! – soulzap Feb 14 '19 at 09:50
  • patchItAdd(person: string, name: string, quantity: number, price: number){ name = name.trim(); if (!name) {return;} const id = +this.route.snapshot.paramMap.get('id'); this.menuService.patchAdd(id, {person, name, quantity, price} as ItemClass) .subscribe(item => { this.items.push(item); }); } ____ patchAdd(menu: MenuModel | number, itemToAdd: ItemClass): Observable { const id = typeof menu === 'number' ? menu: menu.id; const url = `${this.menusUrl}/add/${id}`; return this.http.patch(url, itemToAdd).pipe () } – soulzap Feb 14 '19 at 11:33
  • any idea why i'm getting this error: PATCH http://localhost:8080/menu/add/0 500 (Internal Server Error) – soulzap Feb 14 '19 at 11:33
  • this is your backend that had some error during execution. You need to debug your backend, check that the parameters are correct, check the request etc... – Pac0 Feb 14 '19 at 12:27
  • hey buddy, would you mind taking look at this new issue i've stumbled upon? https://stackoverflow.com/questions/54738121/elements-passed-through-a-form-not-received-by-the-server-nor-displayed-on-the-f – soulzap Feb 17 '19 at 22:17