Adding special options to select using Vue.js

by Thomas Beutel

I get some interesting requests from my clients and some of them are head-scratchers. The beauty of Vue.js is that you can implement almost any behavior and do it fairly simply.

In this case, the client wanted to swap in a different Act-On form via an iframe if a certain option was selected. Since the original options were being populated from an API (via axios) I had to add the special option separately.

Here is what I did in the select component:


Vue.component('course-selector2',{
props: ['courses','value'],
template: '<select class="custom-select" v-model="course"><option value="">Select date and location</option><option v-for="option in options" v-bind:value="option.value">{{ option.label }}</option></select>',
computed: {
options: function() {
var type = this.courses.type;
var list = this.courses.list.map(
function(obj){
var label = obj.start_date_formatted+' | '+obj.location;
return {'value':obj.event_internal_id,'label':label};
}
);
list.push({'value':'-1','label':'I\'m not sure yet. Please have someone call me.'}); // this will show a different form
return list;
}
},
data: function() {
return {
course: ''
}
},
watch: {
course: function() {
this.$emit('input',this.course);
}
}
});

In the computed options above, note how I push the extra option onto the list. Obviously I could have just added the option in the template itself but I find this to be a cleaner and easier to read implementation.

Later in the main app code below, I implemented a watch to do the swapping. Whenever the Please have someone call me option is selected, the registration form is hidden and the contact me form is shown instead.


window.onload = function(){
var app = new Vue({
el: '#app',
data: {
courses: [ ], // populated via axios, not shown
course1: '',
display_reg: true,
display_call: false,
internal_event_id: 0
},
watch: {
course1: function() {
this.event_internal_id = this.course1;
if(this.event_internal_id == -1){
this.display_reg = false;
this.display_call = true;
}
else {
this.display_reg = true;
this.display_call = false;
}
},
template: '<form v-show="display_reg" id="myform" method="post" action="/path/to/cart">' +
'<div style="margin-top:10px;"><label style="display:block;color:#ffffff;">Course Date and Location</label><course-selector2 v-model="course1" v-bind:courses="{type:\'Course Listings\',list:courses}"></course-selector2></div>' +
'<div style="margin-top:24px;"><img style="cursor:pointer;" id="add-reg-btn" v-on:click="onSubmit" type="image" src="/images/acton/continue.png" border="0"/></div>' +
'<p style="color:#ffffff;" v-show="display_cart_text">You will be directed to an online cart to complete your purchase and confirm registration.</p>' +
'</form>' +
'<div class="wrapper"><iframe class="custom-iframe" v-on:load="hideCallHeader" v-show="display_call" src="path/to/act-on-form" style="border: 0; min-height: 565px;margin-left:-10px;"></iframe></div>'
});

Please note that the above is just a rough sketch. I have not tested the above example and major portions of the app are missing. My purpose here is just to give you an idea of what I did.