I need to use Vue.js to progressively enhance an existing server-side rendered form. I need to alter the <select>
's <options>
depending on the value of another field on the form.
As I see it, I cannot mount Vue on the parent <form>
(or another parent element) as I lose all my server-side rendered content, which I need to maintain.
I have mounted on the <select>
that I wish to make dynamic. This allows me to dynamically generate <option>
s however I wish. However the other form input element (a sibling-ish of the mounted <select>
) is now outside of my Vue scope. How can my Vue app be alerted of changes to the dependent field so it can update my <option>
s accordingly?
As I understand it, Vue has its own events system so I'm going to have to hook up a DOM event listener myself - which is completely fine. That's about as far as I've gotten.
Aside: I understand that given infinite time, money, and resources, I should follow the trend of having my entire user experience be an SPA which would solve this issue in a rocket-launcher-to-hammer-a-nail sort of way. However this is not an option. I must progressively enhance the SSR output.
You could still query the document for sibling element with document.querySelector()
, and call addEventListener()
from within a Vue instance:
const ALL_DATA = [
{id: 1, value: 1, text: 'One'},
{id: 2, value: 2, text: 'Two'},
{id: 3, value: 3, text: 'Three'},
];
new Vue({
el: '#app',
data: () => ({
options: [
...ALL_DATA,
]
}),
mounted() {
document.querySelector('#option-type').addEventListener('change', e => {
switch (e.target.value) {
case 'even':
this.options = ALL_DATA.filter(x => x.value % 2 === 0);
break;
case 'odd':
default:
this.options = ALL_DATA.filter(x => x.value % 2 !== 0);
break;
}
})
}
});
document.getElementById('myForm').addEventListener('submit', e => {
e.stopPropagation();
e.preventDefault();
});
<script src="https://unpkg.com/[email protected]"></script>
<form action="#" id="myForm">
<fieldset id="option-type">
<label>Even
<input name="option-type" type="radio" value="even">
</label>
<label>Odd
<input name="option-type" type="radio" value="odd">
</label>
</fieldset>
<select name="option" id="app">
<option v-for="o in options"
value="o.value"
:key="o.id">{{o.text}}</option>
</select>
</form>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With