I'm trying to figure what best practice in this example. I have an FAQ component that takes in a prop called questions which is an array of objects with property question and answer. The answers are hidden in an accordion and i'm creating a button that expands the accordion to also show the answer. However, I am not sure what the best approach to handle this. I need to add a property let's call it isExpanded. How would I do that? I thought about just creating a ref and JSON.parse/JSON.stringify to clone the prop, but is that really best practice?
const props = defineProps({
questions: {
type: Array as () => {
question: string;
answer: string;
}[],
default: () => [],
},
});
You are thinking in a correct way, Just add a property isExpanded in each questions object with default value as false and then on click on accordion, make it true for that specific accordion on which user clicked.
Live Demo :
new Vue({
el: '#app',
data() {
return {
questions: [
{
id: 1,
question: "Question 1",
answer: "Answer 1",
isExpanded: false,
},
{
id: 2,
question: "Question 2",
answer: "Answer 2",
isExpanded: false,
},
{
id: 3,
question: "Question 3",
answer: "Answer 3",
isExpanded: false,
}
]
}
},
methods: {
toggleExpand(item) {
item.isExpanded = !item.isExpanded;
}
}
});
#app {
padding: 10px;
font-family: "Inconsolata", monospace;
box-sizing: border-box;
}
.card {
width: 80%;
height: auto;
display: block;
position: relative;
margin: 8px 0;
padding: 0 10px;
border: 1px solid #aaa;
border-radius: 4px;
}
.card-header,
.card-content {
margin: 10px 0;
}
.card-header {
cursor: pointer;
}
.card-header span {
font-weight: 600;
}
.card-body {
height: auto;
}
.icon {
float: right;
}
hr {
margin: 0;
height: 1px;
display: block;
border-width: 0;
border-top: 1px solid #aaa;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js"></script>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inconsolata&display=swap"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css"/>
<div id="app">
<div class="card"
v-for="item in questions"
:key="item.id">
<div class="card-header"
#click.prevent="toggleExpand(item)">
<span>{{ item.question }}</span>
<div class="icon">
<i class="fas fa-arrow-down" v-if="item.isExpanded"></i>
<i class="fas fa-arrow-up" v-if="!item.isExpanded"></i>
</div>
</div>
<div class="card-body" v-if="item.isExpanded">
<hr />
<div class="card-content">{{ item.answer }}</div>
</div>
</div>
</div>
Related
I have read many question and articles suggesting to use me emit,props but I am not able to figure it out. Below is my code.
I have an array of products which contains details of product and I want to add those items to cart component with their quantity and display products name in cart.
Container.vue
<template>
<div class="container pb-130">
<div class="d-flex">
<product></product>
<cartData></cartData>
</div>
</div>
</template>
<script>
import product from "#/components/product.vue";
import cartData from "../components/cartData.vue";
export default {
name: "Container",
components: {
product,
cartData,
},
};
</script>
<style>
.container {
max-width: 1280px;
margin: 0 auto;
}
.pb-130 {
padding-bottom: 130px;
}
</style>
product.vue
<template>
<div v-for="product in products" :key="product.id" class="product-item">
<img :src="product.img" alt="Product image" />
<div class="product-content">
<div class="product-head">
<h6 class="product-title">{{ product.name }}</h6>
<span
>By<span class="owner">{{ product.owner }}</span></span
>
</div>
<div class="product-footer">
<div class="price">
<span>Price</span>
<span class="val">{{ product.val }}</span>
</div>
<div class="btns">
<button
class="remove-tocart"
#click="
updateCart(product, 'subtract');
removeFromCart(product);
"
>
-
</button>
<span class="quantity">{{ product.quantity }}</span>
<button
class="add-tocart"
#click="
updateCart(product, 'add');
addToCart(product);
takeToCart(product);
"
>
+
</button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
products: [
{
id: 1,
name: "One Tribe Black Edition",
img: "https://enftymart.themenio.com/img/nft-lg.8f26d1a6.jpg",
val: "14.99",
owner: "ZeniconStudio",
quantity: 0,
},
{
id: 2,
name: "One Tribe Black Edition",
img: "https://miro.medium.com/max/2000/1*AJrLFnuCAD8dE1p1Bg0dbg.jpeg",
val: "15.99",
owner: "ZeniconStudio",
quantity: 0,
},
{
id: 3,
name: "One Tribe Black Edition",
img: "https://creativereview.imgix.net/content/uploads/2021/09/F4E079D612B9653BEFC4D8D2F39781E39A3025C693B177A61D6C73A5156248EA.jpg?auto=compress,format&q=60&w=1200&h=849",
val: "14.99",
owner: "ZeniconStudio",
quantity: 0,
},
{
id: 4,
name: "One Tribe Black Edition",
img: "https://coffeebros.com/wp-content/uploads/2021/10/astronaut-background.jpg",
val: "14.99",
owner: "ZeniconStudio",
quantity: 0,
},
{
id: 5,
name: "One Tribe Black Edition",
img: "https://cloudfront-us-east-1.images.arcpublishing.com/coindesk/5NOWWNNEBRER7BXFZKCYRCA7NA.jpg",
val: "14.99",
owner: "ZeniconStudio",
quantity: 0,
},
{
id: 6,
name: "One Tribe Black Edition",
img: "https://static01.nyt.com/images/2021/08/15/fashion/TEEN-NFTS--fewocious/TEEN-NFTS--fewocious-videoSixteenByNineJumbo1600.jpg",
val: "14.99",
owner: "ZeniconStudio",
quantity: 0,
},
],
cartItems: [],
};
},
methods: {
updateCart(product, updateType) {
for (let i = 0; i < this.products.length; i++) {
if (this.products[i].id === product.id) {
if (updateType === "subtract") {
if (this.products[i].quantity !== 0) {
this.products[i].quantity--;
}
} else {
this.products[i].quantity++;
}
break;
}
}
},
addToCart(product) {
this.cartItems.push(product);
},
removeFromCart(product) {
this.cartItems.splice(this.cartItems.indexOf(product), 1);
},
takeToCart(product) {
this.$emit("receiveInCart", product);
},
},
};
</script>
<style>
.product-item {
position: relative;
box-shadow: 0 1px 10px rgb(24 24 24 / 7%);
flex: 1 0 calc(100% / 3 - 60px);
}
.product-item {
margin: 0 15px 15px;
}
.product-item img {
height: 245px;
width: 100%;
object-fit: cover;
}
.product-item .product-content {
padding: 15px;
}
.product-item .product-content .product-head {
margin-bottom: 15px;
text-align: initial;
}
.product-item .product-content .product-title {
font-size: 18px;
}
.product-item .product-content .product-head span,
.product-item .product-content .product-footer .price {
color: #c5c5c5;
font-size: 14px;
}
.product-item .product-content .product-head .owner,
.product-item .product-content .product-footer .val {
color: #000;
font-size: 16px;
margin-left: 5px;
}
.product-item .product-content .product-footer .val {
margin-left: 0;
font-weight: 700;
position: relative;
}
.product-item .product-content .product-footer .val::before {
content: "$";
}
.product-item .product-content .product-footer {
display: flex;
justify-content: space-between;
align-items: center;
}
.product-item .product-content .product-footer .price {
display: flex;
flex-direction: column;
}
.add-tocart,
.remove-tocart {
background-color: #fff;
border: 1.5px solid #000;
color: #000;
text-decoration: none;
padding: 0px 10px;
font-size: 20px;
transition: 0.5s;
line-height: 30px;
}
.add-tocart:hover,
.remove-tocart:hover {
color: #fff;
background-color: #000;
cursor: pointer;
}
.btns {
display: flex;
align-items: center;
justify-content: space-between;
width: 80px;
}
</style>
Here is the component where I need data of added item in cart.
cartData.vue
<template>
<div class="cartData" #receiveInCart="storeData">
<h1>Your cart</h1>
<span class="title">{{ item.name }}</span>
</div>
</template>
<script>
export default {
data() {
return {
cartData: [],
};
},
methods: {
storeData(data) {
this.cartData = data;
},
},
};
</script>
<style>
.cartData {
flex-basis: 100%;
margin: 0 15px;
box-shadow: 0 1px 10px rgb(24 24 24 / 7%);
}
</style>
You can use vuex and dispatch action in product component for changing cart data, and with getter display cart data in cartData component. Here is codesandbox with simple solution.
i have three components icons.vue which contains icons and dropdown also and this component is the child component of DisplayNotes.vue, Now when a user clicks on any card DeleteNote-option(which present inside of icons.vue)that card id and content should be passed to the another component DeleteNote.vue,How to pass the particular clicked card[visit my output img]1 data to the DeleteNote.vue component,please help me to fix this issue
icons.vue
<template>
<div class="footer">
<i class="fas fa-bell"></i>
<i class="fas fa-user"></i>
<i class="fas fa-palette"></i>
<i clss="fas fa-image"></i>
<i class="fas fa-archive"></i>
<div class="dropdown">
<i #click="myFunction();" class="fas fa-ellipsis-v"></i>
<div ref="myDropdown" class="dropdown-content">
DeleteNote
ChangeLabel
Add drawing
Make a Copy
Show Checkboxes
</div>
</div>
</div>
</template>
<script>
export default {
methods: {
myFunction(event) {
this.$refs.myDropdown.classList.toggle("show");
return event;
// document.getElementById("myDropdown").classList.toggle("show");
}
}
}
</script>
<style scoped>
.footer i {
opacity: 0.9;
position: relative;
}
.footer .fa-bell {
margin-top: 5px;
margin-left: 10px;
}
.footer .fa-user {
margin-top: 5px;
margin-left: 40px;
}
.footer .fa-palette {
margin-top: 5px;
margin-left: 40px;
}
.footer .fa-image {
margin-top: 5px;
margin-left: 40px;
}
.footer .fa-archive {
margin-top: 5px;
margin-left: 40px;
}
.footer .fa-ellipsis-v {
margin-top: 5px;
margin-left: 40px;
cursor: pointer;
}
.dropbtn {
background-color: white;
color: white;
padding: 16px;
font-size: 14px;
font-family: 'Times New Roman', Times, serif;
border: none;
cursor: pointer;
}
.dropbtn:hover,
.dropbtn:focus {
background-color: #2980B9;
}
.dropdown {
position: relative;
display: inline-block;
}
.dropdown-content {
margin-left: 40%;
display: none;
position: absolute;
background: white;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
z-index: 1;
}
.dropdown-content a {
color: black;
padding: 8px 17px;
text-decoration: none;
display: block;
}
.dropdown-content a:hover {
background-color: rgb(241, 234, 234)
}
.show {
display: block;
}
</style>
DisplayNotes.vue
<template>
<div class="carddisplay-section">
<div v-for="note in notes" :key="note.id" id="blur" class="container note">
<div #click="toggle(note.id)" class="card-content">
<h5>{{note.title}}</h5>
<p>{{note.body}}</p>
</div>
<div class="import-icons">
<icons class="imported-icons note-icons" />
<button v-if="flag" class="card-button" type="button" #click="handlesubmit();Togglebtn();">Close</button>
</div>
</div>
<div id="popup">
<UpdateNotes :cardId="clickedCard" :cardContent="cardContent" />
</div>
</div>
</template>
<script>
import service from '../service/User'
import icons from './icons'
import UpdateNotes from './UpdateNotes.vue'
export default {
name: 'DisplayNotes',
components: {
icons,
UpdateNotes
},
data() {
return {
flag: true,
notes: [{
id: 1,
title: 'Fundoo',
body: 'unlimited notes..'
}, ],
clickedCard: '',
cardContent: {},
}
},
methods: {
Togglebtn() {
this.flag = !this.flag;
},
async handlesubmit() {
service.userDisplayNotes().then(response => {
this.notes.push(...response.data);
})
},
toggle(id) {
var blur = document.getElementById('blur');
blur.classList.toggle('active');
this.clickedCard = id;
// this.card.content = this.notes.filter((note) => note.id === id);
var popup = document.getElementById('popup');
popup.classList.toggle('active');
},
}
}
</script>
<style lang="scss">
#import "#/styles/DisplayNotes.scss";
</style>
DeleteNote.vue[i want o pass the clicked card id(click of DeleteNote inside dropdown inside icons.vue)]
<template>
<div v-if="flag==false" class="update">
<form class="update-note" #submit.prevent autocomplete="off">
<input name="title" v-model="title" placeholder="Title" />
<textarea name="content" v-model="body" style="resize: none" placeholder="Take a note..." rows="3"></textarea>
<div class="btm-icons">
<icons />
<button id="btn-section" type="submit" #click="handlesubmit();flip();">Close</button>
</div>
</form>
</div>
</template>
<script>
import icons from './icons.vue'
import service from '../service/User'
export default {
components: {
icons
},
props: ['cardId', 'cardContent'],
data() {
return {
title: '',
body: '',
flag: false,
}
},
created() {
this.title = this.cardContent.title;
this.body = this.cardContent.body;
},
methods: {
flip() {
this.flag = !this.flag;
},
async handlesubmit() {
let userData = {
id: this.cardId,
title: this.title,
body: this.body
}
service.userUpdateNotes(userData).then(response => {
alert("Note updated successfully");
return response;
}).catch(error=>{
alert("Error ");
return error;
})
},
}
}
</script>
<style lang="scss" scoped>
#import "#/styles/UpdateNotes.scss";
</style>
router.js[routing path for deleteNote.vue]
{
path:'/trash',
component:DeleteNote
},
You need to activate props in your routes
{
path: '/trash',
component: DeleteNote,
name: 'DeleteNote',
props: true
},
Pass props to the icons component. From the icons component the pass the cardId and cardContent to the DeleteNote component using router-link.
if i hover on a card one it displays the icons of every card but i want to display icons on a particular hovering card (ouput of my card-image).These cards are automatically generated by using v-for and fetch the data from axios package,DisplayNotes.vue file responsibility is to show the notes to the user in the cards ,please help me to fix this issue.`
[DisplayNotes.vue]
<template>
<div class="main-section">
<div v-for="note in notes" :key="note.data" class="container">
<div class="card-content">
<h5>{{note.title}}</h5>
<p><i>{{note.body}}</i></p>
</div>
<div #mouseover="hover=true" #mouseleave="hover=false" class="import-icons">
<icons v-if="hover" />
<button type="button" #click="handlesubmit()">close</button>
</div>
</div>
</div>
</template>
<script>
import service from '../service/User'
import icons from './icons'
export default {
components: {
icons
},
data() {
return {
hover: false,
notes: [{
id: 1,
title: 'Fundoo',
body: 'unlimited Notes...'
}, ],
}
},
methods: {
async handlesubmit() {
const response = await axios.get('/displayNotes', {});
localStorage.getItem('token', response.data.token);
this.notes.push(response.data);
},
}
}
</script>
<style lang="scss">
.card-content {
input {
border: none;
}
textarea {
border: none;
outline: none;
}
}
/* dividing the width percentage */
.container {
height: 200px;
width: 25%;
float:left;
margin: -2.98%;
margin-left:20%;
margin-top: 5%;
border-style: ridge;
}
.import-icons {
display: block;
margin-left: -2%;
padding-top: 25%;
button {
border: none;
background: none;
float: right;
font-weight: 600;
font-family: Arial, Helvetica, sans-serif;
margin-top: -2%;
padding-left: 400px;
}
}
</style>
[icons.vue]
<template>
<div class="used-icons">
<i id="first-icon" class="fas fa-bell"></i>
<i id="second-icon" class="fas fa-user"></i>
<i id="third-icon" class="fas fa-palette"></i>
<i id="forth-icon" class="fas fa-archive"></i>
<!-- <i id="fifth-icon" class="fas fa-ellipsis-v"></i> -->
</div>
</template>
<style scoped>
#first-icon {
opacity: 0.9;
}
#second-icon {
padding-left: 30px;
padding-right: 30px;
opacity: 0.9;
}
#third-icon {
opacity: 0.9;
}
#forth-icon {
padding-left: 30px;
padding-right: 30px;
opacity: 0.9;
}
#fifth-icon {
padding-right: 195px;
opacity: 0.9;
}
</style>
All the items are conditionally rendered on the same hover property, so whenever that property is true (when an item is hovered), all items are shown instead of only the hovered one.
One way to fix this is to add hover to each notes[] array element, and use that to conditionally render them:
<div v-for="note in notes">
<div #mouseover="note.hover=true" #mouseleave="note.hover=false">
<icons v-if="note.hover" />
</div>
</div>
export default {
data() {
return {
// hover: false, // remove this
notes: [
{
id: 1,
title: 'Fundoo',
body: 'unlimited Notes...',
hover: false, // add this
},
{
id: 2,
title: 'Fundoo',
body: 'unlimited Notes...'
hover: false, // add this
},
],
}
},
}
To add hover property to new notes[] array elements in handlesubmit():
export default {
methods: {
async handlesubmit() {
//...
this.notes.push({
...response.data,
hover: false,
})
}
}
}
According to your implementation I consider you add 'hover' property to each card and then manipulate it in event handlers.
<template>
<div class="main-section">
<div v-for="(note, index) in notes" :key="note.data" class="container">
<div class="card-content">
<h5>{{note.title}}</h5>
<p><i>{{note.body}}</i></p>
</div>
<div #mouseover="note[index].hover=true" #mouseleave="note[index].hover = false" class="import-icons">
<icons v-if="hover" />
<button type="button" #click="handlesubmit()">close</button>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
hover: false,
notes: [{
id: 1,
title: 'Fundoo',
body: 'unlimited Notes...',
hover: false
}, ],
}
},
methods: {
async handlesubmit() {
const response = await axios.get('/displayNotes', {});
localStorage.getItem('token', response.data.token);
this.notes.push(response.data);
},
}
}
</script>
You can do this with only CSS, no JavaScript required.
Add a note class to the note container and note-icons to the icons element.
Then with some simple css we can conditionally show the note-icons on hover.
.note-icons {
visibility: hidden;
}
.note:hover .note-icons
visibility: visible;
}
Full Snippet
<template>
<div class="main-section">
<div v-for="note in notes" :key="note.data" class="container note"> <!-- ⭐️ -->
<div class="card-content">
<h5>{{note.title}}</h5>
<p><i>{{note.body}}</i></p>
</div>
<div class="import-icons">
<icons class="note-icons"/> <!-- ⭐️ -->
<button type="button" #click="handlesubmit()">close</button>
</div>
</div>
</div>
</template>
<script>
import service from '../service/User'
import icons from './icons'
export default {
components: {
icons
},
data() {
return {
hover: false,
notes: [{
id: 1,
title: 'Fundoo',
body: 'unlimited Notes...'
}, ],
}
},
methods: {
async handlesubmit() {
const response = await axios.get('/displayNotes', {});
localStorage.getItem('token', response.data.token);
this.notes.push(response.data);
},
}
}
</script>
<style lang="scss">
.card-content {
input {
border: none;
}
textarea {
border: none;
outline: none;
}
}
/* dividing the width percentage */
.container {
height: 200px;
width: 25%;
float:left;
margin: -2.98%;
margin-left:20%;
margin-top: 5%;
border-style: ridge;
}
.import-icons {
display: block;
margin-left: -2%;
padding-top: 25%;
button {
border: none;
background: none;
float: right;
font-weight: 600;
font-family: Arial, Helvetica, sans-serif;
margin-top: -2%;
padding-left: 400px;
}
}
.note-icons { /* ⭐️ */
visibility: hidden;
}
.note:hover .note-icons { /* ⭐️ */
visibility: visible;
}
</style>
i have two components DisplayNotes.vue which is responsible for displaying notes on dashboard wthe response is coming from backend(displayed as a cards),And next component is icons.vue(responsible for icons) in this icons when i click on more-icon(3 dots-icon)[see option img]1 it should open dropdown options,if i click on DeleteNote option i want to get that particular clicked card id based on that id i have to pass that id to my API-url, i am trying to do by using props but it's not hitting proper URl (id is something diff like #7%..)[check here]2.i am unable to figure out where did i mistake ,please help me to fix this issue
user.js
userTrashNote(data){
return axios.userTrash(`/deleteNote/${data.id}`,data);
}
icons.vue
<template>
<div class="footer">
<i class="fas fa-bell"></i>
<i class="fas fa-user"></i>
<i class="fas fa-palette"></i>
<i clss="fas fa-image"></i>
<i class="fas fa-archive"></i>
<div class="dropdown">
<i #click="myFunction();" class="fas fa-ellipsis-v"></i>
<div ref="myDropdown" class="dropdown-content">
<!-- when user click on DeleteNote i have to get that cardid -->
<a #click="handlesubmit();">DeleteNote</a>
<a >ChangeLabel</a>
</div>
</div>
</div>
</template>
<script>
import service from '../service/User'
export default {
props: ['cardId'],
data() {
return {
clickedCard: '',
}
},
methods: {
myFunction(event) {
this.$refs.myDropdown.classList.toggle("show");
return event;
// document.getElementById("myDropdown").classList.toggle("show");
},
async handlesubmit() {
let userData = {
id: this.cardId,
}
service.userTrashNote(userData).then(response => {
console.log("details",this.cardId);
alert("Note deleted successfully");
return response;
})
},
}
}
</script>
<style scoped>
.footer i {
opacity: 0.9;
position: relative;
}
.footer .fa-bell {
margin-top: 5px;
margin-left: 10px;
}
.footer .fa-user {
margin-top: 5px;
margin-left: 40px;
}
.footer .fa-palette {
margin-top: 5px;
margin-left: 40px;
}
.footer .fa-image {
margin-top: 5px;
margin-left: 40px;
}
.footer .fa-archive {
margin-top: 5px;
margin-left: 40px;
}
.footer .fa-ellipsis-v {
margin-top: 5px;
margin-left: 40px;
cursor: pointer;
}
.dropbtn {
background-color: white;
color: white;
padding: 16px;
font-size: 14px;
font-family: 'Times New Roman', Times, serif;
border: none;
cursor: pointer;
}
.dropbtn:hover,
.dropbtn:focus {
background-color: #2980B9;
}
.dropdown {
position: relative;
display: inline-block;
}
.dropdown a{
cursor:pointer;
}
.dropdown-content {
margin-left: 40%;
display: none;
position: absolute;
background: white;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
z-index: 1;
}
.dropdown-content a {
color: black;
padding: 8px 17px;
text-decoration: none;
display: block;
}
.dropdown-content a:hover {
background-color: rgb(241, 234, 234)
}
.show {
display: block;
}
</style>
DisplayNotes.vue
<template>
<div class="carddisplay-section">
<div v-for="note in notes" :key="note.id" id="blur" class="container note">
<div #click="toggle(note.id)" class="card-content">
<h5>{{note.title}}</h5>
<p>{{note.body}}</p>
</div>
<div class="import-icons">
<icons class="imported-icons note-icons" :cardId="clickedCard" />
<button v-if="flag" class="card-button" type="button" #click="handlesubmit();Togglebtn();">Close</button>
</div>
</div>
<div id="popup">
<UpdateNotes :cardId="clickedCard" :cardContent="cardContent" />
</div>
</div>
</template>
<script>
import service from '../service/User'
import icons from './icons'
import UpdateNotes from './UpdateNotes.vue'
export default {
name: 'DisplayNotes',
components: {
icons,
UpdateNotes
},
data() {
return {
flag: true,
notes: [{
id: 1,
title: 'Fundoo',
body: 'unlimited notes..'
}, ],
clickedCard: '',
cardContent: {},
}
},
methods: {
Togglebtn() {
this.flag = !this.flag;
},
async handlesubmit() {
service.userDisplayNotes().then(response => {
this.notes.push(...response.data);
})
},
toggle(id) {
var blur = document.getElementById('blur');
blur.classList.toggle('active');
this.clickedCard = id;
// this.card.content = this.notes.filter((note) => note.id === id);
var popup = document.getElementById('popup');
popup.classList.toggle('active');
},
}
}
</script>
<style lang="scss">
#import "#/styles/DisplayNotes.scss";
</style>
userTrashNote(data){
return axios.userTrash("/deleteNote/${data.id}",data);
}
This is wrong, use back ticks
userTrashNote(data){
return axios.userTrash(`/deleteNote/${data.id}`,data);
}
Ok so now thats out of the way, Why are you changing the card id on focus? either create a new component and pass it the note so it can handle itself or pass the id on delete.
<template>
<div class="carddisplay-section">
<div v-for="note in notes" :key="note.id" id="blur" class="container note">
<div #click="toggle(note.id)" class="card-content">
<h5>{{note.title}}</h5>
<p>{{note.body}}</p>
</div>
<div class="import-icons">
<icons class="imported-icons note-icons" :cardId="note.id" />
<button v-if="flag" class="card-button" type="button" #click="handlesubmit();Togglebtn();">Close</button>
</div>
</div>
<div id="popup">
<UpdateNotes :cardId="clickedCard" :cardContent="cardContent" />
</div>
</div>
</template>
See how ive now passed <icons class="imported-icons note-icons" :cardId="note.id" /> the note.id instead of relying on a method to set it.
I have problem with checkboxes and vue filter of array.
new Vue({
el: "#app",
data: {
todos: [
{ text: "Learn JavaScript"},
{ text: "Learn Vue"},
{ text: "Play around in JSFiddle"},
{ text: "Build something awesome"}
],
search: '',
},
methods: {
},
computed: {
filtered() {
return this.todos.filter(todo => {
return todo.text.toLowerCase().includes(this.search.toLowerCase())
})
},
}
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
del {
color: rgba(0, 0, 0, 0.3);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input type="text" v-model="search">
<ol>
<li v-for="todo in filtered">
<label>
<input type="checkbox">
<del v-if="todo.done">
{{ todo.text }}
</del>
<span v-else>
{{ todo.text }}
</span>
</label>
</li>
</ol>
</div>
If you check first from array and search for any of others:
Check -> Learn javascript
Search -> Learn Vue
Vue appear to be checked..
Is that suppose to work like that?
How can I remove all from displayed list and append same time?
Use v-model to bind in filtered array
new Vue({
el: "#app",
data: {
todos: [
{ text: "Learn JavaScript"},
{ text: "Learn Vue"},
{ text: "Play around in JSFiddle",done:true},
{ text: "Build something awesome"}
],
search: '',
},
methods: {
},
computed: {
filtered() {
return this.todos.filter(todo => {
return todo.text.toLowerCase().includes(this.search.toLowerCase())
})
},
}
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
del {
color: rgba(0, 0, 0, 0.3);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input type="text" v-model="search">
<ol>
<li v-for="todo in filtered">
<label>
<input v-model="todo.done" type="checkbox">
<del v-if="todo.done">{{ todo.text }}</del>
<span v-if="!todo.done">{{ todo.text }}</span>
</label>
</li>
</ol>
</div>
Here is put checked by default for Play around in JSFiddle
Simply just add done: false in todos and add v-model="todo.done" to input in v-for.
Example on JSFiddle
Differences from your code:
// added `done`
todos: [
{ done: false, text: "Learn JavaScript"},
{ done: false, text: "Learn Vue"},
{ done: false, text: "Play around in JSFiddle"},
{ done: false, text: "Build something awesome"}
]
<!-- added `v-model="todo.done"` -->
<input v-model="todo.done" type="checkbox">