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">
Related
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>
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>
My select drop-down element contains the correct options, but on first load there is no default option selected. That means the drop-down appears blank. How can I ensure the first option in the list is selected WITHOUT resorting to hardcoded selected attribute because the data is actually dynamically loaded from a database.
Here is the JSFiddle and same below:
new Vue({
el: "#app",
data() {
return {
Form: {
TypeID: null
}
}
}
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<form>
<li>
<label for="Category">Category:</label>
<select id="Category" name="Category" v-model.number="Form.TypeID">
<option value="3">Vegetable</option>
<option value="1">Bread</option>
<option value="2">Dairy</option>
</select>
</li>
</form>
</div>
If I change the Form: { TypeID: null } code to Form: { TypeID: 1 } then Bread appears selected as default.
So given the above I thought I should try to get the first option in the select element like such:
Form: {
TypeID: document.querySelector("#Category").selectedIndex = 0,
}
But if I do that then I get an error along the lines of [Vue warn]: Error in data(): "TypeError: Cannot read property 'selectedIndex' of null"
You have to explicitly set it in Form.TypeID.
HTML selected attribute won't work as it is overwritten by Vue's v-model.
new Vue({
el: "#app",
data() {
return {
Form: {
TypeID: 3
}
}
}
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<form>
<li>
<label for="Category">Category:</label>
<select id="Category" name="Category" v-model.number="Form.TypeID">
<option value="3">Vegetable</option>
<option value="1">Bread</option>
<option value="2">Dairy</option>
</select>
</li>
</form>
</div>
A bit other way:
new Vue({
el: "#app",
data() {
return {
Form: {
TypeID: null
},
selectOptions: [{
text: 'Vegetable',
val: 3
},
{
text: 'Bread',
val: 1
},
{
text: 'Dairy',
val: 2
}
]
}
},
mounted() {
// setting the default selected option on the form
// by picking the first item in the selectOptions
// data attribute
this.Form.TypeID = this.selectOptions[0].val
}
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<form>
<li>
<label for="Category">Category:</label>
<select id="Category" name="Category" v-model.number="Form.TypeID">
<option v-for="(item, i) in selectOptions" :key="i" :value="item.val">
{{ item.text }}
</option>
</select>
</li>
</form>
</div>
With Vue you should not rely on DOM elements - only as a last resort. Create the data structure as data, computed, or anything and only render that data structure in the DOM.
Seems to work for me.
you can get the first option element and pass its value to TypeID to select it.
new Vue({
el: "#app",
data() {
return {
Form: {
TypeID: document.querySelector("#Category option:first-of-type").value
}
}
}
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<form>
<li>
<label for="Category">Category:</label>
<select id="Category" name="Category" v-model.number="Form.TypeID">
<option value="3">Vegetable</option>
<option value="1">Bread</option>
<option value="2">Dairy</option>
</select>
</li>
</form>
</div>