3
votes

I have a web application with frontend Vue js and backend Laravel. I have to show a dropdown for selecting timezone which will be populated from Laravel backend in blade file. I have a scoped slot in my vue component which can bind that dropdown list providing reactive property selectedId which I can bind to select element as v-model. The problem here is that the select element sets to a value passed from reactive property selectedId but on changing select option the new value is not passed back to that reactive property selectedId. So I think I am not able to bind the reactive property selectedId two way. How can I fix this?

Following is my code

NewProject.vue

<template>
    <div>
        <div class="row">
            <div class="col-md-12">
                <fieldset>
                    <div class="form-group">
                        <label class="col-sm-2 control-label">Select Project Time Zone</label>
                        <slot name="timezone" :selectedId="selectedId"></slot>
                        {{selectedId}}
                    </div>
                </fieldset>

                <button v-on:click="getSelectedTimeZone">Click Me</button>

            </div>
        </div>
    </div>
</template>

<script>

    export default{

        data(){
            return {
                selectedId: 'Pacific/Fiji'
            }
        },

        methods: {
            getSelectedTimeZone: function (event) {
                alert(this.selectedId);
            }
        },
    }

</script>

<style scoped>

</style>

newProject.js

require('./bootstrap');

import NewProject from "../../../assets/js/components/Template/NewProject.vue";
import GlobalMixin from "../../../assets/js/mixins/GlobalMixin";

const newProject=new Vue({
    el:'#newProject',
    mixins:[
        GlobalMixin,
    ],
    components:{
        'new-project':NewProject,
    },
    methods:{

    },
    mounted(){

    },
});

new_project.blade.php

@extends('layouts.headless')


@section('content')

    <new-project>

        <template slot="timezone" slot-scope='data'>
            <select v-model="data.selectedId">
                @foreach ($timezone_list['Pacific'] as $key=>$value)
                    <option value="{{$key}}">{!! $value !!}</option>
                @endforeach
            </select>
        </template>

    </new-project>

@stop

Outputs Following

But the value is not getting updated

1

1 Answers

0
votes

Pass the timezone array into the component as a prop and use v-for to create the bound slots. I would also use v-model on your custom component to bind the selected timezone to a parent data property, which will allow for reactive updates.

To pass a PHP array to a Vue component prop:

<timezones :timezones='{!! json_encode($timezone_list['Pacific']) !!}' v-model="selectedTZ">

// Laravel 5.5+ allows using the @json directive
<timezones :timezones=@json($timezone_list['Pacific']) v-model="selectedTZ">

Vue.component('timezones', {
  props: ['timezones', 'value'],
  data: () => ({
    selected: null
  }),
  template: `<div>
<select @change="$emit('input', $event.target.value)">
<option v-for="timezone in timezones" :value="timezone" :key="timezone">
<slot :timezone="timezone"></slot>
</option>
</select>
</div>`
})

new Vue({
  el: '#app',
  data: () => ({
    timezones: [],
    selectedTZ: 'Africa/Abidjan'
  }),
  mounted() {
    this.timezones = moment.tz.names()
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://momentjs.com/downloads/moment.js"></script>
<script src="https://momentjs.com/downloads/moment-timezone-with-data.js"></script>
<div id="app">
  <timezones :timezones="timezones" v-model="selectedTZ">
    <template slot-scope="slotProps">
      <span v-if="slotProps.timezone.startsWith('Africa')">🐘</span>
      <span v-else-if="slotProps.timezone.startsWith('Asia')">🐉</span>
      <span v-else-if="slotProps.timezone.startsWith('America')">🗽</span>
      <span v-else-if="slotProps.timezone.startsWith('Antarctica')">⛄</span>
      <span v-else-if="slotProps.timezone.startsWith('Australia')">🕷</span>
      <span v-else-if="slotProps.timezone === 'Pacific/Fiji'">⭐</span>
      {{ slotProps.timezone }}
    </template>
  </timezones>

  <p>You've selected: {{ selectedTZ }}</p>
</div>