Blocks are created through a loop, there is a select in each block. Tell me how when clicking on a button, take the selected values from all created selects?
I tried join ref to select, and v-model, but not one of them is working properly
<div v-for="attribute in attributes" class="col">
{{ attribute.name }}
<select ref="selectedVariation" class="form-control">
<option selected>---</option>
<option v-for="variation in attribute.variations"
:key="variation.id"
:value="variation.id">
{{ variation.name }}
</option>
</select>
</div>
<button class="btn btn-success" #click="addItemToCart()">Test</button>
Hi Данил and welcome to stack overflow. There's not enough detail in the question to provide an exact solution, but the following hints might get you started. Also, there are several different approaches that could work; this is just one possibility.
First, include a property in the attributes objects that can be used to track the selected value, perhaps calling it .selected.
data: {
attributes: [
{name: "Name 1", selected: null, variations: [/*...*/]},
{name: "Name 2", selected: null, variations: [/*...*/]},
// ...
]
}
Second, tell Vue about that property using the v-model directive:
<select
class="form-control"
v-model="attribute.selected"
>
Then, when the button is clicked, the code can simply read the appropriate values:
methods: {
addItemToCart() {
// get an array of variation.id values
selectedArray = this.attributes.map(attribute => attribute.selected);
}
}
Related
<template>
<div id="app">
<span v-if="isLoaded" class="select">
<select v-model="selectNum" name="text">
<option value="" selected="selected">status</option>
<option value="ok">ok</option>
<option value="notok">notok</option>
<option value="medium">medium</option>
</select>
</span>
<span class="search-wrapper">
<span class="bar">
<input
type="text"
v-model="search"
placeholder="filter"
class="s-bar"
/>
</span>
</span>
<div v-for="user in users" :key="user.id">
{{ user.name }}
<div v-for="list in lists" :key="list.id">
{{ list.pan }}
</div>
</div>
</div>
</template>
<script>
import { userdata } from "../assets/userdata";
import { listdata } from "../assets/listdata";
export default {
name: "HelloWorld",
data: function () {
return {
users: userdata,
lists: listdata,
search: "",
isLoaded: false,
selectNum: "",
};
},
created() {
this.isLoaded = true;
},
computed: {
sourceInfo() {
function compare(a, b) {
if (a.name < b.name) return -1;
if (a.name > b.name) return 1;
return 0;
}
const res = this.userList
.filter((user) => {
return user.name.toLowerCase().includes(this.search.toLowerCase());
})
.sort(compare);
if (this.selectNum) {
return res.filter((user) => user.status === this.selectNum);
}
return res;
},
},
};
</script>
Initially the user data will be loaded completely. Later based on two filters, i.e., One for search filter, I should filter the array out of all user array. second one, for drop down based on status in User array, I need to filter the array.
How do i make my code changes in order to work it correctly. at present it is not filtering the array either from search or from dropdown. But just displaying the data.
There are multiple changes required to make this example functioning.
First, you need to update what you are displaying. Instead of the list that you have now, I suggest to just print out the variable sourceInfo, which will contain the filtered list. Therefore, add somewhere to the HTML part
{{ sourceInfo }}
After this change, you should already get an error message in the console, because the content of sourceInfo is now in use and thus, finally evaluated. The message goes something around:
[Vue warn]: Error in render: "TypeError: this.userList is undefined"
So, you need to change this.userList to this.users which is an actual variable and contains the list of users:
const res = this.users.filter((user) => ...
And another error pops up:
[Vue warn]: Error in render: "TypeError: user.name.toLowerCase().includes(...).sort is not a function"
This one comes from applying the sort() function on a boolean, which is expected to be returned by the includes() function. Thus, as a last step, remove the sort() part of the filter which checks that the user matches the text search criteria, and apply it before returning the result:
const res = this.users.filter((user) => {
return user.name.toLowerCase().includes(this.search.toLowerCase());
});
...
return res.sort(compare);
The basic functionality should work by now. When checking your filters of the dropdown, you might notice that for nok an empty array is returned even though one user has the corresponding status. This comes from the fact, that the dropdown element nok has the value notok assigned. Therefore, by simply changing the value to nok you're good to go.
<option value="nok">nok</option>
Here is the link to a codesandbox of the running code: https://codesandbox.io/s/vue-sort-problem-hgdm7?file=/src/components/HelloWorld.vue
I know that "v-if" must avoid with "v-for" but not sure about "v-show" because it is just to toggle the display attribute.
This is the code in case anyone wants to know. Basically, I try to switch 3 different types of filter list. The code runs fine but I just wanna know if it should be avoid like "v-if".
<template>
<button
v-for="(filter, index) in filterList" :key="index"
#click="chosenFilter = filter.name"
>
{{ filter.name }}
</button>
<div
v-for="(filter, index) in filterList" :key="index"
v-show="chosenFilter === filter.name"
>
<div v-for="(listItem, index) in filter.list" :key="index">
{{ listItem }}
</div>
</div>
</template>
<script>
data () {
return {
filterList: [
{ name: 'Type 1', list: [] },
{ name: 'Type 2', list: [] },
{ name: 'Type 3', list: [] }
],
chosenFilter: 'Type 1'
}
}
</script>
From the official style guide: https://v2.vuejs.org/v2/style-guide/#Avoid-v-if-with-v-for-essential
There are 2 points in which it's not a good practice to use that, the 2nd one is interesting: To avoid rendering a list if it should be hidden. This one is basically fine since you're not doing heavy JS rendering, just basic CSS toggling.
So yeah, I'd say it's correct to have a v-show (and ESlint is not complaining btw).
But IMO, you can solve this kind of behavior in pretty much all cases with a computed: your filter button could be selected with an ID and your list rendering could be filtered with a filter here.
Replace #click="chosenFilter = filter.name" with #click="chooseFilter and get the ID (thanks to $event) of the item you've clicked on, then filter your list with the selected filter.
I have a cascading select (two part select) where the options in the second dropdown are determined by the value of the first dropdown. I do this by having a computed property which is based off of the first select. This then feeds the options into the second select. This mostly works fine.
The problem I'm having is if I have selected an option in the second select (which through v-model sets the value of the bound variable in Vue), and then I change the value of the first select. The options for the second select then update, and in that second select I appear to be selected to the empty option. However, the bound variable still has the previously selected value. I'm assuming this is because updating the option values for the second select doesn't actually trigger an input or change event so v-model doesn't respond to anything. I suppose I could fix this with a watcher, but I was hoping for a more elegant solution.
Coded example is here: https://codepen.io/Slotheroo/pen/ajwNKO/
JS/Vue:
new Vue({
el: '#app',
data: {
selectedFruit: null,
selectedVariety: null,
fruits: {
"apples": [
{
name: "honeycrisp",
madeBy: "applebees",
},
{
name: "macintosh",
madeBy: "the steves",
},
{
name: "gala",
madeBy: "ac/dc",
},
{
name: "pink lady",
madeBy: "Alecia Beth Moore",
},
],
"pears": [
{
name: "d'anjou",
madeBy: "Maya D'Anjoulou",
},
{
name: "bartlett",
madeBy: "Anton Yelchin",
}
],
},
},
computed: {
fruitVarieties: function() {
return this.fruits[this.selectedFruit]
}
},
});
HTML:
<div id="app">
<div>
<select v-model="selectedFruit">
<option value=""></option>
<option v-for="fruitName in Object.keys(fruits)" :value ="fruitName">{{fruitName}}</option>
</select>
</div>
<select v-model="selectedVariety">
<option value=""></option>
<option v-for="fruitVariety in fruitVarieties" :value="fruitVariety">{{ fruitVariety.name }}</option>
</select>
<div>
</div>
<p>Selected variety: {{ selectedVariety }}</p>
</div>
Steps to reproduce:
Select 'apples' in the first select
Select 'honeycrisp' in the second select
Select 'pears' or 'blank' in the first select
Hoped for result
selectedVariety returns to null
Actual result
selectedVariety still equals honeycrisp
I'd add an on-change handler to the first <select> to empty the selectedVariety when the selection changes...
<select v-model="selectedFruit" #change="selectedVariety = null">
https://codepen.io/anon/pen/JByEwy
Another option would be to add a watch on selectedFruit but Vue generally recommends using event handlers.
if you're using version 3.0.0, there is some feature with :reset-on-options-change='true'
e.g
<v-select required :options="filterKaryawan.unit.options" :reset-on-options-change='true' v-model="filterKaryawan.unit.selected" placeholder="placeholder" >
<template #search="{attributes, events}">
<input
class="vs__search"
v-bind="attributes"
v-on="events"
:required="filterKaryawan.unit.selected"
/>
</template>
</v-select>
The computed propertive is actually a watcher. So just put the reset value code in it.
computed: {
fruitVarieties: function() {
this.selectedVariety = null;
return this.fruits[this.selectedFruit]
}
}
Example based on Aurelia doc.
Page code:
export class MyPage {
products = [
{ id: 0, name: 'Motherboard' },
{ id: 1, name: 'CPU' },
{ id: 2, name: 'Memory' },
];
selectedProduct = null;
}
Page HTML:
<label>
Select product:<br/>
<select value.bind="selectedProduct">
<option model.bind="null">Choose...</option>
<option repeat.for="product of products"
model.bind="product">
${product.id} - ${product.name}
</option>
</select>
</label>
<div if.bind="selectedProduct">
Selected product 1: ${selectedProduct.id} - ${selectedProduct.name}
<div if.bind="selectedProduct.id > 0">
Selected product 2: ${selectedProduct.id} - ${selectedProduct.name}
</div>
</div>
When selecting CPU, then selecting null value, then selecting Memory, Selected product 1 is updated correctly with a value from a select element, but Selected product 2 is stuck with a CPU value.
How to bind selected value correctly inside the inner div?
In my application, I want to be able to display a content of selected item. Depending on an item type, I have a several <div if.bind="item.type === N">...</div> elements in order to display different HTML for each type of an item.
Note: binding doesn't work with newest packages, but works fine when I assign specific versions to the following packages in my package.json:
"aurelia-templating": "1.4.2"
"aurelia-templating-binding": "1.3.0"
"aurelia-templating-resources": "1.4.0"
"aurelia-templating-router": "1.1.0"
I have an object containing questions data.
I'm looping through these in the view and then aiming to update the objects 'answer' value.
The questions come from an API and are structured as:
[
{
"id": 1,
"choices": [
// choices
],
"created_at": "2016-12-08 09:19:30",
"updated_at": "2016-12-09 15:29:14",
"answer": []
},
]
They don't come from the API with an answer value but I have added it in the js file.
I then show the question answers in another loop:
<div v-for="(choice, index) in question.choices" class="input-row">
<input type="radio" v-model="question.answer" value="choice.value"/>
</div>
I then out the answer into the view:
#{{ question.answer }}
I can see it's an empty array, but when selecting the radio button the array isn't updated like I thought it would. Any ideas?
Your input have wrong markup to bind the value with a Vue data property.
<div v-for="(choice, index) in question.choices" class="input-row">
<input type="radio" v-model="question.answer" v-bind:value="choice.value"/>
</div>