3

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": "[email protected]"
  }
]

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: "[email protected]", // 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");
      }
    },
  },
};

2 Answers 2

2

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
}
Sign up to request clarification or add additional context in comments.

5 Comments

Why I'm getting this error: Error in v-on handler (Promise/async): "TypeError: Cannot read property 'email' of null" ?
My bad, the parameters in the select form were wrong
I'm still having a problem, during the first load of the application courses computed property is null and it gives me this error: TypeError: Cannot read property 'map' of null. To avoid the error I have to use for the first time the array in the select form without computing it, after that I can switch to the computed array
@Raul Another possible solution would be to make the default value of courses an empty array [] rather than null. This would prevent that error, since map() is valid to call on an empty array; it will simply return a new empty array.
to solve this error before the computing I check if the array is null, if it is null return []
1

Here's two different options you can do.

One would be to generate the <option>'s inside the select yourself, using a v-for looping over your teachers, and binding the email property to the value, and displaying the name and surname inside the option.

This will make your <b-select>'s v-model return the chosen teachers e-mail, which you can then use in your filter.

new Vue({
  el: '#app',
  data() {
    return {
      selectedTeacher: null,
      activeTeachers: [{
          "id": 1,
          "name": "Dickerson",
          "surname": "Macdonald",
          "email": "[email protected]"
        },
        {
          "id": 2,
          "name": "Larsen",
          "surname": "Shaw",
          "email": "[email protected]"
        },
        {
          "id": 3,
          "name": "Geneva",
          "surname": "Wilson",
          "email": "[email protected]"
        }
      ]
    }
  }
})
<link href="https://unpkg.com/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/[email protected]/dist/bootstrap-vue.css" rel="stylesheet" />

<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/bootstrap-vue.js"></script>


<div id="app">
  <b-select v-model="selectedTeacher">
    <option v-for="teacher in activeTeachers" :value="teacher.email">
      {{ teacher.name }} {{ teacher.surname }}
    </option>
  </b-select>

  {{ selectedTeacher }}
</div>


The other option would be to change your computed to return an array of objects instead of simple strings as you're currently doing.

By default <b-select> expects the properties value and text if you use an array of objects in the options prop.

Here you would bind the email for each teacher to the value, and the name and surname to the text prop.

This will make your <b-select>'s v-model return the chosen teachers e-mail, which you can then use in your filter.

Reference: https://bootstrap-vue.org/docs/components/form-select#options-property

new Vue({
  el: '#app',
  data() {
    return {
      selectedTeacher: null,
      activeTeachers: [{
          "id": 1,
          "name": "Dickerson",
          "surname": "Macdonald",
          "email": "[email protected]"
        },
        {
          "id": 2,
          "name": "Larsen",
          "surname": "Shaw",
          "email": "[email protected]"
        },
        {
          "id": 3,
          "name": "Geneva",
          "surname": "Wilson",
          "email": "[email protected]"
        }
      ]
    }
  },
  computed: {
    teacherOptions() {
      return this.activeTeachers.map(teacher => ({
        value: teacher.email,
        text: `${teacher.name} ${teacher.surname}`
      }));
    }
  }
})
<link href="https://unpkg.com/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/[email protected]/dist/bootstrap-vue.css" rel="stylesheet" />

<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/bootstrap-vue.js"></script>


<div id="app">
  <b-select v-model="selectedTeacher" :options="teacherOptions"></b-select>

  {{ selectedTeacher }}
</div>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.