Rabu, 24 Maret 2021

Membuat Kategori Tree berjenjang pada laravel 8

 Pada awalnya awalnya saya membutuhkan kategori berjenjang yang mudah. Akhirnya saya ketemu dengan laravel-nestedset yang menurut saya sangat membantu sekali. Jadi case-nya seperti ini misal saya membuat kategori seperti ini

HP

    - Samsung

    - Iphone

BUKU

    - Komik

        - Humor

        - Serem

        - Romansa

    - Tutorial

Nah misal saya membuat tabel produk, dan satu produk memiliki satu kategori, Maka akan sangat kesulitan apa bila saya ingin menampilkan semua produk yang ada dalam kategori BUKU,

Nah Package lazychaser/laravel-nestedset ini menjawab hal tersebut,, mungkin untuk pembuatannya temen - temen bisa menginstallnya sesuai github berikut

https://github.com/lazychaser/laravel-nestedset

Gak perlu lah saya menjelaskan cara install dan konfigurasinya karena didalam link diatas udah luengkaps bangetss penggunaanya. So disini saya akan membuat tutorial gimana kategori tersebut disajikan dengan apik menggunakan jstree, kira2 seperti ini penampakannya



Disini saya menggunakan component aja ya,, untuk apa itu component dalam laravel silahkan anda googling di tempat lain. Saya menggunakan component karena dengan mudah bisa di panggil di halaman yang lain.

Pertama untuk databasenya kita buat migrationnya seperti ini ya... 

 php artisan make:model Master/Category -m 

Misal file modelnya saya taruh di folder master,, 

Kedua isi migrationnya dengan ini, harus persis yaa.. soalnya ntar jstree nya gak jalan kalau gak persis

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Kalnoy\Nestedset\NestedSet;

class CreateCategoriesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('categories'function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('text');
            NestedSet::columns($table);
            $table->timestamps();
        });
    }


    public function down()
    {
        Schema::dropIfExists('categories');
    }
}


Ketiga buat dulu component kategori dengan cara :

php artisan make:component Kategori

So tercipta controller component kategori di folder App\View\Component\Kategori.php

Kemudian isikan file tersebut seperti ini :

<?php

namespace App\View\Components;

use App\Models\Master\Category;
use Illuminate\View\Component;

class Kategori extends Component
{
    public function __construct()
    {
        //
    }

    public function render()
    {
        $tree = Category::get()->toTree();
        return view('components.kategori'compact('tree'));
    }
}

So disini saya udah bikin model yang bernama category ya,, agar bisa nyambung dengan js tree maka 

Category::get()->toTree(); ini lah jawabannya

Kemudian pada viewnya data tree tersebut kita tampilkan pada textarea yang saya hidden, kemudian dengan jQuery data dari textarea tersebut ditampilkan kedalam div dengan id jstree

Untuk viewnya ada pada resources/view/component/kategori.blade.php

Berikut isinya :


  
  @section('css')
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css" />
  @endsection

  <div id="jstree"></div>
  <textarea id='txt_folderjsondata' style="display:none;"> {!! $tree !!}</textarea>
  
  @push('js')
  {{-- <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script> --}}
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js"></script>
  <script type="text/javascript">
      $(document).ready(function(){
        var folder_jsondata = JSON.parse($('#txt_folderjsondata').val());
        // console.log(folder_jsondata);
        var $treeview = $("#jstree");
        var node = $("#node").val() + '_anchor';
        $treeview.jstree({ 
          'core' : {
            'data' : folder_jsondata,
            },
          })
          .on('loaded.jstree'function() {
              $treeview.jstree('open_all');
              $treeview
        .jstree(true)
        .select_node(node);
          })
          ;
      });
  </script>
  @endpush

 Tuh terlihat text areanya aku display none,, kemudian pada javascriptnya data pada textarea tersebut dijadikan jstree pada div. Untuk Jquery itu saya disable/komentar karena di template yang saya gunakan udah ada jquerynya,, kalau saya aktifkan ntar bentrok

Okkay sekarang kita panggil component tersebut pada halaman view,, tentunya karena ini component maka bisa dipanggil dimana aja dengan cara hanya menginputkan kode ini

<x-kategori/>

So pertanyaanya gimana ya,, saat kita klik kategori tersebut maka menampilkan data yang sesuai kategori tersebut ? jawabannya adalah dengan menggunakan javascript,, disini saya paka jquery karena simple banget scriptnya

@push('js')
<script type="text/javascript">
$(function () {
    $('#jstree').on("changed.jstree"function (edata) {
      console.log(data.selected);
        var slug = data.selected;
        url = "{{ route('edit.category',":slug") }}";
        url = url.replace(':slug'slug);
        window.location.replace(url);
    });  
  });
</script>
  @endpush

Maka saat jstree di klik di jquery kan pakai onchanged dan kita redirect deh ke halaman yang kita butuhkan berdasarkan id kategori tersebut.

Kalau ada yg belum paham silahkan bertanya yaa,, Insya Allah akan saya jawab




Cara membagi file route pada laravel 8 (route mapping)

 Mmmm kayakya judulnya agak aneh,, tapi disini saya mau menginfokan bahwa file route tidak hanya di folder routes dan web.php,, akan tetapi bisa di bagi-bagi sesuai prefix yang digunakan,

Jadi misalkan route kita seperti ini :

admin/permission

admin/user

admin/role

transaksi/penjualan

transaksi/pembelian

report/penjualan

report/pembelian

Terlihat kita bisa membagi file route kedalam 3 file, yaitu file admin.php, transaksi.php dan report.php

Letak konfigurasi file web.php ada di  App/Providers/RouteServiceProvider.php berikut contoh file tersebut 

 public function boot()
    {
        $this->configureRateLimiting();

        $this->routes(function () {
            Route::prefix('api')
                ->middleware('api')
                ->namespace($this->namespace)
                ->group(base_path('routes/api.php'));

            Route::middleware('web')
                ->namespace($this->namespace)
                ->group(base_path('routes/web.php'));
        });
    }

Jadi apabila ubah nama web.php menjadi default.php dan kita merubah settingan diatas yang semula 'routes/web.php' menjadi 'routes/default.php' maka aplikasi kita dapat berjalan dengan normal.

So agar menjadi rapi maka saya biasanya membuat folder web dan merename web.php menjadi default.php dan men-cut file default.php ke dalam folder web. Sehingga file RoutesServiceProvider.php saya rubah seperti ini ;

            Route::middleware('web')
                ->namespace($this->namespace)
                ->group(base_path('routes/web/default.php'));

Okkay setelah saya rubah seperti itu mestinya aplikasi berjalan seperti biasa.

Setelah itu saya membagi file sesuai dengan prefix dan menambahkan seperti ini


            Route::middleware('web')
                ->namespace($this->namespace)
                ->group(base_path('routes/web/default.php'));

            Route::middleware('web''has.role')
                ->namespace($this->namespace)
                ->prefix('admin')
                ->group(base_path('routes/web/admin.php'));

            Route::middleware('web''has.role')
                ->namespace($this->namespace)
                ->prefix('master')
                ->group(base_path('routes/web/master.php'));

            Route::middleware('web''has.role')
                ->namespace($this->namespace)
                ->prefix('trans')
                ->group(base_path('routes/web/trans.php'));

            Route::middleware('web''has.role')
                ->namespace($this->namespace)
                ->prefix('report')
                ->group(base_path('routes/web/report.php'));

Hilangkan 'has.role' bila halaman yg di akses tidak perlu login

Dan bisa di tebak sekarang didalam folder web terdapat file-file seperti ini :


So sekarang kita bisa membagi-bagi route ke masing-masing folder, contoh untuk prefix account, maka isi didalam file account.php seperti ini :

<?php

use App\Http\Controllers\Account\ChangePasswordController;
use App\Http\Controllers\Account\EditProfileController;
use App\Http\Controllers\Account\ProfileController;
use Illuminate\Support\Facades\Route;


Route::middleware('auth')->group(function () {
    Route::get('profile',  ProfileController::class)->name('profile');
    Route::get('change-password',  [ChangePasswordController::class'index'])->name('password');
    Route::get('edit-profile',  [EditProfileController::class'index'])->name('edit.profile');
    Route::put('{id}/edit', [EditProfileController::class'update'])->name('update.profile');
    Route::put('{id}/edit-password', [ChangePasswordController::class'update'])->name('update.password');
    //     });
});

Hilangkan middleware('auth') jika halaman yg di akses tidak perlu login

Maka kita tidak perlu mendefinisikan group prefix lagi disini karena sudah dibagi sebelumnya di file RouteServiceProvider.

Sekian tutorial saya,, semoga bermanfaat.