N
Nuxt2d ago
o.m

How do I get the current DOM value of useTemplateRef() ?

I have this code and the watchEffect doesn't log everytime I dran an element. Is it possible to get the value of the current DOM after dragging the arrangement of the element?
<script setup lang="ts">
import { ref } from "vue";
import Sortable from "sortablejs";

// Reference to the list element
const itemsRef = useTemplateRef<HTMLElement | null>("items");

const list = ref(["Item 1", "Item 2", "Item 3", "Item 4", "Item 5"]);

onMounted(() => {
if (itemsRef.value) {
// Initialize Sortable on the list element
Sortable.create(itemsRef.value, {
animation: 150,
ghostClass: "sortable-ghost",
group: "shared",
});
}
watchEffect(() => {
console.log(itemsRef.value);
});
});
</script>

<template>
<ul id="items" ref="items">
<li v-for="item in list">
{{ item }}
</li>
</ul>
</template>

<style scoped></style>
<script setup lang="ts">
import { ref } from "vue";
import Sortable from "sortablejs";

// Reference to the list element
const itemsRef = useTemplateRef<HTMLElement | null>("items");

const list = ref(["Item 1", "Item 2", "Item 3", "Item 4", "Item 5"]);

onMounted(() => {
if (itemsRef.value) {
// Initialize Sortable on the list element
Sortable.create(itemsRef.value, {
animation: 150,
ghostClass: "sortable-ghost",
group: "shared",
});
}
watchEffect(() => {
console.log(itemsRef.value);
});
});
</script>

<template>
<ul id="items" ref="items">
<li v-for="item in list">
{{ item }}
</li>
</ul>
</template>

<style scoped></style>
5 Replies
kapa.ai
kapa.ai2d ago
Hi @o.m. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- To address your question about getting the current DOM value of useTemplateRef() after dragging elements, I can provide some insights based on the available knowledge sources. The useTemplateRef() composable in Nuxt 3 is similar to Vue's ref(), but it's specifically designed for template refs. However, the watchEffect you're using might not be the best approach to detect changes in the DOM after dragging elements. To get the current DOM value after dragging, you can use Sortable's onEnd event. Here's how you can modify your code to achieve this:
<script setup lang="ts">
import { ref } from "vue";
import Sortable from "sortablejs";

const itemsRef = useTemplateRef<HTMLElement | null>("items");

const list = ref(["Item 1", "Item 2", "Item 3", "Item 4", "Item 5"]);

onMounted(() => {
if (itemsRef.value) {
Sortable.create(itemsRef.value, {
animation: 150,
ghostClass: "sortable-ghost",
group: "shared",
onEnd: (evt) => {
// This will be called after a drag operation ends
console.log("New order:", Array.from(itemsRef.value.children).map(el => el.textContent));
}
});
}
});
</script>

<template>
<ul id="items" ref="items">
<li v-for="item in list">
{{ item }}
</li>
</ul>
</template>
<script setup lang="ts">
import { ref } from "vue";
import Sortable from "sortablejs";

const itemsRef = useTemplateRef<HTMLElement | null>("items");

const list = ref(["Item 1", "Item 2", "Item 3", "Item 4", "Item 5"]);

onMounted(() => {
if (itemsRef.value) {
Sortable.create(itemsRef.value, {
animation: 150,
ghostClass: "sortable-ghost",
group: "shared",
onEnd: (evt) => {
// This will be called after a drag operation ends
console.log("New order:", Array.from(itemsRef.value.children).map(el => el.textContent));
}
});
}
});
</script>

<template>
<ul id="items" ref="items">
<li v-for="item in list">
{{ item }}
</li>
</ul>
</template>
In this modified version, we've added an onEnd callback to the Sortable options. This callback will be triggered every time a drag operation ends. Inside this callback, we can access the current state of the DOM. The Array.from(itemsRef.value.children).map(el => el.textContent) line creates an array of the current text content of each list item, reflecting their new order after dragging. This approach should give you the current DOM state after each drag operation, which seems to be what you're looking for. Remember that while this will log the new order, it won't automatically update your list ref. If you need to keep your data in sync with the DOM, you might need to update the list ref in the onEnd callback as well. Stack Overflow: Vue Ref nolonger reactive after being returned from composable (https://stackoverflow.com/questions/77395749) provides some additional context on working with refs in Vue 3 and Nuxt 3, which might be helpful for understanding reactivity in this context. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2d ago
<@674984670156423171> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
o.m
o.mOP2d ago
@kapa.ai is this possible to use without having to call onMounted?
kapa.ai
kapa.ai2d ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Based on the knowledge sources provided and the context of your question, I can offer some insights on using Sortable without onMounted in Nuxt 3. While it's generally recommended to use onMounted for DOM manipulations, Nuxt 3 provides an alternative that might suit your needs: the onNuxtReady composable. Nuxt Docs: onNuxtReady (https://nuxt.com/docs/api/utils/on-nuxt-ready) states that this composable allows running a callback after your app has finished initializing. It only runs on the client-side and is ideal for running code that should not block the initial rendering of your app. Here's how you could potentially use onNuxtReady instead of onMounted:
<script setup lang="ts">
import { ref } from "vue";
import Sortable from "sortablejs";

const itemsRef = useTemplateRef<HTMLElement | null>("items");
const list = ref(["Item 1", "Item 2", "Item 3", "Item 4", "Item 5"]);

onNuxtReady(() => {
if (itemsRef.value) {
Sortable.create(itemsRef.value, {
animation: 150,
ghostClass: "sortable-ghost",
group: "shared",
onEnd: (evt) => {
console.log("New order:", Array.from(itemsRef.value.children).map(el => el.textContent));
}
});
}
});
</script>

<template>
<ul id="items" ref="items">
<li v-for="item in list">
{{ item }}
</li>
</ul>
</template>
<script setup lang="ts">
import { ref } from "vue";
import Sortable from "sortablejs";

const itemsRef = useTemplateRef<HTMLElement | null>("items");
const list = ref(["Item 1", "Item 2", "Item 3", "Item 4", "Item 5"]);

onNuxtReady(() => {
if (itemsRef.value) {
Sortable.create(itemsRef.value, {
animation: 150,
ghostClass: "sortable-ghost",
group: "shared",
onEnd: (evt) => {
console.log("New order:", Array.from(itemsRef.value.children).map(el => el.textContent));
}
});
}
});
</script>

<template>
<ul id="items" ref="items">
<li v-for="item in list">
{{ item }}
</li>
</ul>
</template>
This approach should initialize Sortable after the app has finished loading, without relying on onMounted. However, it's important to note that this method might not guarantee that the DOM is fully rendered in all cases. If you encounter issues, you might need to combine this with nextTick to ensure the DOM is updated:
onNuxtReady(async () => {
await nextTick();
if (itemsRef.value) {
Sortable.create(itemsRef.value, {
// ... Sortable options
});
}
});
onNuxtReady(async () => {
await nextTick();
if (itemsRef.value) {
Sortable.create(itemsRef.value, {
// ... Sortable options
});
}
});
Remember that onNuxtReady is specific to Nuxt and might not be available in a standard Vue.js application. If you're working in a pure Vue.js environment, onMounted would still be the recommended approach. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2d ago
<@674984670156423171> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Want results from more Discord servers?
Add your server