Reputation: 685
Is it possible to use v-model on an element in the DOM that is outside the root element of the Vue instance?
I.e, Could you have the following:
$(function(){
Vue.component('custom-element', {
template: '#custom-template'
})
var vm = new Vue({
el: "#app"
data: {
selected: ""
}
})
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<select id="SportSelector" v-model="selected">
<option value="football"> Football </option>
<option value="tennis"> Tennis </option>
</select>
<div id="app">
<custom-element>
</custom-element>
</div>
<script type="text/x-template" id="custom-template">
<div>
<p> {{selected}} </p>
</div>
</script>
Where the select is outside the root element ("app") of the Vue. This is a simplified version of my problem, but I believe highlights the difficulties I'm having.
I saw this answer talking about centralised state management for sharing data between Vues but that seems a bit heavy to have to wrap the select in an entirely different Vue, I feel like i'm missing something major! (still very new to Vue). Does everything the Vue interacts with have to be under the root element of the instance of the Vue?
Upvotes: 1
Views: 4164
Reputation: 2458
You can use portal-vue
to accomplish this. It allows you to place the code from your component anywhere in the DOM.
Add it your view instance:
import PortalVue from 'portal-vue';
Vue.use(PortalVue);
In your component you define the content you want to render outside the component:
<portal to="destination">
<p>This slot content will be rendered wherever the <portal-target> with name 'destination'
is located.</p>
</portal>
You can then place this anywhere in the DOM:
<portal-target name="destination">
<!--
This component can be located anywhere in your App.
The slot content of the above portal component will be rendered here.
-->
</portal-target>
Example code from https://github.com/LinusBorg/portal-vue
Upvotes: 1
Reputation: 1566
Unless you have some funky interaction going on with the select, add it to your Vue instance. The Vue instance should encapsulate all your templates and logic for the form.
If you're trying to mix jQuery and Vue on the same element you're probably not going to have a good time.
Upvotes: 0
Reputation: 82459
No, you cannot use v-model
on elements outside the context of the Vue. The reason is Vue compiles down to a render function that renders the contents of the element it controls; it doesn't render anything outside that element, unless you involve specific code or a library like vue-portal
.
That said, you can update Vue when the select changes using standard javascript set the Vue data property. I also cleaned up a few things like passing the selected data to your component (which is necessary; components cannot access their parents data directly).
$(function(){
Vue.component('custom-element', {
props: ["selected"],
template: '#custom-template'
})
var vm = new Vue({
el: "#app",
data: {
selected: ""
}
})
//get a reference to the select
const sports = document.querySelector("#SportSelector")
//add a listener that updates the Vue data when the select changes
sports.addEventListener("change", evt => vm.selected = evt.target.value)
//initialize Vue with the current selected value
vm.selected = sports.value
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<select id="SportSelector">
<option value="football"> Football </option>
<option value="tennis"> Tennis </option>
</select>
<div id="app">
<custom-element :selected="selected">
</custom-element>
</div>
<script type="text/x-template" id="custom-template">
<div>
<p> {{selected}} </p>
</div>
</script>
Upvotes: 3