2

I am trying to implement the bootstrap-select plugin (found here https://developer.snapappointments.com/bootstrap-select/) into a ruby on rails app with Vue.js as the javascript framework.

The objective is that in one select you can pick a category and in the other one you can pick all the teachers available for that category. To do this i use axios and vue to do a request to my own api and use that to populate the second select and it works fine with a simple select field, however I want bootstrap-select to be shown, I am aware the plugin has a function "selectpicker('refresh')" to make the option reload possible but my browser console claims selectpicker is not a function when I call it on my vue instance, I can manually run it on the browser console however and it works as intended

My code:

js:

Vue.use(VueAxios, axios)
    document.addEventListener('DOMContentLoaded', () => {
      if(document.getElementById('enrollment_form')) {
      var app = new Vue({
        el: '#enrollment_form',
        data: {
          CategoryValue: null,
          TeacherValue: null,
          teachers: null,
        },
        methods: {
          fetchTeachers() {
            this.axios.get('/api/teachers/' + this.licenceTypeValue).then(response => (this.teachers = response.data))
              $('.selectpicker').selectpicker('refresh');
          }
        }, 
      })
    }})

view:

       <div class="row">
          <div class="col-lg-5">
            <div class="form-group">
              <%= f.label :category %>*<br />
              <%= f.collection_select(
                  :category,
                  Category.all,
                  :id,
                  :catgegory_name,
                  {include_blank: true},
                  {
                    class: 'form-control selectpicker',
                    "v-model" => "CategoryValue",
                    "v-on:change" => "fetchTeachers"

                  }
              )%>
            </div>
          </div>  
        </div>

        <div class="row">
          <div class="col-lg-5">
            <div class="form-group">
              <label for="teacher_id">Teacher</label>
              <div>
                <select id="teachers-list" class='form-control selectpicker' v-model="TeacherValue" data-fieldname = "TeacherValue">
                  <option label="" ></option>
                  <option v-for="teacher in teachers" :value="teacher.id"> {{teacher.name}}  </option>
                </select>
              </div>
            </div>
          </div>  
        </div>

        <div>
          <%= f.hidden_field :teacher_id, {"v-model" => "TeacherValue"} %>
        </div>

Finally my application.js

//= require rails-ujs
//= require activestorage
//= require jquery
//= require jquery_ujs
//= require popper
//= require bootstrap
//= require bootstrap-select

I would really appreciate if someone could help as i simply can't figure out what to do

1

2 Answers 2

5

Try changing to the following:

var app = new Vue({
    el: '#enrollment_form',
    data: {
        CategoryValue: null,
        TeacherValue: null,
        teachers: null,
    },
    methods: {
        fetchTeachers() {
            // Get the Vue object in a variable so you can use it in the "then" 
            // since 'this' context changes in the "then" handler function.
            let theVue = this;

            this.axios
                .get('/api/teachers/' + this.licenceTypeValue)
                .then(response => {
                    theVue.teachers = response.data;
                    // Call bootstrap-select's 'refresh' using Vue's $nextTick function 
                    // to ensure the update is complete before bootstrap-select is refreshed.
                    theVue.$nextTick(function(){ $('#teachers-list').selectpicker('refresh'); });
                });
        }
    }, 
})

I ran into this problem in an application I'm developing, and wrote an article with a more detailed explanation, including broken and working examples. My examples change the options via JavaScript without AJAX, but the concept is the same.

In the code above, you are calling the bootstrap-select 'refresh' using Vue's $nextTick function which waits until the Vue object's update is complete before executing the code passed to the $nextTick call. (see $nextTick on Vue's documentation)

Note: You could also do a more generic update in the Vue's 'update' event handler by adding:

updated: function(){
  this.$nextTick(function(){ $('.selectpicker').selectpicker('refresh'); });
}

Please be aware that this will always update all bootstrap-selects that share the same class 'selectpicker'. The update will occur on every update of the vue data, including those unrelated to the <select>s in question, which is wasteful and could potentially cause performance issues.

I believe the best practice is to refresh just the <select> that needs updating, at the moment it needs the refresh (in your case when the AJAX call returns and the 'teachers' property has been updated.)

Sign up to request clarification or add additional context in comments.

Comments

0

If you run it in timeout method, it will be refresh.

 setTimeout(function () {
            $(".selectpicker").selectpicker("refresh");
        }, 1000);

1 Comment

Hi @Suphi Atlı, welcome to stackoverflow! You're answering an old question which is over 1 year old. Please try to answer new questions, this would be more helpful. And check your answer in the preview before sending it. The code indent is not correct.

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.