0

I have a Vue app using JS. I needed to use some Select2 for dynamically loaded values, among other things. I made a Vue Component for my Select2 which worked wonderfully except for one problem. I am using Ajax to get dynamic options for the Select2, but when my Select2 is mounted it is not loading a value for the Ajax URL. This is my code:

<template>
    <table class="table">
        <thead>
        <tr>
            <th>Substance</th>
            <th>Tested</th>
            <th>Results</th>
            <th>Cause of Death</th>
            <th>Person Perscribed For</th>
            <th>Category</th>
            <th></th>
        </tr>
        </thead>
        <tbody>
        <tr v-for="index in SubstanceRows" :key="index">
            <td><input type="text" class="form-control form-control-sm substance-row" /></td>
            <td><select2 class="js-example-basic-single tested-row" :apiurl="SummaryTested" style="width: 100%;"></select2></td>
            <td><select2 class="js-example-basic-single result-row" :apiurl="SummaryResult" style="width: 100%;"></select2></td>
            <td><div class="form-check"><input type="checkbox" class="form-check-input cause-of-death-row" value=""></div></td>
            <td><select2 class="js-example-basic-single obtained-for-row" :apiurl="DrugObtainedFor" style="width: 100%;"></select2></td>
            <td><div class="form-check"><input type="text" class="form-control form-control-sm category-row" /></div></td>
        </tr>
        </tbody>
    </table>
</template>
<script type="text/x-template" id="select2-template">
  <select>
    <slot></slot>
  </select>
</script>

And this is my Component:

Vue.component('select2', {
    props: ['apiurl', 'id'],
    template: '#select2-template',
    mounted: function(){
        this.loadSelect2
    },
    watch: {
        loadSelect2: function() {
            var vm = this
            var apiURL = this.apiurl
            $(this.$el).select2({
                placeholder: "Select an option",
                allowClear: true,
                templateResult: dropdownTemplate,
                templateSelection: dropSelection,
                ajax: {
                    url: function(params){
                        url = 'api/variable/' + apiURL
                        if(params.term) url = 'api/variable/' + apiURL + '/' + params.term
                        return url
                    }
                }
            })
            //Check if it has a value assigned
            if (vm.$root[apiURL] && vm.$root[apiURL] != ''){
                $.ajax({
                    type: 'GET',
                    url: '/api/variable/' + apiURL + '/' + vm.$data[apiURL]
                }).then(function(data) {
                    var option = new Option(data.results[0].label, data.results[0].id, true, true)
                    element.append(option).trigger('change')
                    element.trigger({
                        type: 'select2:select',
                        params: {
                            data: data.results
                        },
                        templateResult: dropdownTemplate,
                        templateSelection: dropSelection
                    })
                })
            }
        }
    }
})

The part where I'm stuck is that, as you can see (or not), I'm using a v-for to generate those fields, using a variable I declared inside a Vue app. I have a button that adds more of these as needed (for the moment I just add +1 to the variable). Where I'm having the problem is when doing the ajax for the select2. The part that says /api/variable + apiURL, when generating for the first time, the variable apiURL is undefined. I should mention that the v-for variable, SubstanceRows, has an initial value of 3 (so I have three rows when it loads up). However, when I add a row using the button, it works just fine and the url is loaded as it is supposed to. I'm guessing this is some issue with asynchrony, but I really don't have enough experience with Vue to figure out what it is.

Also, the script part id=select2-template, I followed that off a guide but I have no idea what it does.

3 Answers 3

1

Have you tried to move the loadSelect2 function from watch to methods? As far as I know, watch is used for listening a props. to watch the props if there is data update from parent component.

so it would be like this:

    mounted: function(){
        this.loadSelect2();
    },
    methods: {
        loadSelect2: function() {
            var vm = this
            var apiURL = this.apiurl

           // the rest of the code

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

Comments

0

This is because you do not have the props or propsData in the mounted method they only come in later. Put the same. function in a watcher so that when apiUrl changes a value (receives a non null/undefined value) you then invoke the function.

1 Comment

Thank you for your answer! I took everything and put it in a watch function, but I'm having the same problem. I'm pretty sure I'm doing it wrong though, sorry for the inconvenience. See my updated question.
0

when you call var apiURL = this.apiURL is wrong. Your prop is all lower case, should it not be var apiUrl = this.apiurl

7 Comments

Thank you for your answer! I have updated my question with your suggestion. Used the ':' and used lowercase apiurl. However, now I am getting an error on console saying Property or method "SummaryTested" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. Thank you for your time. I get this error for each of the apiurl
I ammended my comment and removed it about binding as you just passing a string you don't need to bind it.
I removed the bindings and it's still not working. Is it maybe because I put the function in watch, and it should be in mounted? Either way, I had it like that in mounted but it was also not working. Quite a mystery. console.log(this.apiurl) shows that the value is there, but it's not getting there when doing the ajax part.
Why don't you build a proper Vue select box in your template. I assume that's what the jQuery is doing? jQuery and Vue don't play nice together. It seems like your trying to do much for what you want to do? On the select box do a @change=yourFunctionName() and then everytime the select box is changed your function will be called and make the Ajax request? Here how to do a select box. vuejs.org/v2/guide/forms.html#Select Rremove that whole script type at the bottom as well.
Managed to fix it by doing <select2 class="js-example-basic-single tested-row" data-apiurl="SummaryTested" style="width: 100%;"></select2> on my tags, then on the component I got the value by using var apiURL = $(this.$el).data('apiurl'). 100% sure there has to be a better and more elegant way to do this, but for now it works.
|

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.