VueJS Using #click on <option> elements and #change on <select> element - vue.js

I have a simple function that manipulates a data between true and false. I use it to make my div hidden and visible like a toggle. I also have a with three element. I found out that I cannot use #click for <option> elements, I need to use #change for my <select>.
But in this way, whenever an is selected, the function is being triggered and my data toggles between true and false. Here is my <select> element;
<select #change="isDisabled">
<option>Please select a security type</option>
<option>No Security</option>
<option>Personal</option>
<option>Enterprise</option>
</select>
IsDisabled function takes a variable and change its values between true and false so my div becomes hidden and visible as follows;
<div v-if="noSecurity">something</div>
But here is the thing, I only want to trigger the function when the user select the "No Security" option. Now it's being triggered whenever I select an option, so it turned out to be some kind of a toggle. But I want to hide the div when I select the "No Security" option and show the div if something different is selected. What should I do?

I've made a CodeSandbox where you could see the result :
https://codesandbox.io/s/magical-meitner-63eno?file=/src/App.vue
But here is the explanation:
<template>
<section>
<select #change="isDisabled">
<option>Please select a security type</option>
<option>No Security</option>
<option>Personal</option>
<option>Enterprise</option>
</select>
<div v-if="noSecurity">You Choose no security, that's dangerous !</div>
</section>
</template>
<script>
import HelloWorld from "./components/HelloWorld";
export default {
name: "App",
data() {
return {
noSecurity: false,
};
},
methods: {
isDisabled(e) {
console.log("e", e.target.value);
if (e.target.value === "No Security") {
// do your change
return (this.noSecurity = !this.noSecurity);
}
// to allow reset if another option is selected
if (this.noSecurity) {
return this.noSecurity = false;
}
},
},
};
</script>
Basically when you use the #change handler, your function will receive an event, in this event you can catch the target value with event.target.value.
Doing so, you do a condition if the value is equal to No Security (so the selected item), you change your state, if it's not No Security, you do nothing, or you do something else you would like to do.
Appart from that, I advice you to change your method name isDisabled to a global convention name like handleChange, or onChange.
Pass id values in your option so when you get the select event you're clear that No security or whatver the name you would like to change will be the same.
Because if one day you change No security to another name, you have to update all your conditions in your app. Try to avoid conditions with strings values like this if you can.
<option value="1">No Security</option> // :value="securityType.Id" for example if coming from your database
<option value="2">Personal</option>
<option value="3">Enterprise</option>
then in your function it will be
if (e.target.value === noSecurityId) {
// do your change
this.noSecurity = !this.noSecurity;
}
//...

There's no need for the additional noSecurity variable. Create your select with v-model to track the selected value. Give each option a value attribute.
<select v-model="selected">
<option value="">Please select a security type</option>
<option value="none">No Security</option>
<option value="personal">Personal</option>
<option value="enterprise">Enterprise</option>
</select>
Check that value:
<div v-if="selected === 'none'">something</div>
You can still use the noSecurity check if you prefer by creating a computed:
computed: {
noSecurity() {
return this.selected === 'none';
}
}
Here's a demo showing both:
new Vue({
el: "#app",
data() {
return {
selected: ''
}
},
computed: {
noSecurity() {
return this.selected === 'none';
}
},
methods: {},
created() {}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<select v-model="selected">
<option value="">Please select a security type</option>
<option value="none">No Security</option>
<option value="personal">Personal</option>
<option value="enterprise">Enterprise</option>
</select>
<div v-if="selected === 'none'">something</div>
<div v-if="noSecurity">something</div>
</div>

Is using v-model instead of using a method is option for you? If it is, please try the following:
HTML:
<div id="hello-vue" class="demo">
<select v-model="security">
<option>Please select a security type</option>
<option>No Security</option>
<option>Personal</option>
<option>Enterprise</option>
</select>
<div v-if="security=='No Security'">something</div>
</div>
JS:
const HelloVueApp = {
data() {
return {
security: undefined
}
}
}

Related

How to remove value from an element according to a condition in VueJS

I'm trying to remove the values, and hide the elements, by changing a select. I know how to hide, but I would like a remove the values if something has been written.
Here's my code :
<select v-model="switchopera">
<option :value="undefined" selected disabled
>Is the reservation under the same name ?</option>
<option :value="false"
>Yes</option>
<option :value="true"
>No</option>
</select>
<select
:required="switchopera ? false : true"
:value="switchopera ? false : true">
<option selected disabled>Title (on the reservation)</option>
<option>Mr</option>
<option>Mrs/option>
</select>
And here's my Vuejs code :
data() {
return {
switchopera: undefined
};
}
};
you can use watch property to check and do actions :
watch: {
switchopera: function(value){
// do action
}
}

How to update Vuejs2 page content when changing select option on api rxjs observable api endpoint?

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.

Change options and value at the same time

I have a problem when I try to change the options of my select and its value at the same time. If I use v-model, it works properly but if I use v-bind:value + v-on:change, it will not work.
Here is a js fiddle that will illustrate the problem : https://jsfiddle.net/2vcer6dz/18/
The first time you click on the button "change", only the first select value will be 3. If you reclick they all become 3.
Html
<div id="app">
<select v-model="value">
<option v-for="item in options" :key="item.Value" :value="item.Value">{{item.Text}}</option>
</select>
<select :value="value" v-on:change="value = $event.target.value">
<option v-for="item in options" :key="item.Value" :value="item.Value">{{item.Text}}</option>
</select>
<select-option v-model="value" :options="options"></select-option>
<br />
<input type="button" value="change" v-on:click="change" />
</div>
<template id="template-select-option">
<select :value="value" v-on:change="update($event.target.value)">
<option v-for="item in options" :key="item.Value" :value="item.Value">{{item.Text}}</option>
</select>
</template>
Javascript
Vue.component('select-option', {
template: '#template-select-option',
props: ['value', 'options'],
methods: {
update: function (value) {
this.$emit('input', value);
}
}
});
new Vue({
el: '#app',
data: {
value: 1,
options: [{Value:1, Text:1}, {Value:2, Text:2}]
},
methods: {
change: function () {
this.options = [{Value:1, Text:1}, {Value:2, Text:2}, {Value:3, Text:3}];
this.value = 3;
}
}
});
Expected result
All selects should have the value "3" when you click on the button "change"
Changing the options and the value at the same time is confusing Vue. This is probably a minor bug in Vue. If you use $nextTick to push the value change off to the next update cycle, they all work.
change: function () {
this.options = [{Value:1, Text:1}, {Value:2, Text:2}, {Value:3, Text:3}];
this.$nextTick(() => {
this.value = 3;
});
}
It seems that this is a known bug which was closed because a workaround was found.
The workaround is to declare another property and cast v-model on it. This solutions is easier to implement inside a component.
https://jsfiddle.net/6gbfhuhn/8/
Html
<template id="template-select-option">
<select v-model="innerValue">
<option v-for="item in options" :key="item.Value" :value="item.Value">{{item.Text}}</option>
</select>
</template>
Javascript
Vue.component('select-option', {
template: '#template-select-option',
props: ['value', 'options'],
computed: {
innerValue: {
get: function() { return this.value; },
set: function(newValue) { this.$emit('input', newValue); }
}
}
});
Note: In the github thread, it is suggested to use a computed property instead, but if you use a computed property, vue will throw warning every time you change the value in your dropdown because computed property don't have setter.

Computed properties in vue not reflected in select list

I have a vue component that is meant to create a select list with all available options. The save method puts the saved value into a vuex store. The available fields are generated using a computed property on the component that calls the vuex getter for the list.
In the component, there's a v-for with a v-if that checks that the select item isn't already being used by another component (by looking at a mapped property on the list item object).
Testing this, everything seems to be working as expected, the vuex store gets the list, it accepts the update, and once a save is called, the destination field is marked as mapped and that mapped property is visible in the vuex debug panel.
However, the other select lists on the page don't get updated to reflect the (now shorter) list of available options.
Once the select item is selected in another instance of the component, I'd expect the other components to drop that select option- but it appears the v-if is not re-evaluated after the initial load of the component?
Sorry, here's the basic component:
<template>
<div class="row">
<div class="col-4">
{{ item.source_id }}
</div>
<div class="col-8">
<select v-model="destination" class="form-control form-control-sm">
<option v-for="dest in destinationFields" v-if="shouldShow(dest)" v-bind:value="dest.id">{{ dest.id }} - {{ dest.label }} ({{ dest.dataType }})</option>
</select>
</div>
</div>
</template>
<script>
export default {
props: ['item'],
data() {
return {
destination: ''
}
},
methods: {
shouldShow: function(dest) {
if (this.hideDestination && (!dest.hasOwnProperty('mapped') || dest.id === this.destination)) {
return true
} else if (!this.hideDestination) {
return true
}
return false
}
},
computed: {
destinationFields: function() {
return this.$store.getters.visibleDestination
},
hideDestination: function() {
return this.$store.getters.hideMappedDestinations // boolean
}
}
}
I think a better approach would be to already filter the data inside of your computed function as follows:
computed: {
destinationFields: function() {
return this.$store.getters.visibleDestination()
.filter(dest => !dest.hasOwnProperty('mapped') || dest.id === this.destination)
},
hideDestination: function() {
return this.$store.getters.hideMappedDestinations // boolean
}
}
You would also have to change your template to:
<select v-model="destination" class="form-control form-control-sm">
<option v-for="dest in destinationFields" v-bind:value="dest.id">{{ dest.id }} - {{ dest.label }} ({{ dest.dataType }})</option>
</select>

Clickable option with action in select

I'm working on a Vue file and have a select
<select v-if="show">
<option v-on:click="test()" value=""> someData</option>
<option>otherdata</option>
</select>
[...]
var instance = new Vue({
el: "#General",
[...]
methods:{
test: function(){
alert('youre goddam right');
}
[...]
}
[...]
}
So What i'm trying to do is to display my datas someData and otherdata. That works great but what i want it's when the user click on firstData, the action "test" append, and an alert comes up but that doesn't work here. I tried with the v-on:click but nothing happend.
Thanks for the help
Yes so it appears that the click event is not triggered for an <option> element. Here is one of the many fix available: using the input event on the select instead, and filter the value.
var instance = new Vue({
el: "#General",
methods:{
test: function(value) {
if (value === "choice1") {
alert('youre goddam right');
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.js"></script>
<div id="General">
<select v-on:input="test($event.target.value)">
<option value="choice1">someData</option>
<option>otherdata</option>
</select>
</div>