Get 2025 Templates Mega Bundle!$1000 worth of 19 Bootstrap HTML, Vue & React Templates + 3 Vector Sets for just $99
Get for 99$

Unable to use Draggable plugins


So basically i am first time Metronic users so a lot of thing like including plugin etc is not familiar to me. I am using Laravel template for metronic for one of my project.
So i am trying to use the Draggable plugin: https://preview.keenthemes.com/html/metronic/docs/general/draggable/overview#usage
I followed the tutorial and included in my required page with the below script:


<script src="{{ asset("/assets/plugins/custom/draggable/draggable.bundle.js") }}" defer></script>


<script>

document.addEventListener("DOMContentLoaded", () => {


var containers = document.querySelectorAll(".draggable-zone");

if (containers.length === 0) {
return false;
}

var swappable = new Sortable.default(containers, {
draggable: ".draggable",
handle: ".draggable .draggable-handle",
mirror: {
//appendTo: selector,
appendTo: "body",
constrainDimensions: true
}
});



</script>


But unfortunately none of this working and i am getting:

8:996 Uncaught ReferenceError: Sortable is not defined
at HTMLDocument.<anonymous> (8:996:17)


What am i missing here?


Text formatting options
Submit
Here's a how to add some HTML formatting to your comment:
  • <pre></pre> for JS codes block
  • <pre lang="html"></pre> for HTML code block
  • <pre lang="scss"></pre> for SCSS code block
  • <pre lang="php"></pre> for PHP code block
  • <code></code> for single line of code
  • <strong></strong> to make things bold
  • <em></em> to emphasize
  • <ul><li></li></ul>  to make list
  • <ol><li></li></ol>  to make ordered list
  • <h3></h3> to make headings
  • <a></a> for links
  • <img> to paste in an image
  • <blockquote></blockquote> to quote somebody
  • happy  :)
  • shocked  :|
  • sad  :(

Replies (12)


Possible Causes & Solutions
1. Ensure Draggable Plugin is Loaded Correctly
Verify that the draggable.bundle.js file is properly loaded. Check the Network tab in your browser's Developer Tools (F12 > Network > JS) to confirm the file is being loaded successfully.

If it’s not being loaded:

Ensure the file exists at the expected path:
vbnet
Copy
Edit
public/assets/plugins/custom/draggable/draggable.bundle.js
Try clearing Laravel's cache and reloading:
bash
Copy
Edit
php artisan cache:clear
php artisan config:clear
2. Reference Sortable Correctly
Metronic uses @shopify/draggable, where Sortable is part of the Draggable object. Modify your script to explicitly reference it:

javascript
Copy
Edit
document.addEventListener("DOMContentLoaded", () => {
if (typeof window.Draggable === "undefined") {
console.error("Draggable is not loaded properly.");
return;
}

var Sortable = window.Draggable.Sortable; // Correct reference to Sortable
var containers = document.querySelectorAll(".draggable-zone");

if (containers.length === 0) {
return;
}

var sortableInstance = new Sortable(containers, {
draggable: ".draggable",
handle: ".draggable .draggable-handle",
mirror: {
appendTo: "body",
constrainDimensions: true
}
});

console.log("Sortable initialized:", sortableInstance);
});
This ensures Sortable is accessed correctly within the Draggable library.

3. Load the Plugin Before Your Script
Since you’re using defer, ensure the script is loaded before your custom script executes. Try removing defer and placing the <script> tag before your inline script:

html
Copy
Edit
<script src="{{ asset('/assets/plugins/custom/draggable/draggable.bundle.js') }}"></script>

<script>
// Your JavaScript code here
</script>
4. Verify Laravel Asset Path Resolution
Ensure Laravel correctly serves the asset. Use the following in Blade to print the actual URL:

php
Copy
Edit
{{ asset('/assets/plugins/custom/draggable/draggable.bundle.js') }}
Open this URL in your browser and check if the script is accessible.

5. Try Using a CDN
If the local script is not working, use a CDN to load the plugin:

html
Copy
Edit
<script src="https://cdn.jsdelivr.net/npm/@shopify/draggable@1.0.0-beta.8/lib/sortable.js"></script>
6. Check for Dependencies
If you’re using npm/yarn, ensure @shopify/draggable is installed:

bash
Copy
Edit
npm install @shopify/draggable
Then, if you're using a JS module system, import it properly:

javascript
Copy
Edit
import { Sortable } from "@shopify/draggable";
Conclusion
✅ Ensure draggable.bundle.js is loading properly.
✅ Correctly reference Sortable from window.Draggable.Sortable.
✅ Remove defer if necessary and adjust script order.
✅ Verify Laravel asset paths.
✅ Use a CDN or reinstall dependencies if needed.
By following these steps, your Draggable plugin should function correctly. Let me know if you need further assistance! 🚀



Ensure draggable.bundle.js loads (check the Network tab for errors).
Use Draggable.Sortable instead of Sortable.default:
js
Copy
Edit
var swappable = new Draggable.Sortable(containers, {
draggable: ".draggable",
handle: ".draggable .draggable-handle",
mirror: { appendTo: "body", constrainDimensions: true }
});
Remove defer from <script> and place it before </body>.
Try loading @shopify/draggable from a CDN:
html
Copy
Edit
<script src="https://cdnjs.cloudflare.com/ajax/libs/Draggable/1.0.0-beta.8/draggable.bundle.legacy.js"></script>
Clear Laravel cache:
sh
Copy
Edit
php artisan view:clear && php artisan cache:clear
Try these and let me know if the issue persists! 🚀



Well i have basically did this, and it worked that way. Its sad that documentations are a bit lacking in this regards how to enable the plugins properly that already are within the app.



Hi,

Can you try to run your code in the bottom, after all core script includes within dom ready event as shown below:


KTUtil.onDOMContentLoaded(function () { 
// your code
});


Thus you can access the draggable plugin once its loaded and initialized.

Regards,
Sean.



Within the same blade file?



Hi,

inside blade just use like this:


<script>
window.addEventListener("load", () => {
// your code
});
});
</script>


Regards,
Sean



Still same, heres my updated blade file:


<x-default-layout>

@section("title")
Product Information
@endsection

@section("breadcrumbs")
{{ Breadcrumbs::render("categories.category-list") }}
@endsection

<div class="card mb-10">
<form method="POST" action="{{ route("product.update", $product->id) }}" enctype="multipart/form-data">
@csrf
@method("PUT")
<div class="mb-10">
<div class="card-header">
<h3 class="card-title">Upload Images
</div>
<div class="card-body">
<div class="mb-10">
<div class="dropzone" >
<!--begin::Message-->
<div class="dz-message needsclick">
<i class="ki-duotone ki-file-up fs-3x text-primary"><span class="path1"></span><span class="path2"></span></i>

<!--begin::Info-->
<div class="ms-4">
<h3 class="fs-5 fw-bold text-gray-900 mb-1">Drop files here or click to upload.
<span class="fs-7 fw-semibold text-gray-500">Upload up to 10 files</span>
</div>
<!--end::Info-->
</div>
</div>

</div>
<div class="mb-10">

<div class="image-container">
@foreach($product->images as $image)
<div class="image-input image-input-outline" data-kt-image-input="true" >
<!--begin::Image preview wrapper-->
<div class="image-input-wrapper w-125px h-125px" ></div>

<span class="btn remove-avatar-btn btn-icon btn-circle btn-color-muted btn-active-color-primary w-25px h-25px bg-body shadow"
data-kt-image-input-action="change"
data-bs-toggle="tooltip"
data-bs-dismiss="click"
data-image-
title="Remove">
<i class="ki-outline ki-cross fs-3"></i>
</span>
</div>
@endforeach
</div>
<div class="row row-cols-lg-2 g-10 draggable-zone">
<div class="col draggable">
<!--begin::Card-->
<div class="card card-bordered">
...
</div>
<!--end::Card-->
</div>

<div class="col draggable">
<!--begin::Card-->
<div class="card card-bordered">
...
</div>
<!--end::Card-->
</div>

<div class="col draggable">
<!--begin::Card-->
<div class="card card-bordered">
...
</div>
<!--end::Card-->
</div>

<div class="col draggable">
<!--begin::Card-->
<div class="card card-bordered">
...
</div>
<!--end::Card-->
</div>

<div class="col draggable">
<!--begin::Card-->
<div class="card card-bordered">
...
</div>
<!--end::Card-->
</div>

<div class="col draggable">
<!--begin::Card-->
<div class="card card-bordered">
...
</div>
<!--end::Card-->
</div>

<div class="col draggable">
<!--begin::Card-->
<div class="card card-bordered">
...
</div>
<!--end::Card-->
</div>

<div class="col draggable">
<!--begin::Card-->
<div class="card card-bordered">
...
</div>
<!--end::Card-->
</div>

<div class="col draggable">
<!--begin::Card-->
<div class="card card-bordered">
...
</div>
<!--end::Card-->
</div>

<div class="col draggable">
<!--begin::Card-->
<div class="card card-bordered">
...
</div>
<!--end::Card-->
</div>
</div>
</div>
</div>
</div>

</div>
<div>

<div class="card card-flush mb-10">
<div class="card-header">
<h3 class="card-title">Product Details
</div>
<div class="card-body">
<!-- Product Title -->
<div class="mb-10">
<label class="form-label required">Product Title</label>
<input type="text" class="form-control" placeholder="Enter title" name="name" maxlength="20" value="{{ $product->name }}">
<span class="form-text text-muted">Do not exceed 20 characters when entering the product name.</span>
</div>

<!-- Category -->
<div class="row g-9 mb-10">

<div class="col-md-6">
<label class="form-label">Category</label>
<input type="text" class="form-control" placeholder="Category" name="category" value="{{$product->category->name}}" disabled>
<input type="hidden" name="category_id" value="{{ $product->category->id }}">
</div>
<!-- Price -->
<div class="col-md-6">
<label class="form-label required">Price</label>
<input type="number" class="form-control" placeholder="Price" name="price" value="{{$product->price}}" >
</div>
</div>

<div class="row">
<!-- Left Column -->
<div class="col-md-6 mb-10">
<!--begin::Input wrapper-->
<div class="d-flex flex-column mb-8 fv-row">
<!--begin::Label-->
<label class="d-flex align-items-center fs-6 fw-semibold mb-2">
<span class="required">Size</span>
</label>
<!--end::Label-->

<!--begin::Buttons-->

<div >
@foreach ($product->category->sizes as $size)
<div class="form-group row mb-2 align-items-center">
<div class="col-md-1 d-flex align-items-center">
<label class="form-label">{{ $size }}</label>
</div>
<div class="col-md-3 d-flex align-items-center">
<input type="number" class="form-control mb-2 mb-md-0" placeholder="Enter Stock" name="quantities[{{ $size }}]" value="{{ $quantities[$size] ?? 0 }}" />
</div>
</div>
@endforeach
</div>

</div>

</div>

<!-- Right Column -->
<div class="col-md-6 mb-10">
<!-- Wrapper Div to Handle Structure and Spacing -->
<div class="d-flex flex-column">
<!-- Checkbox to Toggle the Collapsible Section -->
{{-- <label class="btn btn-outline btn-outline-dashed d-flex text-start p-6 align-items-start">
<input type="hidden" name="has_discount" value="0">
<!-- Checkbox for Selling Price -->
<span class="form-check form-check-custom form-check-solid form-check-sm mt-1">
<input

name="has_discount"
class="form-check-input"
type="checkbox"
value="1"
data-bs-toggle="collapse"
data-bs-target="#sellingPriceOptions"
aria-expanded="false"
aria-controls="sellingPriceOptions"
/>
</span>
<!-- Info and Label Text -->
<span class="ms-5 d-flex flex-column">
<span class="fs-4 fw-bold text-gray-800 text-nowrap mb-2" for="sellingPriceToggle">Discount Price</span>

<!-- Collapsible Section for Sale Price and Schedule -->
<div class=" mt-4">
<!-- Sale Price Input -->
<div class="mb-10">
<label class="form-label">Sale Price</label>
<input type="number" class="form-control" placeholder="Discount Price" name="discount_price">
</div>
<!-- Schedule Input -->
<div>
<label class="form-label">Schedule</label>
<input type="date" class="form-control" name="discount_date">
</div>
</div>
</span>
</label> --}}
<label class="btn btn-outline btn-outline-dashed d-flex text-start p-6 align-items-start">
<input type="hidden" name="has_discount" value="0">
<!-- Checkbox for Selling Price -->
<span class="form-check form-check-custom form-check-solid form-check-sm mt-1">
<input

name="has_discount"
class="form-check-input"
type="checkbox"
value="1"
checked = {{$product->has_discount ? "checked" : ""}}
/>
</span>
<!-- Info and Label Text -->
<span class="ms-5 d-flex flex-column">
<span class="fs-4 fw-bold text-gray-800 text-nowrap mb-2" for="sellingPriceToggle">Discount Price</span>

<!-- Section for Sale Price and Schedule -->
<div class="mt-4">
<!-- Sale Price Input -->
<div class="mb-10">
<label class="form-label">Sale Price</label>
<input type="number" class="form-control" placeholder="Discount Price" name="discount_price" {{$product->has_discount ? "" : "disabled"}} value="{{$product->discount_price == null ? "0.0" : $product->discount_price}}">
</div>
<!-- Schedule Input -->
<div>
<label class="form-label">Schedule</label>
<input type="date" class="form-control" name="discount_date" value={{date("Y-m-d", strtotime($product->discount_date))}} {{$product->has_discount ? "" : "disabled"}}>
</div>
</div>
</span>
</label>
</div>
</div>
</div>

<div class="row g-9 mb-10">

<!-- Variant: Color -->
<div class="col-md-4">
<label class="form-label">Color</label>
<input type="text" class="form-control" placeholder="Choose color" name="color" value={{$product->color}} >
</div>
<!-- SKU -->
<div class="col-md-4">
<label class="form-label">SKU</label>
<input type="text" class="form-control" placeholder="Enter SKU" name="sku" value={{$product->sku}}>
</div>
<div class="d-flex col-md-4 align-items-center">
<label class="d-flex align-items-center fs-6 fw-semibold mb-2">
<span>Best Seller &nbsp;</span>

<input

name="best_seller"
class="form-check-input"
type="checkbox"
value="1"
{{$product->best_seller ? "checked" : ""}}
/>
</label>

</div>
{{-- <!-- Tags -->
<div class="col-md-4">
<label class="form-label">Tags</label>
<input type="text" class="form-control" placeholder="Enter a tag" name="tags">
</div> --}}
</div>

<!-- Description -->
<div class="mb-10">
<label class="form-label required">Description</label>
<textarea class="form-control" name="description" placeholder="Short description about product" maxlength="100" >{{$product->description}}</textarea>
<span class="form-text text-muted">Do not exceed 100 characters when entering the description.</span>
</div>
</div>
<!--begin::Actions-->
<div class="card-footer d-flex justify-content-end py-6 px-9">
{{-- <button type="reset" class="btn btn-light btn-active-light-primary me-2">Discard</button> --}}
<button type="submit" class="btn btn-primary">Save Changes</button>
</div>
<!--end::Actions-->
</div>
</form>
</div>
<script src="{{ asset("assets/plugins/custom/draggable/draggable.bundle.js") }}" defer></script>

<script>
window.addEventListener("load", () => {
var containers = document.querySelectorAll(".draggable-zone");

if (containers.length === 0) {
return false;
}

var swappable = new Sortable.default(containers, {
draggable: ".draggable",
handle: ".draggable .draggable-handle",
mirror: {
//appendTo: selector,
appendTo: "body",
constrainDimensions: true
}
});
});
</script>
</x-default-layout>


Text formatting options
Submit
Here's a how to add some HTML formatting to your comment:
  • <pre></pre> for JS codes block
  • <pre lang="html"></pre> for HTML code block
  • <pre lang="scss"></pre> for SCSS code block
  • <pre lang="php"></pre> for PHP code block
  • <code></code> for single line of code
  • <strong></strong> to make things bold
  • <em></em> to emphasize
  • <ul><li></li></ul>  to make list
  • <ol><li></li></ol>  to make ordered list
  • <h3></h3> to make headings
  • <a></a> for links
  • <img> to paste in an image
  • <blockquote></blockquote> to quote somebody
  • happy  :)
  • shocked  :|
  • sad  :(
Text formatting options
Submit
Here's a how to add some HTML formatting to your comment:
  • <pre></pre> for JS codes block
  • <pre lang="html"></pre> for HTML code block
  • <pre lang="scss"></pre> for SCSS code block
  • <pre lang="php"></pre> for PHP code block
  • <code></code> for single line of code
  • <strong></strong> to make things bold
  • <em></em> to emphasize
  • <ul><li></li></ul>  to make list
  • <ol><li></li></ol>  to make ordered list
  • <h3></h3> to make headings
  • <a></a> for links
  • <img> to paste in an image
  • <blockquote></blockquote> to quote somebody
  • happy  :)
  • shocked  :|
  • sad  :(