I'm trying to make a list item clickable. When the item is clicked the checkbox within the list item should be enabled or disabled. However it's not working the way I expect.
I've made an example:
var app = new Vue({
el: '#app',
data: {
showNav: false,
categories: [{name: 'test' }]
},
mounted() {
this.categories.forEach((category) => {
category.active = true;
});
}
})
<div id="app">
<nav class="navbar-dropdown w-full">
<ul class="list-reset">
<li class="flex justify-between items-center hover:bg-grey hover:text-white text-grey uppercase cursor-pointer p-3" v-for="category in categories" #click="category.active = !category.active">
{{ category.name }}
<input type="checkbox" class="shadow" v-model="category.active" #click="category.active = !category.active"/>
</li>
</ul>
</nav>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss/dist/tailwind.min.css" rel="stylesheet"/>
When I change this:
categories: [{name: 'test' }]
to this:
categories: [{name: 'test', active: true }]
It's working. But in my application I fetch the application with an ajax and receive the category objects without an active property.
That's why I'm doing this:
this.categories.forEach((category) => {
category.active = true;
});
But that's obviously not working. How could I fix this?
As #ohgodwhy mentioned in his comment there's an issue with the way you define a property for a category. I'm having a hard time explaining why exactly this doesn't work, although this is how you could do this:
var app = new Vue({
el: '#app',
data: {
showNav: false,
categories: [{
name: 'test'
}],
},
mounted() {
this.categories = this.categories.map((category) => {
return {
name: 'test',
active: true,
};
});
},
});
<div id="app">
<ul class="list-reset">
<li class="flex justify-between items-center hover:bg-grey hover:text-white text-grey uppercase cursor-pointer p-3" v-for="category in categories" #click="category.active = !category.active">
{{ category.name }}
<input type="checkbox" class="shadow" v-model="category.active" #click="category.active = !category.active" />
</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
I would appreciate any additions or expansions on the reason why OP has this issue.
Related
AppsTab.vue
<script>
export default {
props: {
tabList: {
type: Array,
required: true,
},
variant: {
type: String,
required: false,
default: () => "vertical",
},
},
data() {
return {
activeTab: 1,
};
},
};
</script>
<template>
<div
:class="{
'flex space-x-4': variant === 'horizontal',
}"
>
<ul
class="list-none bg-blue-900 bg-opacity-30 p-1.5 rounded-lg text-center overflow-auto whitespace-nowrap"
:class="{
'flex items-center mb-6': variant === 'vertical',
}"
>
<li
v-for="(tab, index) in tabList"
:key="index"
class="w-full px-4 py-1.5 rounded-lg"
:class="{
'text-blue-600 bg-white shadow-xl': index + 1 === activeTab,
'text-white': index + 1 !== activeTab,
}"
>
<label
:for="`${_uid}${index}`"
v-text="tab"
class="cursor-pointer block"
/>
<input
:id="`${_uid}${index}`"
type="radio"
:name="`${_uid}-tab`"
:value="index + 1"
v-model="activeTab"
class="hidden"
/>
</li>
</ul>
<template v-for="(tab, index) in tabList">
<div
:key="index"
v-if="index + 1 === activeTab"
class="flex-grow bg-white rounded-lg shadow-xl p-4"
>
<!-- <slot :name="`tabPanel-${index + 1}`" /> --> want to get data using loop inside tab
</div>
</template>
</div>
</template>
App.vue
< script >
import AppTabs from "./components/AppTabs";
export default {
components: {
AppTabs,
},
data() {
return {
tabList: ["Tab 1", "Tab 2", "Tab 3", "Tab 4"],
};
},
}; <
/script>
<template>
<div class="bg-gradient-to-r from-blue-300 to-blue-500 min-h-screen">
<app-tabs
class="w-11/12 lg:w-10/12 mx-auto"
:tabList="tabList"
variant="horizontal"
>
{{value}} // want to bind data inside tab
</app-tabs>
</div>
</template>
Expected Output
I am working on vertical tabs. Where the functionality is working fine. Here is the complete working code with static mock data https://codesandbox.io/s/vue-js-tabs-forked-we2cx?file=/src/App.vue
Now i want to create some mockdata inside of my data like 'tabList' and then, i want to display data dynamically when user clicked on tabs(including content -->tabs)
How to remove static data, which is inside slots and then only use data dynamically
To start with that, i am not sure, Where to start the looping to display data inside tabs dynamically with mock data?
You can set dynamic slot name using :slot="slotName" where slotName is a dynamic value
This can be achieved using a v-for aswell like below.
<template v-for="content in contentList" :slot="content.slot">
{{ content.content }}
</template>
Where contentList is your array something like below.
contentList: [
{ id: 1, slot: "tabPanel-1", content: "Content 1" },
{ id: 2, slot: "tabPanel-2", content: "Content 2" },
{ id: 3, slot: "tabPanel-3", content: "Content 3" },
{ id: 4, slot: "tabPanel-4", content: "Content 4" },
]
Working Fiddle
Ok, so, I am new to Vue and I am trying to make a simple to do list. I have managed to display it and stuff but I am having trouble with the code to add items to the list. When I click the button to add the task, it adds a bullet point but it doesn’t show the text given. For example, in the input box, I will type the name of a task but when I click the button, what I wrote doesn’t show up, just the bullet point.
I have tried putting the newTask part in other places but the same problem happens. I know this is probably a pretty silly question and the solution is probably pretty obvious but please help as fast as you can, I need to do this for school.
Here is my HTML:
<body>
<div id="app">
<!-- Vue App HTML Code -->
<h1>To Do List</h1>
<div id="app">
<ul>
<li v-for="x in tasks">
{{ x.text }}
</li>
</ul>
</div>
<div id="newTask">
<input type="text" value="taskName" placeholder="Task Name" v-model="newTask"></input>
<button v-on:click="tasks.push(newTask)">Add Task</button>
</div>
</body>
And my JavaScript/ Vue:
myObject = new Vue({
el: '#app',
data: {
tasks: [
{ text: '1' },
{ text: '2' },
{ text: '3' },
],
newTask: ''
},
})
I would really appreciate any other Vue tips (relevant or not) because it is my first week learning it and anything would be really useful.
You can achieve this by pushing the newTask in the existing tasks array.
Working Demo :
var vm = new Vue({
el: '#app',
data: {
tasks: [
{ text: '1' },
{ text: '2' },
{ text: '3' },
],
newTask: ''
},
methods: {
addTask() {
this.tasks.push({ text: this.newTask })
this.newTask = '';
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h1>To Do List</h1>
<ul>
<li v-for="x in tasks">
{{ x.text }}
</li>
</ul>
<input type="text" placeholder="Task Name" v-model="newTask"/>
<button v-on:click="addTask">Add Task</button>
</div>
I'm new in Vuejs and I want to change the selected tab of nav on click event I trying using function but console throw an error:
vue.runtime.global.js:8392 Uncaught TypeError: _ctx.changeTab is not a
function
CodePen
What I want to do, is to on #click event run a function that change selected tab and show content depending on the selected tab in a single paragraph element
Code:
<template>
<div>
<div class="sm:hidden">
<label for="tabs" class="sr-only">Select a tab</label>
<select id="tabs" name="tabs" class="block w-full focus:ring-indigo-500 focus:border-indigo-500 border-gray-300 rounded-md">
<option v-for="tab in tabs" :key="tab.name" :selected="tab.current">{{ tab.name }}</option>
</select>
</div>
<div class="hidden sm:block">
<nav class="flex space-x-4" aria-label="Tabs" :class="bg-gray-600">
<a v-for="tab in tabs" #click="changeTab(tab)" :key="tab.name" :href="tab.href" :class="[tab.current ? 'bg-purple-700 text-white' : 'text-purple-700 hover:text-gray-700', 'px-12 py-2 font-medium text-sm rounded-full font-bold text-lg']" >
{{ tab.name }}
</a>
</nav>
</div>
</div>
</template>
<script>
const tabs = [
{ id: 1 , name: 'LOREM', href: '#test1', current: false },
{ id: 2, name: 'IPSUM', href: '#test2', current: false },
{ id: 3, name: 'PDF', href: '#test3', current: true },
]
export default {
setup() {
return {
tabs,
}
function changeTab(selectedTab){
let test = this.tabs.find(selectedTab.id);
console.log(test)
}
},
}
</script>
<style>
nav {
width: max-content;
display: flex;
gap: 20px;
background: #E5E5E5;
border-radius: 20px;
}
</style>
How can I achieve this? Regards
Move your array to setup function, make it reactive with ref or reactive:
const { ref } = Vue
const app = Vue.createApp({
setup() {
const tabs = ref([
{ id: 1 , name: 'LOREM', href: '#test1', current: false },
{ id: 2, name: 'IPSUM', href: '#test2', current: false },
{ id: 3, name: 'PDF', href: '#test3', current: true },
])
const changeTab = (selectedTab) => {
tabs.value.map(t => {
t.id === selectedTab.id ? t.current = true : t.current = false
});
}
return { tabs, changeTab }
},
})
app.mount('#demo')
nav {
width: max-content;
display: flex;
gap: 20px;
background: #E5E5E5;
border-radius: 20px;
}
<script src="https://unpkg.com/vue#3/dist/vue.global.prod.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/1.0.5/tailwind.min.css">
<div id="demo">
<div>
<div class="">
<nav class="flex space-x-4 bg-gray-600" aria-label="Tabs" >
<a v-for="tab in tabs" #click="changeTab(tab)" :key="tab.name" :href="tab.href" :class="[tab.current ? 'bg-purple-700 text-white' : 'text-purple-700 hover:text-gray-700', 'px-12 py-2 font-medium text-sm rounded-full font-bold text-lg']" >
{{ tab.name }}
</a>
</nav>
</div>
<div v-for="tab in tabs" #click="changeTab(tab)" :key="tab.name" :href="tab.href" class="px-12" :class="[tab.current || 'hidden']">
{{ tab.id }} - {{ tab.name }} - {{ tab.href }}
</div>
</div>
</div>
const app = new Vue({
el: "#app",
name: 'aselect',
data: {
value: 'Select a Fruit',
list: ["Orange", "Apple", "Kiwi", "Lemon", "Pineapple"],
visible: false
},
methods: {
toggle() {
this.visible = !this.visible;
},
select(option) {
this.value = option;
}
}
})
<div id="app">
<h1>Custom Select Dropdown</h1>
<div class="aselect" :data-value="value" :data-list="list">
<div class="selector" #click="toggle()">
<div class="label">
<span>{{ value }}</span>
</div>
<div class="arrow" :class="{ expanded : visible }"></div>
<div :class="{ hidden : !visible, visible }">
<ul>
<li :class="{ current : item === value }" v-for="item in list" #click="select(item)">{{ item }}</li>
</ul>
</div>
</div>
</div>
</div>
I am using the reference from https://www.npmjs.com/package/vue-click-outside
This is my codepen link https://codepen.io/santoshch/pen/gOmvvmN In the codepen link, i have a dropdown, where after toggling down the dropdown i am unable to close the dropdown list.
So i have searched for some reference i vuejs, And finally found npm package called vue-click-outside, Itried to place event but not sure how to proceed.
I found out a solution to your problem. Follow below steps
At first Add box class to every element that lies inside the box that toggle the dropdown
<div id="app">
<h1>Custom Select Dropdown</h1>
<div class="aselect" :data-value="value" :data-list="list">
<div class="selector box" #click="toggle()">
<div class="label box">
<span class="box">{{ value }}</span>
</div>
<div class="arrow box" :class="{ expanded : visible }"></div>
<div :class="{ hidden : !visible, visible }">
<ul>
<li :class="{ current : item === value }" v-for="item in list" #click="select(item)">{{ item }}</li>
</ul>
</div>
</div>
</div>
</div>
Then add click listener to window in vue.js
const app = new Vue({
el: "#app",
name: 'aselect',
data: {
value: 'Select a Fruit',
list: ["Orange","Apple","Kiwi", "Lemon", "Pineapple"],
visible: false
},
methods: {
toggle() {
this.visible = !this.visible;
},
select(option) {
this.value = option;
},
handleClick(e){
const classname = e.target.className;
if(this.visible && !classname.includes("box")){
this.visible = false;
}
}
},
created () {
window.addEventListener('click', this.handleClick);
},
destroyed () {
window.removeEventListener('click', this.handleClick);
},
})
Check this pen: https://codepen.io/salim-hosen/pen/xxqYYMQ
Background: I have a list of checkboxes that is bound to a names array. I am trying to change the class of the specific name once the checkbox is clicked.
Problem: Once a checkbox is clicked it changes the class of all the names instead of the specific name attached to the checkbox.
JSFiddle of the issue:
JSFiddle
HTML
<div id="app">
<ul>
<li v-for="name in names" :key="index">
<input #click="available = !available" type="checkbox">
<label :class="{available:available}" >{{name.name}}</label>
</li>
</ul>
</div>
Vue instance
var app = new Vue({
el: '#app',
data: {
available: false,
names: [{'name':'Jerry'},{'name':'Eddie'},{'name':'Kerry'},{'name':'Jane'}]
}
})
Css
.available{
text-decoration: line-through;
}
Ad the available variable to each name object and use a method to update the available property:
var app = new Vue({
el: '#app',
data: {
names: [
{'name':'Jerry', 'available': false},
{'name':'Eddie', 'available': false},
{'name':'Kerry', 'available': false},
{'name':'Jane', 'available': false}
]
},
methods: {
updateAvailable(index) {
// Update the available property on the specific object with its index
this.names[index].available = !this.names[index].available
}
}
})
Then in your template, call the method updateAvailable:
<div id="app">
<ul>
<li v-for="(name, index) in names" :key="index">
<input #click="updateAvailable(index)" type="checkbox">
<label :class="{available: name.available}" >{{name.name}}</label>
</li>
</ul>
</div>
Move the available property in to each name element and toggle name.available in your template. You can even use v-model on your checkboxes.
const names = [{'name':'Jerry'},{'name':'Eddie'},{'name':'Kerry'},{'name':'Jane'}]
const app = new Vue({
el: '#app',
data: () => ({
names: names.map(name => ({ ...name, available: false }))
})
})
.available {
text-decoration: line-through;
}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<div id="app">
<ul>
<li v-for="(name, i) in names">
<input :id="`name_${i}`" v-model="name.available" type="checkbox">
<label :for="`name_${i}`" :class="{ available: name.available }">
{{name.name}}
</label>
</li>
</ul>
</div>