0
votes

i'm working on an laravel vuejs spa. I try to update a post from the admin. I send the form datas on creating a new FromData who are sending with and axios request.

But the controller send me the error:

message: "The given data was invalid."
errors: {name: ["The name field is required."], description: ["The description field is required."]}
  • Here is the post/edit.vue
<template>
  <div class="post-edit">
    <form id="form" @submit.prevent="createPost">
      <!-- Title -->
      <div class="form-group">
        <label for="title" class="form-label">Title</label>
        <input id="title" v-model="post.title" :title="post.title" type="text"
               name="title" class="form-control"
        >
      </div>

      <!-- Category -->
      <div class="form-group">
        <label for="category" class="form-label">Category</label>
        <select id="category" v-model="post.category" :value="post.category" :category="post.category"
                name="category" class="form-control"
        >
          <option disabled :value="post.category">
            Choisir une catégorie
          </option>
          <option v-for="(category) in categories" :key="category.id" :value="post.category">
            {{ category.name }}
          </option>
        </select>
      </div>

      <div class="post-edit-image">
        <img :src="path + post.image" alt="">
      </div>

      <!-- Image -->
      <div class="form-group post-edit-select-image">
        <label for="content" class="form-label">Image</label>
        <input type="file" name="image" class="form-control" @change="selectedImage">
      </div>

      <!-- Content -->
      <div class="form-group">
        <label for="content" class="form-label">Content</label>
        <editor
          id="content"
          v-model="post.content"
          api-key="the-api-key"
          :init="{
            height: 500,
            menubar: false,
            plugins: [
              'advlist autolink lists link image charmap print preview anchor',
              'searchreplace visualblocks code fullscreen',
              'insertdatetime media table paste code help wordcount'
            ],
            toolbar:
              'undo redo | formatselect | bold italic backcolor | \
               alignleft aligncenter alignright alignjustify | \
               bullist numlist outdent indent | removeformat | help'
          }"
          name="content"
          :content="post.content"
        />
      </div>

      <!-- Submit Button -->
      <button type="submit" class="btn btn-primary">
        Sauvegarder
      </button>
    </form>
  </div>
</template>

<script>
import axios from 'axios'
import { mapGetters } from 'vuex'
import Editor from '@tinymce/tinymce-vue'

export default {
  middleware: 'auth',

  components: {
    'editor': Editor
  },

  props: ['id'],

  data () {
    return {
      post: {
        id: '',
        user_id: '',
        title: '',
        category: '',
        image: null,
        content: ''
      },
      path: '/images/post/thumbnail/'
    }
  },

  computed: {
    ...mapGetters({
      user: 'auth/user',
      categories: 'categories/categories'
    })
  },

  beforeCreate () {
    this.$store.dispatch('categories/fetchCategories')
  },

  created () {
    this.getPostById(this.$route.params.id)
  },

  methods: {
    selectedImage (event) {
      this.post.image = event.target.files[0]
    },

    getPostById (id) {
      axios.get('/api/posts/edit/' + id)
        .then((response) => {
          this.post.id = response.data.id
          this.post.user_id = response.data.user_id
          this.post.title = response.data.title
          this.post.category = response.data.category
          this.post.image = response.data.image
          this.post.content = response.data.content
        })
        .catch((error) => {
          console.log(error)
        })
    },
    createPost (e) {
      this.post.userId = this.user.id
      let formData = new FormData(e.target)
      let id = this.post.id

      formData.append('title', this.post.title)
      formData.append('category', this.post.category)
      formData.append('image', this.post.image)
      formData.append('content', this.post.content)

      axios.patch('/api/posts/update/' + id, formData, {
        headers: {
          'Content-Type': 'multipart/form-data'
        }
      })
        .then((response) => {
          console.log(response)
          this.$store.dispatch('posts/fetchPosts')
        })
        .catch((error) => {
          console.log(error)
        })

      this.$router.push({ name: 'admin' })
    }
  }
}
</script>
  • And here the laravel controller PostController@update method
    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(PostUpdateRequest $request, $id)
    {
        $post = Post::findOrFail($id);
        $post->update($request->getValidRequest());
        return response()->json($request, 200);
    }
  • And the custom validator PostUpdateRequest.php
/**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'title' => 'required|max:250|unique:posts,title',
            'category' => 'required',
            'image' => 'mimes:jpg,jpeg,png,bmp',
            'content' => 'required'
        ];
    }

    public function getValidRequest()
    {
        $image = $this->file('image');
        $slug = Str::slug($this->input('title'));

        if (isset($image)) {

            $imageExt = $image->getClientOriginalExtension();
            $currentDate = Carbon::now()->toDateString();
            $imageName = $slug . '-' . $currentDate . '-' . uniqid() . '.' . $imageExt;

            if (!Storage::disk('public')->exists('post')) {
                Storage::disk('public')->makeDirectory('post');
            }
            if (!Storage::disk('public')->exists('post/thumbnail')) {
                Storage::disk('public')->makeDirectory('post/thumbnail');
            }

            $path = "images/";

            $postImage = Image::make($image)->resize(null, 1060, function ($constraint){
                $constraint->aspectRatio();
            })->save(public_path($path).'post/'.$imageName);

            $thumbnail = Image::make($image)->fit(550, 550)
                ->save(public_path($path).'post/thumbnail/'.$imageName);

        }

        return [
            'user_id' => Auth::user()->getAuthIdentifier(),
            'category_id' => $this->input('category'),
            'title' => $this->input('title'),
            'slug' => $slug,
            'content' => $this->input('content'),
            'image' => $imageName,
            'is_published' => $this->input('is_published') ?? false,
        ];
    }
  • The api route in laravel
Route::patch('/update/{id}', 'Backend\PostController@update');

I use practically the same things to store a post, and it work's fine, the only difference is here i pass an id for the post to update and i not use the post method but patch for axios and the route (and i try with put, it's the same error).

thank's for your time !

1

1 Answers

1
votes

append '_method' field with value 'PATCH' to formData

    formData.append('_method', 'PATCH')

and send axios request post request to update data

   axios.post('/api/posts/update/' + id, formData, {
    headers: {
        'Content-Type': 'multipart/form-data'
    }
})