Search code examples
javascriptvue.jsbootstrap-4bootstrap-vue

Dynamically change select input in Bootstrap Vue


I am trying to set some objects in a Bootstrap-Vue form select which I get via JSON. The JSON is made up of teacher objects from the following fields:

[
  {
    "id": 1,
    "name": "John",
    "surname": "Doe",
    "email": "john.doe@gmail.com"
  }
]

What I'm trying to do is put the name and surname in the select list, that is the full name.

I have already managed to do this via a computed property by processing the list. But now I want that when I select a teacher, the list of courses is filtered according to the chosen teacher.

To do this I need the teacher's email, which I can't recover, having processed the teachers to get the full name. Consequently, I can't even update the list of courses based on the teacher chosen.

This is the code for the template:

<b-form-group
  id="input-group-3"
  label="Docente:"
  label-for="input-3"
>
  <b-form-select
    v-model="teacher"
    :options="teachers"
    value-field="item"
    text-field="fullName"
    required
    @change="filterCourse"
  ></b-form-select>
  <div class="mt-3">
    Selected: <strong>{{ teacher }}</strong>
  </div>
</b-form-group>

This is the script code:

import { mapGetters, mapActions } from "vuex";
export default {
  data() {
    return {
      teacher: "",
      course: "",
    };
  },

  created: function() {
    this.GetActiveTeachers();
    this.GetActiveCourses();
  },

  computed: {
    ...mapGetters({
      ActiveTeacherList: "StateActiveTeachers",
      ActiveCourseList: "StateActiveCourses",
      FilteredTeacherList: "StateTeacherByCourse",
      FilteredCourseList: "StateCourseByTeacher",
    }),

    teachers: function() {
      let list = [];
      this.ActiveTeacherList.forEach((element) => {
        let teacher = element.name + " " + element.surname;
        list.push(teacher);
      });
      return list;
    },
  },

  methods: {
    ...mapActions([
      "GetActiveTeachers",
      "GetActiveCourses",
      "GetCourseByTeacher",
      "GetTeacherByCourse",
      "AssignTeaching",
    ]),

    async filterCourse() {
      const Teacher = {
        teacherEmail: "john.doe@gmail.com", // For testing purpose
      };
      try {
        await this.GetCourseByTeacher(Teacher);
      } catch {
        console.log("ERROR");
      }
    },

    async filterTeacher() {
      const Course = {
        title: "Programming", // For testing purpose
      };
      try {
        await this.GetTeacherByCourse(Course);
      } catch {
        console.log("ERROR");
      }
    },
  },
};

Solution

  • You're currently using the simplest notation that Bootstrap Vue offers for form selects, an array of strings.

    I suggest you switch to use their object notation, which will allow you to specify the text (what you show in the list) separately from the value (what's sent to the select's v-model).

    This way, you'll be able to access all the data of the teacher object that you need, while still being able to display only the data you'd like.

    We can do this by swapping the forEach() in your teachers computed property for map():

    teachers() {
      return this.ActiveTeacherList.map((teacher) => ({
        text: teacher.name + " " + teacher.surname,
        value: teacher
      }));
    },
    

    Then, all you need to do is update your filterCourse() handler to use the new syntax, eg.:

    async filterCourse() {
      const Teacher = {
        teacherEmail: this.teacher.email,
      };
      try {
        await this.GetCourseByTeacher(Teacher);
      } catch {
        console.log("ERROR");
      }
    },
    

    As a final note, if you don't want or need the full object as the value, then you can mold it to be whatever you need, that's the beauty of this syntax.
    For example, you want the full name and email, instead of the parts:

    value: { 
      fullName: teacher.name + " " + teacher.surname,
      email: teacher.email
    }