Reputation: 1239
What I want to happen, is when you click on the radio button on the left, then it filter the content on the right to show only has the same location.
I don't know how to emit an event when someone click on the radio buttons.
I'm using the x-template in this vue code.
const locations = {
options: [
{
title: 'A',
value: 'a'
},
{
title: 'B',
value: 'b'
},
{
title: 'C',
value: 'c'
}]
};
const team = {
options: [
{
name: 'Team A',
location: 'a'
},
{
name: 'Team B',
location: 'b'
},
{
name: 'Team C',
location: 'c'
}]
};
Vue.component('location-filter', {
template: '#location-filter',
props: {
location: {
type: Array,
required: true
}
}
});
new Vue({
el: '#location-finder',
data: {
location: locations.options,
teams: team.options
}
});
.page {
padding:5px;
border:1px solid #cccccc;
display:flex;
flex-flow:row;
}
.sidebar {
flex-grow:0.6;
border: 1px solid red;
padding:10px;
}
.body {
padding:10px;
border:1px solid blue;
flex-grow:1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div class="page" id="location-finder">
<div class="sidebar">
<location-filter :location="location"></location-filter>
</div>
<div class="body">
<div v-for="team in teams">
<div>{{ team.name }}</div>
</div>
</div>
</div>
<script type="text/x-template" id="location-filter">
<div>
<div v-for="place in location">
<label>
<input type="radio" name="place" value="place.value">{{ place.title }}
</label>
</div>
</div>
</script>
Hopefully, it's good enough my explanation and the code to give you an picture of what i'm trying to achieve.
Upvotes: 1
Views: 129
Reputation: 63059
You can emit a custom event from inside of a component, such as when the user clicks on the radio label, like this:
<label @click="$emit('location', place.value)">
I named the event location
. Now you can listen for an event named location
in the parent's template (locationFinder
) like this:
<location-filter :location="location" @location="changeLocation">
Now, locationFinder
will try to call a method in its instance called changeLocation
every time that location
event is emitted. Here's what that method looks like:
changeLocation(location) {
this.selected = location;
}
You can see it sets a data property called selected
to the selected location. So now you'll need your teams
loop to check that selected
location, and only show a team if its location matches the selected one. The best way to do this is to create a computed
property which will always contain a filtered version of the teams list. If there is no selected team, it returns all teams:
filtered() {
if (this.selected) {
return this.teams.filter(team => team.location == this.selected);
} else {
return this.teams;
}
}
Finally, update the template to loop over this filtered
teams list instead of the unfiltered one:
<div v-for="team in filtered">
I included an updated snippet.
const locations = {
options: [
{
title: 'A',
value: 'a'
},
{
title: 'B',
value: 'b'
},
{
title: 'C',
value: 'c'
}]
};
const team = {
options: [
{
name: 'Team A',
location: 'a'
},
{
name: 'Team B',
location: 'b'
},
{
name: 'Team C',
location: 'c'
}]
};
Vue.component('location-filter', {
template: '#location-filter',
props: {
location: {
type: Array,
required: true
}
}
});
new Vue({
el: '#location-finder',
data: {
location: locations.options,
teams: team.options,
selected: null
},
computed: {
filtered() {
if (this.selected) {
return this.teams.filter(team => team.location == this.selected);
} else {
return this.teams;
}
}
},
methods: {
changeLocation(location) {
this.selected = location;
}
}
});
.page {
padding:5px;
border:1px solid #cccccc;
display:flex;
flex-flow:row;
}
.sidebar {
flex-grow:0.6;
border: 1px solid red;
padding:10px;
}
.body {
padding:10px;
border:1px solid blue;
flex-grow:1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div class="page" id="location-finder">
<div class="sidebar">
<location-filter :location="location" @location="changeLocation"></location-filter>
</div>
<div class="body">
<div v-for="team in filtered">
<div>{{ team.name }}</div>
</div>
</div>
</div>
<script type="text/x-template" id="location-filter">
<div>
<div v-for="place in location">
<label @click="$emit('location', place.value)">
<input type="radio" name="place" value="place.value">{{ place.title }}
</label>
</div>
</div>
</script>
Upvotes: 1