The general idea is to map up the relation between what I would call "top level subjects" or topics and the "sub level subjects" or sub-topics.
If you know you only ever will have three inputs (at max), then doing a mapping for a pre-populated array is ok. However, if you're looking at dynamically adding more levels, you would need to put down more work. That being said, I've looked at this briefly and added a subject <-> topic relation. Each entry has the parent attribute which defines if they have one or more. If they don't, they're a "top level subject" or topic. If they do, they're a sub-topic.
By handling the onChange event for each select, you can figure out what ID the subject you selected has and find the corresponding entry in the subjects object array. Once you found that, you filter all entries that have parents !== null and match every ID in their parent array. This is calculated using a property, which is ideal for such purposes.
HTML
<div id="app">
<select
v-model="selected[0].id"
@change="selectTopic($event)"
>
<!-- List first only the top level topics -->
<option
v-for="(subject, subjectKey) in topics"
:key="`subject-${subjectKey}`"
:value="subject.id"
>
{{ subject.name }}
</option>
</select>
<select
v-if="nextLevelSubjects"
v-model="selected[1].id"
@change="selectTopic($event)"
>
<!-- List first only the top level topics -->
<option
v-for="(subject, subjectKey) in nextLevelSubjects"
:key="`next-level-subject-${subjectKey}`"
:value="subject.id"
>
{{ subject.name }}
</option>
</select>
<div v-if="someSelectionHasBeenMade">
<pre>
All topics selected: {{ selected }}
</pre>
</div>
</div>
Vue Code (Excerpt)
data: {
someSelectionHasBeenMade: false,
nextLevelSubjects: null,
selected: [
{
id: null
},
{
id: null
},
{
id: null
}
],
subjects: [
{
id: 1,
name: "Education",
parent: null
},
{
id: 2,
name: "English",
parent: [1]
},
{
id: 3,
name: "English & Creative Writing",
parent: [1]
},
{
id: 4,
name: "French",
parent: [1]
},
{
id: 5,
name: "Economics",
parent: null
},
{
id: 6,
name: "Law",
parent: [5]
},
{
id: 7,
name: "Marketing",
parent: [5]
},
]
},
computed: {
topics () {
return this.subjects.filter(e => e.parent === null)
}
},
methods: {
selectTopic (event) {
this.someSelectionHasBeenMade = true
const parentId = Number.parseFloat(event.target.value)
this.nextLevelSubjects = this.subjects.filter(e => e.parent !== null).filter(i => i.parent.every(p => p === parentId))
}
}
})
I've made a JSFiddle here: https://jsfiddle.net/Coreus/md7ktj6e/2/
Making a sub-topic be parent to several topics
If you want a sub-topic to match either one of more subjects / topics, put in several IDs in the parent property for the sub-topic in question and change the filtering by parent to some. Like so:
subjects: [
{
id: 1,
name: "Education",
parent: null
},
{
id: 2,
name: "Languages",
parent: null
},
{
id: 3,
name: "English",
parent: [1, 2]
},
....
{
id: 4,
name: "French",
parent: [1, 2]
},
{
id: 5,
name: "History",
parent: [1]
},
By the example above, the relation tree looks like so:
Education
Languages
Then change the filtering to use some instead of every.
this.nextLevelSubjects = this.subjects.filter(e => e.parent !== null).filter(i => i.parent.some(p => p === parentId))
Edit: Code example has been updated
Please note this just illustrates purpose. You obviously need to put down more work for it to work on additional tiers (sub-topics) down the line. It should, however, give you an idea on how to approach this further.