skip to Main Content

I am sending data from ionic project using api. And receiving from laravel. My "Add" product api is working fine. But "Update" product api is not working.

I can see from browser inspection tool that Request payload got data which is being send to laravel. So, data is being send but laravel is not able to real that data.

This is update function for api.

public function update(Request $request, Product $product)
{

// Validate request
$validatedData = $request->validate([
    'account_type' => 'required|in:1,2',
    'name' => 'required|string|max:255',
    'description' => 'nullable|string',
    'price' => 'required|numeric|min:0'
]);

// Update product
$product->update($validatedData);

return response()->json($product);
}

This is giving following error

account_type    [ "The account type field is required." ]
name    [ "The name field is required." ]
price   [ "The price field is required." ]
and so on..

Laravel unable to read data for some reason.

Update

<form [formGroup]="productForm" (ngSubmit)="onSubmit()">
<!-- Add Type -->
<ion-item>
  <ion-label>Add Type <span class="required">*</span></ion-label>
  <ion-radio-group formControlName="account_type">
    <ion-item>
      <ion-label>Individual</ion-label>
      <ion-radio slot="start" value="1"></ion-radio>
    </ion-item>
    <ion-item>
      <ion-label>Business</ion-label>
      <ion-radio slot="start" value="2"></ion-radio>
    </ion-item>
  </ion-radio-group>
</ion-item>

<!-- Ad Title -->
<ion-item>
  <ion-label position="floating">Ad Title <span class="required">*</span></ion-label>
  <ion-input formControlName="name" type="text"></ion-input>
</ion-item>
<!-- Submit Buttons -->
<div class="ion-padding">
  <ion-button type="submit" expand="block" [disabled]="productForm.invalid">
    {{ isEditMode ? 'Update Product' : 'Submit Now!' }}
  </ion-button>
  <ion-button expand="block" color="light">Preview</ion-button>
</div>

Didn’t add all field of form here to make it short.

TS FILE

onSubmit() {
if (this.productForm.valid) {
  const formData = new FormData();
  const formValues = this.productForm.value;

  // Append all form data
  Object.keys(formValues).forEach((key) => {
    if (key !== 'image' && key !== 'additionalImages') {
      formData.append(key, formValues[key]);
    }
  });

  // Handle file inputs
  const mainImage = document.querySelector('[formControlName="image"]') as HTMLInputElement;
  if (mainImage && mainImage.files && mainImage.files[0]) {
    formData.append('image', mainImage.files[0]);
  }

  const additionalImages = document.querySelector('[formControlName="additionalImages"]') as HTMLInputElement;
  if (additionalImages && additionalImages.files) {
    Array.from(additionalImages.files).forEach((file) => {
      formData.append('additionalImages[]', file);
    });
  }

  // Differentiate between add and update
  if (this.isEditMode) {
    const productId = Number(this.route.snapshot.paramMap.get('productId'));
    this.productService.updateProductPost(productId, formData).subscribe(
      (response) => {
        console.log('Product updated successfully:', response);
        this.router.navigate(['/success']);
      },
      (error) => {
        console.error('Error updating product:', error);
      }
    );
  } else {
      // Get the query string parameter
    const categoryId = this.route.snapshot.paramMap.get('categoryId'); // Extract categoryId from query string
    console.log('Category ID:', categoryId);

    // Get the sessionStorage value
    const userId = sessionStorage.getItem('userId'); // Extract userId from sessionStorage

    // Append query string and sessionStorage data to the formData
    if (categoryId) {
      formData.append('category_id', Number(categoryId).toString());
    }
    if (userId) {
      formData.append('seller_id', Number(userId).toString());
    }

    this.productService.addProduct(formData).subscribe(
      (response) => {
        console.log('Product added successfully:', response);
        this.router.navigate(['/success']);
      },
      (error) => {
        console.error('Error adding product:', error);
      }
    );
  }
} else {
  console.error('Form is invalid');
}
}

PRODUCT.SERVICE.TS

//Add product (is working)
addProduct(product: FormData): Observable<Product> {
  return this.http.post<Product>(`${this.apiUrl}/products`, product);
}

//update producd
updateProductPost(productId: number, product: FormData): Observable<Product> {
  return this.http.put<Product>(`${this.apiUrl}/products-update/${productId}`, product);
}

Laravel route in api.php

Route::put('products-update/{id}', [ProductApi::class, 'update']);

2

Answers


  1. This is the case of incorrectly defined implicit model-binding.
    When you use implicit model-binding you need to use the same name for the Route parameter and for the injected model instance into the controller method(in your case update(Request $request, Product $product)).

    So change you route defination like this.

    Route::put('products-update/{product}', [ProductApi::class, 'update']);
    

    N:B :-

    1. In laravel part this is the issue that causes the error for sure. But in the frontend part I am not able to suggest you anything even if there is any issue since I am not familiar with the angular at all.
    2. Make the above changes and recheck.
    3. Also go through the above link that I have provided where you will get the more details about the implicit model-binding.
    Login or Signup to reply.
  2. The http method PUT doesnt necessarily carry a body by RFC standards.
    Library like axios or even servers like apache can completely ignore processing the body in a put request.

    there are 2 workarounds:

    1- Use POST for updates too:

    As you can see, the 2 url structure are different from insert and update since one needs an id, so you can use post to update too

    Route::post('product', [ProductApi::class, 'store']);
    Route::post('product/{id}', [ProductApi::class, 'update']);
    

    2- Use POST with the input _method:

    In laravel you can send a POST request and have it treated like a PUT one if it has the input _method=PUT.

    PRODUCT.SERVICE.TS

    //update producd
    updateProductPost(productId: number, product: FormData): Observable<Product> {
      product.append('_method','PUT');
      return this.http.post<Product>(`${this.apiUrl}/products-update/${productId}`, product);
    }
    

    Any of the two solutions would work for your case.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search