I'm using the Vue.Draggable component in my Vue application and I need to make a condition so that I can validate whether or not the element I'm dragging can reach it's destination. However, I am unable to find the "destination/target" element when I drag and drop an element. Is there any way to find out what the target element is?
The 'nos' structure is an array that receives the data of each element and inside each node there may or may not be child nodes (this may or may not have to be validated).
Follow the code below:
<template>
<div>
<draggable class="draggable-list" :list="nos" :group="{name:'blocos_texto_draggable'}" :move="onMove">
<div col mx-2 px-2 py-3 bg-light border-rounded
v-for="no in nos"
:key="no.identificador"
:style="no.nivel != 1 ? 'margin-left: 20px;' : 'margin-left: 0px'"
class="div-conteudo"
v-on="calcularOrdem(no, nos)"
>
<fieldset>
<span v-on:click="noClicado(no)">
<legend>
{{estaExpandido(no) ? '▼' : '►'}}
<span v-if="no.tipo === 'parte'">Parte</span> <!-- DEVE CONTER 'LIVROS' E/OU 'TEMÁTICAS' E/OU 'ARTIGOS' -->
<span v-if="no.tipo === 'livro'">Livro</span> <!-- DEVE CONTER 'TÍTULOS' E/OU 'TEMÁTICAS' E/OU 'ARTIGOS' -->
<span v-if="no.tipo === 'titulo'">Título</span> <!-- DEVE CONTER 'CAPÍTULOS' E/OU 'TEMÁTICAS' E/OU 'ARTIGOS' -->
<span v-if="no.tipo === 'capitulo'">Capítulo</span> <!-- DEVE CONTER 'SEÇÃO(ÕES)' E/OU 'TEMÁTICAS' E/OU 'ARTIGOS' -->
<span v-if="no.tipo === 'secao'">Seção</span> <!-- DEVE CONTER 'SUBSEÇÃO(ÕES)' E/OU 'TEMÁTICAS' E/OU 'ARTIGOS' -->
<span v-if="no.tipo === 'subsecao'">Subseção</span> <!-- DEVE CONTER 'TEMÁTICAS' E/OU 'ARTIGOS' -->
<span v-if="no.tipo === 'tematica'">Temática</span> <!-- DEVE CONTER 'ARTIGOS' -->
<span v-if="no.tipo === 'artigo'">Artigo</span> <!-- PODE CONTER 'PARÁGRAFOS' E/OU 'INCISOS' -->
<span v-if="no.tipo === 'paragrafo'">Parágrafo</span> <!-- PODE CONTER 'INCISOS' -->
<span v-if="no.tipo === 'inciso'">Inciso</span> <!-- PODE CONTER 'ALÍNEAS' -->
<span v-if="no.tipo === 'alinea'">Alínea</span> <!-- PODE CONTER 'ITENS' -->
<span v-if="no.tipo === 'item'">Item</span> <!-- NÃO CONTÉM FILHOS -->
<span v-if="no.tipo === 'epigrafe'">Epígrafe</span> <!-- NÃO CONTÉM FILHOS -->
<span v-if="no.tipo === 'ementa'">Ementa</span> <!-- NÃO CONTÉM FILHOS -->
<span v-if="no.tipo === 'preambulo'">Preâmbulo</span> <!-- NÃO CONTÉM FILHOS -->
<span v-if="no.tipo === 'pontilhado'">Pontilhado</span> <!-- NÃO CONTÉM FILHOS -->
</legend>
<table>
<tr>
<td class="blocoTexto" style="width: 96%;">
<div v-html="no.texto"/>
</td>
</tr>
</table>
</span>
</fieldset>
<BlocoTextoArvore
v-if="no.expandido == true"
:nos="no.consultas_blocos_texto_attributes"
:nivel="nivel + 1"
:bloco_editado="bloco_editado"
#onClick="(no) => $emit('onClick', no)"
/>
</div>
</draggable>
</div>
</template>
<script>
import draggable from "vuedraggable";
export default {
name: "BlocoTextoArvore",
props: {
nos: Array,
bloco_editado: Object,
nivel: {
type: Number,
default: 1,
},
expandido: Boolean,
},
components: {
draggable,
},
methods: {
onMove: function(evt) {
let elementoArrastado = evt.draggedContext.element;
console.log(elementoArrastado)
},
estaExpandido(no) {
return no.expandido;
},
noClicado(no) {
this.$set(no, 'expandido', !no.expandido)
},
calcularOrdem(no, nos) {
no.nivel = this.nivel;
no.ordem = nos.indexOf(no) + 1;
}
},
};
</script>
I'm trying to use :move="onMove" property to find the data of the target, by I can't find it. It returns me only the data of the dragged element.
Related
The for loop is working properly. When I add a new task panel shows but the {{task}} variable inside the component is not showing. It must be something with the component template.
<span class="col-span-3 bg-blue-200 p-2">{{task}}</span>
I have left all the code down here maybe is something that I don't see.
Any idea? Thanks
<body>
<div id="app">
<task-input></task-input>
</div>
<script>
let app = Vue.createApp({ });
app.component(
'task-input',
{
template:
`<div class=" container grid grid-cols-4 mb-5 border-2 border-gray-600 center mt-5 mx-auto bg-gray-400 ">
<input id="taskInput" v-model="task" class="bg-white col-span-3 p-3 text-black font-bold" type="text" placeholder="What you will do next" />
<button #click="addTask()" class="text-white font-extrabold uppercase">Add new task</button>
</div>
<div class="container container mx-auto rounded-top-lg">
<div class=" bg-gray-200 border-2 border-gray-600 center column-1 container mx-auto mt-5 mx-auto rounded-top-lg">
<h1 class="font-sans text-2xl text-center text-white bg-gray-500 uppercase font-extrabold px-4 py-4">
{{title}}
</h1>
<ul class="bg-white">
<task-panel v-for="task in tasks"/>
</ul>
</div>
</div>`,
data() {
return {
title:"Here is a nice title",
task: '',
tasks: [],
}
},
components:['task-panel'],
methods:{
addTask(){
this.tasks.push(this.task);
this.task='';
console.log(this.tasks);
}
}
},
);
app.component('task-panel',{
template:
`<li class="grid bg-gray-200 mt-1">
<div class="grid grid-cols-4">
<span class="col-span-3 bg-blue-200 p-2">{{task}}</span>
<span class="col-span-1 text-center self-center uppercase font-bold">test</span>
</div>
<div class="flex justify-end bg-gray-300 p-1">
<button class="bg-blue-500 text-white px-3 py-1 rounded-md m-1 uppercase font-bold">To Do</button>
<button class="bg-green-500 text-white px-3 py-1 rounded-md m-1 uppercase font-bold">Done</button>
<button class="bg-red-500 text-white px-3 py-1 rounded-md m-1 uppercase font-bold">Blocked</button>
</div>
</li>
`,
data() {
return { }
},
props: ['tasks', 'modelValue'],
computed:{
tasks:{
get(){
return this.tasks;
}
}
}
});
app.mount('#app');
</script>
</body>
The v-for is only in the scope of the parent component. The v-for's iterator prop does not get automatically passed into the task-panel.
You need to explicitly bind the iterator prop to task-panel's prop:
👇
<task-panel v-for="task in tasks" :task="task" />
Also, the prop in task-panel should have the same name. It's currently spelled tasks (with an s at the end). The last s should be removed so that it matches what the template is rendering:
// props: ['tasks', ⋯],
props: ['task', ⋯],
<script src="https://unpkg.com/vue#3.2.31/dist/vue.global.js"></script>
<script src="https://cdn.tailwindcss.com"></script>
<div id="app">
<task-input></task-input>
</div>
<script>
let app = Vue.createApp({ });
app.component(
'task-input',
{
template:
`<div class=" container grid grid-cols-4 mb-5 border-2 border-gray-600 center mt-5 mx-auto bg-gray-400 ">
<input id="taskInput" v-model="task" class="bg-white col-span-3 p-3 text-black font-bold" type="text" placeholder="What you will do next" />
<button #click="addTask()" class="text-white font-extrabold uppercase">Add new task</button>
</div>
<div class="container container mx-auto rounded-top-lg">
<div class=" bg-gray-200 border-2 border-gray-600 center column-1 container mx-auto mt-5 mx-auto rounded-top-lg">
<h1 class="font-sans text-2xl text-center text-white bg-gray-500 uppercase font-extrabold px-4 py-4">
{{title}}
</h1>
<ul class="bg-white">
<task-panel v-for="task in tasks" :task="task" />
</ul>
</div>
</div>`,
data() {
return {
title:"Here is a nice title",
task: '',
tasks: [],
}
},
components:['task-panel'],
methods:{
addTask(){
this.tasks.push(this.task);
this.task='';
console.log(this.tasks);
}
}
},
);
app.component('task-panel',{
template:
`<li class="grid bg-gray-200 mt-1">
<div class="grid grid-cols-4">
<span class="col-span-3 bg-blue-200 p-2">{{task}}</span>
<span class="col-span-1 text-center self-center uppercase font-bold">test</span>
</div>
<div class="flex justify-end bg-gray-300 p-1">
<button class="bg-blue-500 text-white px-3 py-1 rounded-md m-1 uppercase font-bold">To Do</button>
<button class="bg-green-500 text-white px-3 py-1 rounded-md m-1 uppercase font-bold">Done</button>
<button class="bg-red-500 text-white px-3 py-1 rounded-md m-1 uppercase font-bold">Blocked</button>
</div>
</li>
`,
data() {
return { }
},
props: ['task', 'modelValue'],
});
app.mount('#app');
</script>
In my vue laravel application ...i have dynamicllay added some select option by onclick function.
For the intial select option select2 is working fine but when i am trying to added more field dynamically the select 2 is not working . i have used (npm install v-select2-component --save )
but unfortunatlley does not work
<script>
import Select2 from 'v-select2-component';
export default {
components: {Select2},
data(){
return{
event_Category_Remove: [],
index: 0,
eventsElement_id: [],
}
},
methods:{
addEvent() {
this.eventsElement_id = [];
this.event_Category_Remove.push({
id: this.index,
name: "ecr" + this.index,
});
this.index++;
},
/** ========= Remove Event ========= */
removeEvent(index) {
this.event_Category_Remove.splice(index, 1);
},
}
</script>
<template>
<div
class="
form-group
row
without-form-background
mb-2
"
>
<label class="col-md-2 label-control" for="weight"
>Event (can be multiple)</label
>
<a class="text-primary" #click="addEvent">
<i>Add</i> <i class="fa fa-plus"></i>
</a>
</div>
<!-- ======== Adding Multiple Event Button End ======== -->
<!-- ///////////////////// -->
<!-- ======== Event Start ======== -->
<div
class="event_Category_Remove"
v-for="(ecr, index) in event_Category_Remove"
:key="ecr.id"
:id="'eventChild_' + index"
>
<div
class="
form-group
row
without-form-background
mb2
"
>
<label class="col-md-2 label-control" for="name"
>Event</label
>
<div class="col-md-10">
<select
:name="'event_' + index"
id=""
class="form-control"
>
<option
name="event"
v-for="event in event"
:key="event.id"
:value="event.id"
:selected="event.id == event_selected"
>
{{ event.name }}
</option>
</select>
</div>
</div>
<!-- ======== Event Ends ======== -->
<!-- ////////////////////// -->
<!-- ======== Category Start ======== -->
<div
class="
form-group
row
without-form-background
mb2
"
>
<label class="col-md-2 label-control" for="name"
>Category</label
>
<div class="col-md-10">
<Select2
:name="'category[]_' + index"
id=""
class="form-control multiselect"
multiple="multiple"
tabindex="-1"
selected
value="cate.id"
>
<option
v-for="cate in categoryarr"
:key="cate.id"
:value="cate.id"
:selected="
categoryarr_selected.includes(
String(cate.id)
)
"
>
{{ cate.title }}
</option>
</Select2>
</div>
</div>
<!-- ======== Category End ======== -->
<!-- /////////////// -->
<!-- ======== Remove Button1 Start ======== -->
<div
class="form-group without-form-background mb2"
>
<button
class="btn btn-danger text-white"
#click="removeEvent(ecr.id)"
>
Remove
</button>
<hr class="bg-danger" />
</div>
</div>
</template>
I am trying to create a simple survey builder with Vue3 and Vue Draggable. All is going well until I try to create a multiple choice question. This type of questions has its own sortable list of possible answers. When I add another multiple choice question it then pulls from the same list which makes sense but I have tried to use a v-if to check the parents ID to match the choice ID..
Basically if I add a new choice it adds to the all multiple choice questions, which makes sense, but how to I keep it to the current item I am in?
Any ideas? I know the code is mess, it will be refactored once it works.
<template>
<div class="p-4">
<div class="container mx-auto rounded-md grid grid-cols-12 gap-4 h-full">
<div class="col-span-4 p-3 flex flex-col min-h-screen bg-gray-200 shadow-md rounded-md">
<div class="text-lg font-bold w-full bg-blue-600 text-white rounded-md p-2 mb-4">Builder your survey</div>
<div class="sticky top-4">
<div class="text-lg font-bold">Components</div>
<draggable
class="p-2 rounded-md"
:list="componentsList"
:group="{ name: 'questions', pull: 'clone', put: false, sort: false }"
:clone="cloneItem"
sort: false
#change="log"
item-key="id"
>
<template #item="{ element }">
<div
class="bg-gray-300 p-4 rounded-md mt-2 shadow-sm hover:shadow-md cursor-pointer border border-blue-800 border-dashed"
>
{{ element.name }}
</div>
</template>
</draggable>
</div>
</div>
<div class="col-span-8 flex p-3 flex-col bg-white shadow-md rounded-md">
<div class="text-lg font-bold pt-4">Survey</div>
<draggable
class="w-full h-full border border-blue-400 rounded-md p-2 flex flex-col flex-1"
:list="questionsList"
group="questions"
#change="log"
handle=".handle"
itemKey="name + index"
>
<template #item="{ element, index }">
<div>
<div v-if="element.name == 'Single Line of Text'" class="bg-gray-300 p-2 rounded-md mt-2 mb-2 shadow-lg hover:shadow-md">
<div class="w-full text-sm text-left">{{ element.name }} {{element.id}}</div>
<div class="flex justify-between items-center p-2 bg-gray-200 rounded-md mb-4">
<div class="w-10 font-bold hidden">Q{{ index + 1 }}</div>
<div class="w-full pr-4">
<input
type="text"
class="w-full p-2 bg-transparent flex-grow"
placeholder="Question title here..."
v-model="element.text"
/>
</div>
<div class="flex ">
<div class="cursor-pointer">
<i class="handle las la-arrows-alt la-2x mr-2"></i>
</div>
<div #click="remove(index)">
<i class="las la-trash-alt text-red-800 la-2x cursor-pointer"></i>
</div>
</div>
</div>
<div>
<input
type="text"
class="w-full p-2 rounded-md border border-gray-400"
placeholder="User response will go here"
/>
</div>
<div class="text-left flex justify-between items-center p-2 bg-gray-200 rounded-md mt-2">
<div class="flex items-center">
<div><input type="checkbox" class="mr-2" /></div>
<div>Required?</div>
</div>
</div>
</div>
<!-- START problem area -->
<div v-else-if="element.name == 'Multiple Choice'" class="bg-gray-300 p-2 rounded-md mt-2 mb-2 shadow-lg hover:shadow-md">
<div class="w-full text-sm text-left">{{ element.name }} {{element.id}}</div>
<div class="flex justify-between items-center p-2 bg-gray-200 rounded-md mb-4">
<div class="w-10 font-bold hidden">Q{{ index + 1 }}</div>
<div class="w-full pr-4">
<input
type="text"
class="w-full p-2 bg-transparent flex-grow"
placeholder="Question title here..."
v-model="element.text"
/>
</div>
<div class="flex ">
<div class="cursor-pointer">
<i class="handle las la-arrows-alt la-2x mr-2"></i>
</div>
<div #click="remove(index)">
<i class="las la-trash-alt text-red-800 la-2x cursor-pointer"></i>
</div>
</div>
</div>
<div class="flex items-center ">
<draggable
class="p-2 rounded-md w-full"
:list="multipleChoiceList"
:group="{ name: 'choice', pull: false, put: false, sort: true }"
sort: true
handle=".handle"
#change="log"
item-key="question"
>
<template #item="{ element }">
<div
class="bg-blue-100 p-4 flex items-center justify-start rounded-md mt-2 shadow-sm hover:shadow-md cursor-pointer w-full"
>
<div class="flex items-center flex-grow"
>
<input type="checkbox" class="w-6 h-6">
<input
type="text"
class="p-2 bg-transparent flex-grow"
placeholder="Add choice here"
v-model="element.text"
/>
</div>
<div class="flex ">
<div class="cursor-pointer">
<i class="handle las la-arrows-alt la-1x mr-2"></i>
</div>
<div #click="remove(index)">
<i class="las la-trash-alt text-red-800 la-1x cursor-pointer"></i>
</div>
</div>
</div>
</template>
<template #footer>
<div>
<button class="p-2 bg-blue-300 mt-2 rounded-md" #click="addChoice(element.id)">Add</button>
</div>
</template>
</draggable>
</div>
<div class="text-left flex justify-between items-center p-2 bg-gray-200 rounded-md mt-2">
<div class="flex items-center">
<div><input type="checkbox" class="mr-2" /></div>
<div>Required?</div>
</div>
</div>
</div>
<!-- END problem area -->
<div v-else-if="element.name == 'Open Ended'" class="bg-gray-300 p-2 rounded-md mt-2 mb-2 shadow-lg hover:shadow-md">
<div class="w-full text-sm text-left">{{ element.name }} {{element.id}}</div>
<div class="flex justify-between items-center p-2 bg-gray-200 rounded-md mb-4">
<div class="w-10 font-bold hidden">Q{{ index + 1 }}</div>
<div class="w-full pr-4">
<input
type="text"
class="w-full p-2 bg-transparent flex-grow"
placeholder="Question title here..."
v-model="element.text"
/>
</div>
<div class="flex ">
<div class="cursor-pointer">
<i class="handle las la-arrows-alt la-2x mr-2"></i>
</div>
<div #click="remove(index)">
<i class="las la-trash-alt text-red-800 la-2x cursor-pointer"></i>
</div>
</div>
</div>
<div>
<textarea
class="h-32 w-full w-full p-2 rounded-md border border-gray-400"
></textarea>
</div>
<div class="flex items-center">
<div>Max Length</div>
<div>
<input
type="number"
class="mr-2 w-20 border border-gray-400 p-2 rounded-md ml-2"
/>
</div>
</div>
<div class="text-left flex justify-between items-center p-2 bg-gray-200 rounded-md mt-2">
<div class="flex items-center">
<div><input type="checkbox" class="mr-2" /></div>
<div>Required?</div>
</div>
</div>
</div>
<div v-else-if="element.name == 'Divider'">
<div class="flex items-center">
<div class="flex-grow border-t border-black mx-4"> </div>
<div class="flex ">
<div class="cursor-pointer">
<i class="handle las la-arrows-alt la-2x mr-2"></i>
</div>
<div #click="remove(index)">
<i class="las la-trash-alt text-red-800 la-2x cursor-pointer"></i>
</div>
</div>
</div>
</div>
</div>
</template>
</draggable>
</div>
</div>
</div>
</template>
See Clone method which assigns a random number as the id
<script>
import draggable from "vuedraggable";
export default {
name: "Survey",
components: {
draggable,
},
data() {
return {
drag: false,
componentsList: [
{ name: "Single Line of Text", type: "question", text: "", id: 1 },
{ name: "Multiple Choice", type: "question", text: "", id: 2 },
{ name: "Matrix", type: "question", text: "", id: 3 },
{ name: "Open Ended", type: "question", text: "", id: 4 },
{ name: "Divider", type: "component", id: 9 },
],
questionsList: [],
multipleChoiceList: [
{text: "text A", type:"choice", question:"32"},
{text: "text B", type:"choice", question:"1"},
{text: "text A", type:"choice", question:"2"} ]
};
},
methods: {
onEnd: function(evt) {
console.log(evt);
},
log: function(evt) {
console.log(evt);
},
addChoice(id) {
this.multipleChoiceList.push({ text: "Choice " + id, type: "choice", question:id });
console.log(this.multipleChoiceList);
},
remove(index) {
this.questionsList.splice(index, 1);
},
cloneItem({ id, name, type }) {
return {
name: name,
id: Math.ceil(Math.random()*100),
text: "",
type: type,
};
}
},
mounted() {
// console.log("mounted");
},
};
</script>
https://github.com/SortableJS/Vue.Draggable/issues/687#issuecomment-1153083717
I just answered to a similar question on github.
Not sure would this help as Vue.Draggable and vue.draggable.next is slightly different.
I have a working on a Responsive yes/no questionnaire where user can select either yes/no on each of the posed questions.
I want each questionCard component to have a radio-button group (yes/no). The radio-circles should be hidden and only label should be visible. Clicking on the label should select the appropiate option.
ALL THIS WORKS
My issue comes in when I re-size the window! The layout changes appropietly but the radio selection is gone.
Any Ideas how I can keep the selection regardless the window size?
CodeSandbox
App.vue
<template>
<parent-component />
</template>
<script>
import parentComponent from "./components/parentComponent.vue";
export default {
name: "App",
components: {
parentComponent,
},
};
</script>
<style>
</style>
Parent.vue
<template>
<div>
<question-card
v-for="car in objectData.cars.data"
:key="car.id"
:carData="car"
></question-card>
</div>
</template>
<script>
import questionCard from "./questionCard.vue";
export default {
name: "App",
components: {
questionCard,
},
data() {
return {
objectData: {
cars: {
data: [
{
id: 1,
name: "Do You Like Tesla?",
},
{
id: 2,
name: "Do You Like BMW?",
},
{
id: 3,
name: "Do You Like AUDI?",
},
],
},
},
};
},
};
</script>
Questioncard.vue
<template>
<br />
<br />
<div class="hidden sm:block">
<h1>Lage Screen</h1>
<h2 class="font-bold">{{ carData.name }}</h2>
<div class="flex items-center justify-center">
<input
#change="onChange($event)"
type="radio"
:name="carData.id"
:id="carData.id + 'yes'"
/>
<label
:for="carData.id + 'yes'"
class="border text-center border-yellow-500 rounded-2xl w-11/12 py-0.5 hover:bg-red-500 hover:text-white hover:border-green-300"
>
<span>Yes</span>
</label>
</div>
<div class="flex items-center justify-center">
<input
#change="onChange($event)"
type="radio"
:name="carData.id"
:id="carData.id + 'no'"
/>
<label
:for="carData.id + 'no'"
class="border text-center border-yellow-500 rounded-2xl w-11/12 py-0.5 hover:bg-red-500 hover:text-white hover:border-green-300"
>
<span>No</span>
</label>
</div>
</div>
<div class="sm:hidden">
<h1>Small Screen</h1>
<h2 class="font-bold">{{ carData.name }}</h2>
<div class="flex items-center w-1/2 justify-center">
<input
#change="onChange($event)"
type="radio"
:name="carData.id"
:id="carData.id + 'yes'"
/>
<label
:for="carData.id + 'yes'"
class="border text-center border-yellow-500 rounded-2xl w-11/12 py-0.5 hover:bg-red-500 hover:text-white hover:border-green-300"
>
<span>Yes</span>
</label>
</div>
<div class="flex items-center w-1/2 justify-center">
<input
#change="onChange($event)"
type="radio"
:name="carData.id"
:id="carData.id + 'no'"
/>
<label
:for="carData.id + 'no'"
class="border text-center border-yellow-500 rounded-2xl w-11/12 py-0.5 hover:bg-red-500 hover:text-white hover:border-green-300"
>
<span>No</span>
</label>
</div>
</div>
</template>
<script>
export default {
props: ["carData"],
data() {
return {
selected: null,
};
},
methods: {
onChange(event) {
this.selected = event.target.value;
},
},
};
</script>
<style scoped>
input[type="radio"] {
display: none;
}
input[type="radio"]:checked + label {
background-color: #78be20;
}
</style>
I see you are using TailwindCSS. You can control the sizes with w-1/2 sm:w-full on the elements
You don't need different input for the different screen sizes. Like this
<div class="">
<h1>Any size Screen</h1>
<h2 class="font-bold">{{ carData.name }}</h2>
<div class="flex items-center justify-center w-1/2 sm:w-full">
<input
#change="onChange($event)"
type="radio"
:name="carData.id"
:id="carData.id + 'yes'"
/>
<label
:for="carData.id + 'yes'"
class="border text-center border-yellow-500 rounded-2xl w-11/12 py-0.5 hover:bg-red-500 hover:text-white hover:border-green-300"
>
<span>Yes</span>
</label>
</div>
<div class="flex items-center justify-center w-1/2 sm:w-full">
<input
#change="onChange($event)"
type="radio"
:name="carData.id"
:id="carData.id + 'no'"
/>
<label
:for="carData.id + 'no'"
class="border text-center border-yellow-500 rounded-2xl w-11/12 py-0.5 hover:bg-red-500 hover:text-white hover:border-green-300"
>
<span>No</span>
</label>
</div>
</div>
I have a Nuxt application where I've installed vue-scrollactive as a plugin.
I am using it on a child page (ie website.com/company). If I do a fresh load of website.com/company the plugin works fine - however, if I load the site from another page (ie website.com or website.com/about) using nuxt-link then the scrollactive plugin does not work.
UPDATE:
It appears to be something to do with the fetchState and the main tag appearing on v-else. I tested with dummy data using fetch and it worked.
plugins/scrollActive.js
import Vue from 'vue'
import scrollactive from 'vue-scrollactive'
Vue.use(scrollactive)
nuxt.config.js
plugins: [{ src: '~/plugins/scrollActive' }],
pages/company.vue
<div class="flex flex-col h-screen bg-gray-100">
<TheAppNavbar :company="company" />
<!-- Subnav -->
<scrollactive
:offset="30"
:highlight-first-item="true"
scroll-container-selector="#data-area"
class="block h-16 overflow-x-auto border-b dark:border-gray-600 md:hidden bg-gray-50 dark:bg-gray-800 scrollbars-hidden my-nav"
>
<div class="inline-flex items-center h-full text-lg">
<a
v-for="category in categories"
:key="category"
:href="`#${category}`"
class="flex items-center h-full text-gray-500 capitalize scrollactive-item dark:text-gray-400'"
>
<span v-if="publicCat(category)" class="mx-4 sm:mx-8">{{
category
}}</span>
</a>
</div>
</scrollactive>
<!-- Bottom section -->
<div class="flex flex-1 min-h-0">
<!-- Narrow sidebar-->
<scrollactive
:offset="30"
:highlight-first-item="true"
scroll-container-selector="#data-area"
aria-label="Sidebar"
class="hidden bg-gray-800 dark:bg-white w-28 md:flex md:flex-col md:overflow-y-auto scrollbars-hidden my-nav"
>
<div class="relative flex flex-col px-2 mt-4 space-y-2">
<a
v-if="publicCat('sports')"
href="#sports"
class="flex scrollactive-item"
>
<span class="mt-2">Sports</span>
</a>
<a
v-if="publicCat('finance')"
href="#finance"
class="flex scrollactive-item"
>
<span class="mt-2">Finance</span>
</a>
</div>
</scrollactive>
<!-- Main area -->
<div v-if="$fetchState.pending">
Loading
</div>
<div v-else-if="$fetchState.error">
An error occurred :(
</div>
<main
v-else
id="data-area"
>
<section
v-for="cat in categories"
:id="cat"
:key="cat"
aria-labelledby="primary-heading"
class="flex flex-col flex-1"
>
<div v-if="company[cat].public === true">
<div id="section-header">
<h2>
{{ cat }}
</h2>
<p v-if="formattedDate(cat) !== null">
Updated:
{{ formattedDate(cat) }}
</p>
</div>
<CompanySports
v-if="cat === 'sports'"
class="pb-20 sm:pt-8"
:financials="company.sports"
/>
<CompanyFinance
v-if="cat === 'finance'"
class="pb-20 sm:pt-8"
:financials="company.finance"
/>
</div>
</section>
<a
:href="`https://${company.website}`"
target="_blank"
>Visit Website
</a>
</main>
</div>
</div>
<script>
...
methods: {
publicCat(cat) {
if (this.company[cat]) {
if (this.company[cat].public === true) {
return true
} else {
return false
}
}
},
formattedDate(cat) {
if (this.company[cat].updated) {
const date = new Date(this.company[cat].updated.seconds * 1000)
return date.toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
})
}
return null
},
},
</script>
It was a bit hacky but I changed the main area without the v-else and added
v-if="$fetchState.pending === false" and :class="company === {} ? 'hidden' : 'block'" to a div that enclosed the area with data. Works for now but not ideal.
<!-- Main area -->
<div v-if="$fetchState.pending">
Loading
</div>
<div v-else-if="$fetchState.error">
An error occurred :(
</div>
<main
id="data-area"
>
<section
v-for="cat in categories"
:id="cat"
:key="cat"
aria-labelledby="primary-heading"
class="flex flex-col flex-1"
>
<div
v-if="$fetchState.pending === false && company[cat].public === true"
:class="company === {} ? 'hidden' : 'block'"
>
<div id="section-header">
<h2>
{{ cat }}
</h2>
<p v-if="formattedDate(cat) !== null">
Updated:
{{ formattedDate(cat) }}
</p>
</div>
<CompanySports
v-if="cat === 'sports'"
class="pb-20 sm:pt-8"
:financials="company.sports"
/>
<CompanyFinance
v-if="cat === 'finance'"
class="pb-20 sm:pt-8"
:financials="company.finance"
/>
</div>
</section>
<a
v-if="$fetchState.pending === false"
:class="company === {} ? 'hidden' : 'block'"
:href="`https://${company.website}`"
target="_blank"
>Visit Website
</a>
</main>