Black Friday Super Sale!Limited Time 50% OFF for All-Access Plans
Save 50% Now

Problem using livewire and ktSelect


Hi Keen team,

I've come across a problem while using livewire with ktui.
I've got a form inside a modal. I'm using wire:ignore.self on the modal div to let ktui work on the opening and closing of the modal.

Inside I've a form with different inputs using wire:model to synchronise it with a livewire form handling validation.

For the select I've tried many options and none are working properly. I've put a wire:ignore on the div surronding the label and select, i've put the kt-select class and the data-kt-select attribute.

this select also triggers the change on the rest of the form depending on its value. I've used this script on the modal to make it work using the change event of ktselect

const selectElement = document.getElementById("pack");
if (selectElement) {
selectElement.addEventListener("change", (event) => {
const { value } = event.detail.payload;
$wire.$set("form.pack", parseInt(value));
});
}


but the problem is when I'm opening the modal to edit a pack. I've tried to add the createInstances of the KTSelect on a livewire hook to trigger the reload of the select everytime livewire refresh the component but that doesn't seem to work

document.addEventListener("livewire:initialized", () => {
Livewire.hook("morph.updated", ({el, component}) => {
KTSelect.createInstances()
})
});


On the documentation it doesn't seem to have a component API methods like for the dropdown, are they implemented and working the same ? How can I make that work properly ?


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 (6)


Hi

Sorry for the delay. Check your Metronic 9.3.4 download includes the latest ktui.min.js.
Verify the file includes getInstance by checking in the browser console:

console.log(typeof KTSelect.getInstance); // Should be "function"


Run "npm run dev" at your Laravel root to rebuild assets.

Thanks



Hi Pierre Ankh

In the recent version, KTSelect has a refresh() method that's designed exactly for this use case. For static selects (non-remote), refresh() syncs the selection from the native select element without triggering change events.

Instead of recreating the entire select element, you can use the refresh() method on the KTSelect instance:
https://gist.github.com/faizalmy/825f876102125363f613ae0a7c6d7e9a

Use wire:ignore on the wrapper div to prevent Livewire from re-rendering the select
Include data-kt-select attribute for auto-initialization
Use wire:model on the select element itself (Livewire will handle the value attribute)

<div class="flex flex-col gap-1.5" wire:ignore>
<label class="kt-label">Pack Premium</label>
<select class="kt-select kt-select-lg" data-kt-select>
<option value="0">No</option>
<option value="1">Yes</option>
</select>
</div>



Thanks for the gist and the code example, unfortunately I've tried with the last metronic so far (9.3.4) and the ktui.min.js provided might not be up to date as I have a console error saying that KTSelect.getInstance is not a function.

I've tried using the ktui npm librairie importing the ktui.min.js in my app.js but then I couldn't make KTSelect available with window.KTSelect



As there is not much documented on the KTSelect methods, I've found a workaround by completely removing the select and recreating it entirely.

I don't know if that's the good way and hopefully methods on KTSelect could help doing that with less code but here is my implementation:


<div class="flex flex-col gap-1.5" wire:ignore>
<label class="kt-label">
Pack Premium
</label>

<select
class="kt-select kt-select-lg
>
<option value="0" selected>No</option>
<option value="1">Yes</option>
</select>
</div>

@script
<script>
document.addEventListener("livewire:initialized", () => {

let selectElement = document.getElementById("pack_premium");
let ktSelectInstance = null;

function initializeKTSelect() {
const currentValue = String($wire.form.pack_premium);

if (ktSelectInstance) {
if (ktSelectInstance.dispose) {
ktSelectInstance.dispose();
}
ktSelectInstance = null;
}

const parent = selectElement.parentElement;
const newSelect = document.createElement("select");
newSelect.id = "pack_premium";
newSelect.className = "kt-select kt-select-lg";

const option0 = document.createElement("option");
option0.value = "0";
option0.textContent = "No";

const option1 = document.createElement("option");
option1.value = "1";
option1.textContent = "Yes";

if (currentValue === "0") {
option0.setAttribute("selected", "selected");
option0.selected = true;
} else {
option1.setAttribute("selected", "selected");
option1.selected = true;
}

newSelect.appendChild(option0);
newSelect.appendChild(option1);

newSelect.value = currentValue;

parent.replaceChild(newSelect, selectElement);
selectElement = newSelect;

ktSelectInstance = new KTSelect(selectElement);

let isManualChange = false;
selectElement.addEventListener("change", (e) => {
if (!isManualChange) {
$wire.$set("form.pack_premium", parseInt(e.target.value));
}
});
}

const add_pack_modal = KTModal.getInstance(document.querySelector("#add_pack_modal"));
add_pack_modal.on("hide", (detail) => {
$wire.$dispatch("reset-form");
});

$wire.$on("open-pack-create-modal", () => {
$wire.$set("form.pack_premium", 0);
initializeKTSelect();
});

$wire.$on("pack-form-loaded", () => {
initializeKTSelect();
});

$wire.$on("pack-updated-success", (event) => {
KTToast.show({ message: "Pack updated", variant: "success" })
add_pack_modal.hide();
})
$wire.$on("pack-created-success", (event) => {
KTToast.show({ message: "Pack created", variant: "success" })
add_pack_modal.hide();
})
});
</script>
@endscript


Is this the good approach or am I missing something?



It sounds like you’re running into a common issue when integrating Livewire with `ktSelect`—usually it comes down to the fact that `ktSelect` (or any JS-based select component) initializes on page load, but Livewire can re-render DOM elements, causing the select to lose its event listeners or selected state. One way to handle this is to use Livewire’s `wire:ignore` on the select element and then re-initialize `ktSelect` in a Livewire hook like `Livewire.hook('message.processed', ...)`. I’ve found that approach keeps the component functional even after updates. Do you also use dynamic content or live streams on your project, like embedding Photocall TV online links, that might complicate the Livewire re-renders?



I indeed had an interference with a wire:key which provokes a rerendering even though I had wire:ignore on the div surrounding the select.

I've made the condition on the form work with hooking to the livewire:initialized event (livewire:init doesn't seem to work)

document.addEventListener("livewire:initialized", () => {
const selectElement = document.getElementById("pack_sans_stand");
if (selectElement) {
selectElement.addEventListener("change", (event) => {
const {value} = event.detail.payload;
$wire.$set("form.pack_sans_stand", parseInt(value));
});
}
}


My only problem now is to be able to reload KTSelect when livewire update the select value. I've tried to do it on the morph:updated hook with destroying the ktselect instance and recreating it with new KTSelect() but it seems that it does generate a change event and thus being listened by the eventlistener and creating an infinite loop of livewire update.

Is there a method to refresh ktselect without triggering the change event ?


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  :(