I have 2 selects, one with data and other one empty. When first one is selected, I catch it using a switch. Now, depending on the value, I want to create option elements and put them inside empty select.
Let's say I have an array of values
var values = ['Hello', 'world', 'etc']
When selected
selected(event) {
var name;
switch (event.target.value) {
case 'roth':
// append values as options into select, using foreach
// such as:
// <option value="hello">Hello</option>
...
}
}
This is select in my template:
<select class="form-control" :id="selection">
<option selected="" disabled="" value="0"></option>
</select>
You can just define an empty array for options for second select, and push values with your switch/case. Later you can use that values with v-for
For example:
new Vue({
el: '#app',
data: {
selectValues: ['Hello', 'world', 'etc'],
secondarySelectValues: [],
},
methods: {
handleChange: function(e) {
switch (e.target.value) {
case 'Hello':
this.secondarySelectValues = [];
this.secondarySelectValues.push('this', 'is', 'hello');
break;
case 'world':
this.secondarySelectValues = [];
this.secondarySelectValues.push('this', 'is', 'world')
break;
case 'etc':
this.secondarySelectValues = [];
this.secondarySelectValues.push('this', 'is', 'etc')
break;
}
}
}
})
<script src="https://unpkg.com/vue#2.4.2"></script>
<div id="app">
<select class="form-control" #change="handleChange">
<option v-for="selectValue in selectValues" :value="selectValue">{{ selectValue }}</option>
</select>
<select class="form-control secondary">
<option v-for="secondarySelectValue in secondarySelectValues" :value="secondarySelectValue">{{ secondarySelectValue }}</option>
</select>
</div>
Related
I have 2 buttons which sorts my array a -z or relevance. They work well. I would like the options to be in a drop-down rather than 2 buttons. How can I achieve this?
This is what I have just now:
<button #click="sortalphabetically">Alphabetically
<button #click="sortbyrelevance">Relevance
methods: {
sortalphabetically() {
this.theResults = [...this.results].sort((a, b) =>
a.title > b.title ? 1 : -1
);
},
sortbyrelevance() {
this.theResults = [...this.results];
},}
I would like a select drop-down instead of the buttons.
<select
class="col-4 col-lg-5"
v-model="sortatoz"
#change="sortIems"
id="sortby"
aria-label="sortby"
>
<option disabled value="" selected>Select</option>
<option value="alphabetically">Alphabetically</option>
<option value="relevance">Relevance</option>
</select>
You need to add a v-model directive to your select
You can then sort depending on the value of the v-model
new Vue({
el: '#app',
data: () => ({
optionSelected: "asc"
}),
methods: {
sort(){
switch (this.optionSelected){
case 'desc':
console.log('here sort desc')
break;
case 'asc':
console.log('here sort asc')
break
}
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.11/vue.js"></script>
<div id="app">
<select v-model="optionSelected" #change='sort'>
<option value="asc">Sort asc</option>
<option value="desc">sort desc</option>
</select>
</div>
I am creating a custom select component in VueJS 2. The component is to be used as below by the end-user.
<custom-select>
<option value="value 1">Option 1</option>
<option value="value 2">Option 2</option>
<option value="value 3">Option 3</option>
...
<custom-select>
I know the Vue <slot> tag and usage. But how do I get the user provided <option> tags as an array/list so I can get its value and text separately for custom rendering inside the component?
Those <option>s would be found in the default slot array (this.$slots.default), and you could get to the inner text and value of the <option>s like this:
export default {
mounted() {
const options = this.$slots.default.filter(node => node.tag === 'option')
for (const opt of options) {
const innerText = opt.children.map(c => c.text).join()
const value = opt.data.attrs.value
console.log({ innerText, value })
}
}
}
demo
You can achieve it, using v-bind and computed property
new Vue({
el: '#vue',
data: {
selected: '',
values: [
{
code: '1',
name: 'one'
},
{
code: '2',
name: 'two'
}
]
},
computed: {
selectedValue() {
var self = this;
var name = "";
this.values.filter(function(value) {
if(value.code == self.selected) {
name = value.name
return;
}
})
return name;
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="vue">
<div>
<select v-model="selected">
<option v-for="value in values" v-bind:value="value.code">
{{ value.name }}
</option>
</select>
</div>
<strong>{{ selected }} {{ selectedValue }}</strong>
</div>
I need a solution how to make as many select form as my option data length and each form must be independent from each other. It means that if i chooce selected value in one form it must do not overide selected value in others form. Also i need pre-set selected value in each form (for the first form it need to show selected first choice, for second = second choice and so on.)
var app = new Vue({
el: "#app",
delimiters: ["[[", "]]"],
data: {
selected: '',
options: [
{ id: 20 , supp_name: 'test1' },
{ id: 21 , supp_name: 'test2' },
{ id: 34 , supp_name: 'supertest' },
]
},
})
<div margin="20px" v-for='option in options'>
<form action="">
<select v-model="selected">
<option v-for="option in options" v-bind:value="option.supp_name">
[[option.supp_name]]
</option>
</select>
<span>Chosen: [[selected]]</span>
</form>
</div>
It display 3 forms but when I make a choice in on one form it override all forms. How could it be fixed?
You will need as many selected references as there are forms.
For example
var app = new Vue({
el: "#app",
delimiters: ["[[", "]]"],
data: {
selected: [], // make selected an array
options: [{"id":20,"supp_name":"test1"},{"id":21,"supp_name":"test2"},{"id":34,"supp_name":"supertest"}]
},
watch: {
options: {
immediate: true,
handler (options) {
// initialise to the "supp_name" from options
this.selected = options.map(({ supp_name }) => supp_name)
}
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<div id="app">
<div v-for="(_, i) in selected">
<form action="">
<select v-model="selected[i]">
<option v-for="option in options" :value="option.supp_name">
[[ option.supp_name ]]
</option>
</select>
<span>Chosen: [[ selected[i] ]]</span>
</form>
</div>
<pre>selected = [[ selected ]]</pre>
</div>
This synchronises the selected array to be the same length as options then binds each form's <select> to the array index.
I'm a bit new at Vuejs2 and rxjs. So please be kind ^_^. I have an Observable api endpoint. I want to change the param value "food_type" via a select drop down on the same page. I want it so that when I select an item via the drop down the param value is updated, changing the end point and the data on the page gets reloaded. How can I achieve this?
here is my select drop down….
<div class="col-sm-2 divTableHead hand">
<select name="food_type" id="food_type" class="form-control" v-model="food_type">
<option value="" selected>Feeding</option>
<option value=“A”>One</option>
<option value=“AB”>Two Bee</option>
<option value=“BB”>Bee Bee</option>
<option value=“CB”>Cee Bee</option>
<option value=“CC”>Cee Cee</option>
</select>
</div>
here is what my Observable looks like…
data() {
return {
thisCat: [],
food_type: ''
}
},
subscriptions() {
return {
thisCat: Observable.from(axios.get(`${process.env.KITTY_URL}/api/v1/feedings/?cat__slug&cat__name=${this.$route.params.catName}&food_type=${""}`)
.catch(error => console.log(error)))
.pluck("data","results")
}
},
Thank you -_^
Seems like what you're looking for is a Watcher.
This is most useful when you want to perform asynchronous or expensive
operations in response to changing data.
That's exactly the case!
Check out the example below I prepared for you using the JSONPlaceholder API.
var app = new Vue({
el: '#app',
data: {
postID: '',
loading: false,
postContent: null,
},
watch: {
postID: function () {
this.fetchPost()
}
},
methods: {
fetchPost: function(id) {
this.loading = true;
fetch('https://jsonplaceholder.typicode.com/posts/'+this.postID)
.then(response => response.json())
.then(json => {
this.postContent = {
title: json.title,
body: json.body
}
this.loading = false;
})
},
}
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<select v-model="postID">
<option value="" disabled>Select a post</option>
<option value="1">Post #1</option>
<option value="2">Post #2</option>
<option value="3">Post #3</option>
<option value="4">Post #4</option>
<option value="5">Post #5</option>
</select>
<h2 v-if="loading">Loading...</h2>
<div v-if="postContent" class="post_content">
<h3>{{postContent.title}}</h3>
<p>{{postContent.body}}</p>
</div>
</div>
As you can see, the watcher watches for any changes of that property and perform whatever you told it to do. In this case, call the fetchPost method and perform a fetch.
I asked question on adding/removing row in how to use "v-for" for adding or removing a row with multiple components
However, I got a bug: when I adding a row, the items in the first row filled to second row and when I changed the second row, the 1st row is also overwritten as the same as 2nd row.
i must did sth really wrong.
in .js
var data1={selected: null, items: ["A1","B1"]};
Vue.component('comp1',{
template: ` <select v-model="selected">
<option disabled value="">Please select</option>
<option v-for="item in items" :value="item">{{item}}
</option>
</select>`,
data:function(){
return data1
}
});
var data2={selected: null, items: ["A2","B2"]};
Vue.component('comp2',{
template: ` <select v-model="selected">
<option disabled value="">Please select</option>
<option v-for="item in items" :value="item">{{item}}
</option>
</select>`,
data:function(){
return data2
}
});
new Vue({
el: '#app',
data: {
rows: []
},
computed:{
newId(){
return this.rows.length == 0 ? 1 : Math.max(...this.rows.map(r => r.id)) + 1
}
},
methods: {
addRow: function() {
this.rows.push({id: this.newId });
},
removeRow: function(row) {
this.rows.splice(this.rows.indexOf(row), 1)
}
},
});
in .html
<div id="app">
<div v-for="row in rows">
<comp1></comp1>
<comp2></comp2>
<button #click="removeRow(row)">Remove Row</button>
</div>
<button #click="addRow">Add Row</button>
</div>
You need to add the key.
<div v-for="row in rows" :key="row.id">
And you shouldn't share the data between the components, so move your data into the components.
data: function() {
return {
selected: null,
items: ["A1", "B1"]
}
}
Here is a working version.
Vue.component('comp1', {
template: ` <select v-model="selected">
<option disabled value="">Please select</option>
<option v-for="item in items" :value="item">{{item}}
</option>
</select>`,
data: function() {
return {
selected: null,
items: ["A1", "B1"]
}
}
});
Vue.component('comp2', {
template: ` <select v-model="selected">
<option disabled value="">Please select</option>
<option v-for="item in items" :value="item">{{item}}
</option>
</select>`,
data: function() {
return {
selected: null,
items: ["A2", "B2"]
}
}
});
new Vue({
el: '#app',
data: {
rows: []
},
computed: {
newId() {
return this.rows.length == 0 ? 1 : Math.max(...this.rows.map(r => r.id)) + 1
}
},
methods: {
addRow: function() {
this.rows.push({
id: this.newId
});
},
removeRow: function(row) {
this.rows.splice(this.rows.indexOf(row), 1)
}
},
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.js"></script>
<div id="app">
<div v-for="row in rows" :key="row.id">
<comp1></comp1>
<comp2></comp2>
<button #click="removeRow(row)">Remove Row</button>
</div>
<button #click="addRow">Add Row</button>
</div>
Specifically, the way you are sharing data is because you are defining the data like this:
var data1={selected: null, items: ["A1","B1"]};
And returning that object from your data function in the component:
data:function(){
return data1
}
This means that every instance of that component is sharing the same data. That's not what you want with components. Each component should have it's own copy of the data. In this case, there is no need whatsoever to define the data object returned from the data function outside the component.