plasmy
plasmy

Reputation: 149

Vue Component not loading value used

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.

Upvotes: 0

Views: 440

Answers (3)

Andang Rian Dimas
Andang Rian Dimas

Reputation: 255

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

        }

Upvotes: 1

James Sanderson
James Sanderson

Reputation: 13

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

Upvotes: 0

Michael
Michael

Reputation: 5038

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.

Upvotes: 0

Related Questions