Membuat Blog dengan Laravel & VueJS - #9 | Membuat Kategori & Upload Gambar

whynwd

whynwd Selasa, 17 September 2019

Membuat Blog dengan Laravel & VueJS - #9 | Membuat Kategori & Upload Gambar

Kita masih akan mengerjakan untuk komponen CreatePost.vue, dimana pada halaman ini adalah untuk proses pembuatan pos baru.

Dalam pembuatan postingan, ada beberapa konten didalamnya, diantaranya title, body, image, dan kategori. Dari keempatnya, kita baru membuat 2 kolom yaitu title dan body yang sudah kita kerjakan sebelumnya, selain itu kita juga sudah buat proses mengirim data ke database, respon pesan, dan validasinya.

Karena konten/field/kolom pos belum semuanya kita buat, masih ada kolom image/gambar dan kategori, maka kita akan membuatnya.

Hal pertama yang akan kita lakukan adalah menambahkan kolom baru pada table posts.

Kita akan buat 2 kolom baru yaitu image dan category_id. Silahkan jalankan perintah dibawah ini untuk membuat table migrasi'nya.
php artisan make:migration add_image_to_posts_table --table=posts

php artisan make:migration add_category_id_to_posts_table --table=posts
Setelah file migrasi keduanya sudah dibuat, kemudian buka filenya yang terdapat pada folder migrations di direktori database/migrations, lalu silahkan buat seperti dibawah ini.
//..add_image_to_posts_table.php
...
class AddImageToPostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('posts', function (Blueprint $table) {
           $table->binary('image')->after('body');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('posts', function (Blueprint $table) {
            Schema::dropIfExists('image');
        });
    }
}
//..add_category_id_to_posts_table.php
...
class AddCategoryIdToPostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('posts', function (Blueprint $table) {
            $table->integer('category_id')->unsigned()->nullable()->after('image');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('posts', function (Blueprint $table) {
            Schema::dropIfExists('category_id');
        });
    }
}
Kemudian jalankan perintah berikut pada terminal:
php artisan migrate
Selain cara diatas ada cara lain yang bisa kita lakukan untuk menambahkan kolom.

Cara lain yang bisa kita lakukan adalah dengan mengupdate file migrasi posts seperti dibawah ini:
//..create_posts_table.php
...
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->integer('user_id')->unsigned();
            $table->string('title');
            $table->text('body');
            $table->binary('image');
            $table->integer('category_id')->unsigned()->nullable();
            $table->timestamps();
        });
    }
...
Kemudian jalankan perintah berikut:
//cmd/terminal
php artisan migrate:fresh
Setelah melakukan migrasi dan berhasil, jika dilihat pada database di tabel posts maka akan bertambah 2 kolom seperti gambar dibawah ini.

Membuat Blog dengan Laravel & VueJS - #9 | Membuat Kategori & Upload Gambar

Request data image

Setelah selesai membuat/menambahkan kolom pada table posts. Selanjutnya kita akan membuat fungsi request datanya.

Kita akan mengerjakan terlebih dahulu untuk kolom image, dan langkah pertama yang akan kerjakan adalah membuat requestnya di PostController.php pada method store.
//PostController.php
...
public function store(Request $request)
{ 
   $request->validate([
      'title' =>  'required',
      'body' =>  'required', 
      'image' => 'required|mimes:jpeg,png,jpg,gif,svg',
   ]);

   $post = new Post;
   $post->user_id = $request->user_id;
   $post->title = $request->title; 
   $post->body = $request->body; 

   if ($request->hasFile('image')) {
   $image = $request->file('image'); 
   $name = str_slug($request->title).'.'.$image->getClientOriginalExtension();
   $destinationPath = public_path('/images');
   $image->move($destinationPath, $name);
   $post->image = $name;
   }
 
   $post->save();

   return $post;
}
...
Diatas kita buat request untuk image beserta validasinya, dan lokasi gambar ketika berhasil disimpan akan berada di folder images di direktori public.

Setelah controller selesai dikerjakan, selanjutnya kita buka komponen CreatePost.vue.

Silahkan tambakan elemen dibawah ini pada form:
//CreatePost.vue
...
<div class="form-group">
    <span v-if="errors.image" class="badge badge-danger"> 
      {{ errors.image[0] }} 
    </span>
    <div class="custom-file mb-3">
        <input type="file" ref="image" name="image" class="custom-file-input" id="image" required>
     <label class="custom-file-label" >Choose file...</label>
    </div>
</div>
...
Kemudian tambahkan value formdata.append untuk image:
//CreatePost.vue
formData.append("image", this.$refs.image.files[0]);
Hasilnya:
//CreatePost.vue
<template>
  <div class="_container">
    <div class="admin-page-title">Create New Post</div>
      <div class="_wrap-form">
        <form class="_bg-form">
         
         <span v-if="successful" class="label label-sucess"><h4>Saved successfully!</h4><small>(Post baru berhasil dikirim dan dipublikasi.)</small></span>
          
          <div class="form-group">
            <span v-if="errors.title" class="label label-danger">
              {{ errors.title[0] }}
            </span>
            <input type="text" ref="title" class="form-control" id="title" placeholder="Title">
          </div> 

          <div class="form-group">
             <span v-if="errors.body" class="badge badge-danger"> 
              {{ errors.body[0] }} 
            </span>
            <textarea class="form-control" ref="body" id="body" placeholder="Body" rows="8"></textarea>
          </div>

          <div class="form-group">
            <span v-if="errors.image" class="badge badge-danger"> 
              {{ errors.image[0] }} 
            </span>
            <div class="custom-file mb-3">
            <input type="file" ref="image" name="image" class="custom-file-input" id="image" required>
            <label class="custom-file-label" >Choose file...</label>
           </div>
          </div>

            <button type="submit" @click.prevent="create" class="btn btn-primary">
            Submit
          </button>
        </form><br><br><br>
      </div>
    </div>
</template>

<script>
  export default {
    props: {
      userId: {
        type: Number,
        required: true
      }
    },  
    data:function() {
      return { 
        successful: false,
        errors: [], 
      };
    },
    methods: { 
      create() {
        const formData = new FormData();
        formData.append("user_id", this.userId);
        formData.append("title", this.$refs.title.value);
        formData.append("body", this.$refs.body.value); 
        formData.append("image", this.$refs.image.files[0]);

        axios.post('/api/posts', formData)
          .then(response => {
            console.log(response.data);
            this.successful = true;
            this.errors = false;
          })
          .catch(error => {
            if((error.response.status = 422 )){
            console.log(error.response.data);
            this.errors = error.response.data.errors;
            this.successful = false;
            }
          });

        this.$refs.title.value = "";
        this.$refs.body.value = "";
        this.$refs.image.value = "";

      }
    }
  };
</script>
Sampai disini silahkan coba untuk membuat pos baru.

*Pastikan php  artisan serve  dan  npm run watch  dijalankan dan tidak ada kesalahan.

Request Data Kategori

Setelah request data gambar selesai dikerjakan, selanjutnya kita akan lanjutkan dengan membuat request data kategori.

Untuk menambahkan kategori dalam pembuatan pos baru kita tidak menginputkan nama kategori secara manual seperi title dan body, akan tetapi kita memilih kategori dengan pilihan nama-nama kategori yang sudah kita buat/sediakan sebelumnya.

Kategori-kategori ini kita perlu membuatnya terlebih dahulu yang disimpan ditable yang berbeda. Jadi dalam pembuatan pos, kita akan membuat relasi untuk mengambil kategori dari table lain yang kita hubungkan dengan table posts sehingga pilihan kategori dapat ditampilkan di halaman createpost.

Membuat table kategori

Kita akan buat table baru di database untuk kategori, silahkan jalankan perintah dibawah ini pada terminal untuk membuat file migrasinya.
php artisan make:migration create_categories_table --create=categories
Setelah file migrasi terbuat, buka file tersebut dan tambahkan field seperti dibawah ini:
//..create_categories_table.php
class CreateCategoriesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('categories', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->integer('user_id')->unsigned();
            $table->string('name');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('categories');
    }
}
Kemudian jalankan perintah berikut:
php artisan migrate
Setelah table categories dibuat, kita akan lakukan insert nama-nama kategorinya dengan cara manual di databasenya langsung.

Silahkan buat seperti contoh dibawah ini:

Membuat Blog dengan Laravel & VueJS - #9 | Membuat Kategori & Upload Gambar

Kita lakukan insert secara manual manual ini hanya sementara, karena nanti kita buat juga CRUD untuk kategorinya.

Menampilkan Kategori

Setelah table kategori di database sudah dibuat beberapa kategori, langkah selanjutnya yang akan kita kerjakan adalah menampilkan kategorinya pada halaman creaepost.

Langkah pertama yang kita lakukan adalah dengan membuat model dari kategori untuk dapat kita ambil datanya pada database.

Silahkan jalankan perintah berikut:
php artisan make:model Category
File model Category.php akan terbuat di direktori  app.

Setelah model dibuat, selanjutnya kita buat method baru pada PostController.php yang akan me'return ke model.
//PostController.php
...
use App\Category;
...
public function getCategories()
{
  return Category::latest()->get();
}
...
Kemudian kita buat route baru di routes/api.php.
//api.php
Route::get('getCategories', 'PostController@getCategories');
Kita buat route dengan method  get  yang actionnya ke  getCategories  pada  PostController.php .

Selanjutnya buka komponen CreatePost.vue.

Pada komponen CreatePost.vue, pertama tambahkan elemen dibawah ini pada form:
//CreatePost.vue
<div class="form-group">
   <span v-if="errors.category_id" class="badge badge-danger">
      {{ errors.category_id[0] }}
   </span>
   <select class="form-control" ref="category_id">
     <option value=""> Select Category  </option>
     <option v-for="category in categories" v-bind:value="category.id">
       {{category.name}} 
     </option>
   </select>  
</div>
Kategori array ditampilkan dalam bentuk pilihan menggunakan elemen option.

Selanjutnya kita tambahkan data categories:
...
data:function() {
  return { 
    successful: false,
    errors: [],
    categories: [], 
  };
},
...
Kemudian kita akan buat lifecycle method yaitu created:
...
created: function () {
   this.getCategories();
},
...
Lalu buat method dalam properti methods untuk kita ambil data kategori agar dapat ditampilkan.
...
},
getCategories() {
 axios.get("/api/getCategories")
 .then(response => {
  console.log(response.data);
  this.categories = response.data; 
  });
}
...
Jadinya:
<script>
  export default {
    props: {
      userId: {
        type: Number,
        required: true
      }
    },  
    data:function() {
      return { 
        successful: false,
        errors: [],
        categories: [], 
      };
    },
    created: function () {
        this.getCategories();
    },
    methods: { 
      create() {
        const formData = new FormData();
        formData.append("user_id", this.userId);
        formData.append("title", this.$refs.title.value);
        formData.append("body", this.$refs.body.value); 
        formData.append("image", this.$refs.image.files[0]);

        axios.post('/api/posts', formData)
          .then(response => {
            console.log(response.data);
            this.successful = true;
            this.errors = false;
          })
          .catch(error => {
            if((error.response.status = 422 )){
            console.log(error.response.data);
            this.errors = error.response.data.errors;
            this.successful = false;
            }
          });

        this.$refs.title.value = "";
        this.$refs.body.value = "";
        this.$refs.image.value = "";
        this.$refs.category_id.value = "";
      },
      getCategories() {
        axios.get("/api/getCategories")
        .then(response => {
         console.log(response.data);
         this.categories = response.data; 
        });
      }
    }
  };
</script>
Jika dilihat hasilnya pada halaman createpost, kategori akan tampil seperti gambar dibawah ini:

Membuat Blog dengan Laravel & VueJS - #9 | Membuat Kategori & Upload Gambar

Sampai disini kita berhasil menampilkan kategorinya.

Setelah berhasil menampilkan kategori, langkah selanjutnya yang akan kita buat adalah membuat request data kategori untuk dapat disimpan pada table posts.

Mari terlebih dahulu kita buka PostController.php dan buat request + validasinya pada method store:
//PostController.php
...
//jangan lupa menambahkan class category
use App\Category;
...

public function store(Request $request)
{ 
    $request->validate([
    'title' =>  'required',
    'body' =>  'required',
    'category_id' => 'required', 
    'image' => 'required|mimes:jpg,jpeg,png',
    ]);

    $post = new Post;
    $post->user_id = $request->user_id;
    $post->title = $request->title; 
    $post->body = $request->body; 

    if ($request->hasFile('image')) {
    $image = $request->file('image'); 
    $name = str_slug($request->title).'.'.$image->getClientOriginalExtension();
    $destinationPath = public_path('/images');
    $image->move($destinationPath, $name);
    $post->image = $name;
    }

    $post->category_id = $request->category_id;

    $post->save();

    return $post;
}
...
Setelah dari PostController.php, kita menuju ke komponen CreatePost.vue.

Silahkan buat formdata append:
formData.append("category_id", this.$refs.category_id.value);
Buat juga:
this.$refs.category_id.value = "";
Untuk mengkosongkan value setelah data berhasil terkirim.

Apabila semua sudah dikerjakan, langkah terakhir kita tinggal mencobanya.

Membuat Blog dengan Laravel & VueJS - #9 | Membuat Kategori & Upload Gambar

Diatas adalah contoh dalam pembuatan pos baru dan semua data berhasil dikirim.

Untuk kolom category_id bukan nama yang diambil tapi id dari kategori, namun saat menampilkan pos nantinya kita tampilkan nama dari kategori.

Sampai disini untuk halaman createpost sudah semua kita kerjakan mulai dari data title, body, image, dan kategori.

Kita lajutkan di part selanjutnya untuk membuat halaman lainnya.


Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel