Check your route if it's ok just dd(request()->all()) in store method to see what you send and if the store method is invoked or no.
successful post request in VUE to Laravel api, does not add record to database
In Vue I created a crud form to manage 'cards', containing title, description and image. Being new to Vue, combined with laravel, this is difficult for me.
I managed to add the file to the form data, appending them to a formData-object
The addition of cards worked fine, until I tried to add the image file to the formData. Sometimes it worked, then again it fails. I am doing something wrong with the Card model creation from the formdata reuqest. I do not see what however. been fooling around for hours now ...
I hope that someone can see at a glance what my ( probably silly) mistake is...
The Vue component that sends the requests:
<template>
<div>
<h2>Cards 1</h2>
<form @submit.prevent="addCard" class="mb-3">
<div class="form-group">
<input type="text" class="form-control" placeholder="title" v-model="card.title">
</div>
<div class="form-group">
<textarea class="form-control" placeholder="description" v-model="card.description">
</textarea>
</div>
<div>
<input type="file" v-on:change="onFileChange" id="file_picture_input">
</div>
<button type="submit" class="btn btn-primary btn-block" style="color:white">Save</button>
</form>
<div class="card card-body mb-2" v-for="card in cards" v-bind:key="card.id">
<h3> {{card.title}} </h3>
<p> {{card.description}}</p>
<img class="img-circle" style="width:150px" v-bind:src="card.picture" alt="Card Image">
<button @click="deleteCard(card.id)" class="btn btn-danger m-1" style="width:100px;color:white"> Delete </button>
<button @click="editCard(card)" class="btn btn-warning m-1" style="width:100px;color:black"> Edit </button>
</div>
</div>
</template>
<script>
export default {
mounted(){
console.log('component mounted')
},
data() {
return{
cards:[],
card:{
id:'',
title:'',
description:'',
},
card_id:'',
edit:false,
selectedFile:''
}
},
created(){
this.fetchCards();
},
methods: {
fetchCards(){
fetch('api/cards')
.then(res => res.json())
.then(res=>{
console.log(res);
this.cards = res;
})
},
deleteCard(id){
if(confirm('Are you sure?')){
fetch(`api/cards/${id}`, {
method: 'delete'
})
.then(res => res.json())
.then(data => {
alert('Card removed');
this.fetchCards();
} )
.catch(err => console.log(err));
}
},
addCard(){
// de informatie voor de card staat inthis.$card, nu omzetten naar FormData om file toe te voegen aan de request zodat api die kan opslaan, api gaat ook naam bedenken voor de card.
// via fetchCards() komt die naam dadelijk terug in card.picture
const formData = new FormData();
formData.append('title',this.card.title);
formData.append('description',this.card.description);
formData.append('picture',this.selectedFile);
console.log(formData.get('picture').name);
if(this.edit === false){
//add
fetch(`api/cards`, {
method: 'post',
body:formData,
headers:{
'content-type': 'multipart/form-data',
}
})
.then(res => console.log(res))
.then(data => {
this.card.title='';
this.card.description='';
alert('Card added');
this.fetchCards();
})
.catch(err => console.log(err));
} else{
//update
fetch(`api/cards/${this.card.card_id}`, {
method: 'put',
body:formData,
headers:{
'content-type': 'multipart/form-data',
}
})
.then(res => console.log(res))
.then(data => {
this.card.title='';
this.card.description='';
alert('Card updated');
this.fetchCards();
})
.catch(err => console.log(err));
}
},
editCard(card){
this.edit=true;
this.card.id=card.id;
this.card.card_id=card.id;
this.card.title=card.title;
this.card.description=card.description;
},
onFileChange(e){
this.selectedFile = e.target.files[0];
console.log(this.selectedFile);
}
}
}
</script>
The CardController script for the api:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Card;
use Intervention\Image\Facades\Image;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
class CardController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$cards = Card::all()->toArray();
//return $cards;
return array_reverse($cards);
//return Card::orderBy('created_at', 'desc')->paginate(2);
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//validate data first
$request->validate([
'description'=> 'required'
]);
$card = $request->all();
if ($request->hasFile('picture')){
// $this->validate($request, ['picture' => 'max:2000'], [__('Maximum file size of 2MB allowed')]);
$image_name = strval(time().Str::random(5)).'.png'; // voor de zekerheid string van maken..
$image = $request->file(); //file_picture_input is naam van file inputveld in het formulier, de naam die de request aan de file geeft
$path = storage_path('images'.$image_name);
$img = Image::make($image);
$img->resize(300, 300, function ($constraint) {
$constraint->aspectRatio();
})->save($path);
$card['picture'] = $path;
}
else {
$card['picture'] = 'img/profile/default_avatar.png';
}
//create a post
return Card::create($card);
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
return Card::find($id);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
$card = Card::find($id);
$card->update($request->all());
return $card;
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
return Card::destroy($id);
}
}
Console responses in browser show successful request, but no added or edited records. Delete works fine, index shows all existing records.
The response I see in the console from the fetch-post:
Response {type: "basic", url: "http://localhost:8000/", redirected: true, status: 200, ok: true, …}
body: (...)
bodyUsed: false
headers: Headers {}
ok: true
redirected: true
status: 200
statusText: "OK"
type: "basic"
url: "http://localhost:8000/"
[[Prototype]]: Response
I tested your code, I found it is only workable after removing these lines. Please remove these and try again.
headers: {
'Content-type': 'multipart/form-data'
}
Edit: Please check this : https://newbedev.com/fetch-missing-boundary-in-multipart-form-data-post
Please or to participate in this conversation.