1

I'm currently facing struggle trying to update the selected item of my dropdown, based on the truth of a checkbox. The reason the selected item is not being updated is because the string that I'm trying to add as a selected item is not present in the dropdown list. Therefore when I check the checkbox, I need to add the string to the dropdown list and have it appear as a selected item. Should I choose to add a string of an item that is already present in the dropdown, the selected item gets updated accordingly. Moreover if I uncheck the checkbox, the string should be removed from the dropdown list and as a selected item.

To give a bit more context, I have a form where users can add their work experience. So users can add their start year and end year. If the users are presently working at their job, they can check the checkbox in which the endYear will take 'Present' as the option instead of a year.

For this I'm working with three components:

ExperienceDetails.vue

...form-wrapper

<div class="year-picker">
     <YearPicker :placeholder="'Voeg datum toe'"
          :select-name="'endYear'"
          :title="'Einddatum'"
          :selected="experienceInfo.endYear" // Here experienceInfo.endYear is being updated with my string, however it does not appear as a selected item.
          :earliest-date="currentYear - 50"
          :latest-date="currentYear"
          :callback="setEndYear"
          :present-year="isPresent"/>
</div>

<div class="checkbox">
      <BasicCheckbox
           :label-text="'Dit is mijn huidige functie.'"
           :id="`id`"
           :callback="setPresent"
           :is-checkbox-checked="isPresent"
           class="expires-checkbox"/>
</div>


export default {
  name: "ExperienceDetails",
  components: {YearPicker},
  props: {
    experienceInfo: {
      type: Object,
      required: false
    }
  },
  setup(props, {emit}) {
    const currentYear = ref(0);
    setCurrentYear();

    function setCurrentYear() {
      currentYear.value = new Date().getFullYear();
    }

    const endYear = ref(props.experienceInfo.endYear ? props.experienceInfo.endYear : currentYear.value);

    function setEndYear(year) {
      endYear.value = year;
    }

    const isPresent = ref(undefined);

    function setPresent() {
      isPresent.value = !isPresent.value;
      const endYearPresent = 'Nu';
      if (isPresent.value) {
        setEndYear(endYearPresent);
        props.experienceInfo.endYear = endYearPresent;
      } else {
        props.experienceInfo.endYear = ''
      }
    }

YearPicker.vue

<template>
  <div>
    <h3 class="form-input-title">{{ title }}</h3>
    <select name="startYear" id="startYear" :value="selected" class="form-input" @change="executeCallback">
      <option></option>
      <option v-for="year in validYears" :key="year" :value="year">{{year}}</option>
    </select>
  </div>
</template>

export default {
  name: "YearPicker",
  props: {
    title: {
      type: String,
      required: false
    },
    callback: {
      type: Function,
      required: true
    },
    selected: {
      type: [String, Number],
      required: false
    },
    earliestDate: {
      type: Number,
      required: true
    },
    latestDate: {
      type: [Number, String],
      required: true
    },
    presentYear: {
      type: Boolean,
      required: false
    }
  },
  setup(props) {

    onBeforeMount(calculateDateRange)
    watch(() => props.earlestDate, (newValue, prevValue) => {
      calculateDateRange()
    });
    // If there is a new value passed from the parent, the dropdown should display that new value.
    watch(() => props.latest, (newValue, prevValue) => {
      calculateDateRange()
    });


// Here I watch presentYear. If presentYear is true (checkbox is ticked) I reset validYears as an empty array so that the years will no longer be visible and instead a string 'Present' should be added.
    watch(() => props.presentYear, (newValue, prevValue) => {
      if (newValue) {
        validYears.value = [];
      } else {
        calculateDateRange()
      }
    });

    function executeCallback(event) {
      props.callback(event.target.value);
    }

    const validYears = ref([])
    function calculateDateRange () {
      for(let year = props.latestDate; year >= props.earliestDate; year--){
        validYears.value.push(year)
      }
    }

    return {
      validYears,
      executeCallback,
    }
  }
}

BasicCheckbox.vue - Here there isn't much happening.

<template>
  <div class="check-wrapper">
    <label :for="id" class="check-label">
      <input @click="checkCheckbox()"
             :id="id"
             :checked="isCheckboxChecked"
             :value="checkboxValue"
             type="checkbox"
             name="newsletter"/>
      <span v-if="labelText">{{ labelText }}</span>
      <span class="check-mark"></span>
    </label>
  </div>
</template>

<script>
  export default {
    name: 'BasicCheckbox',
    props: {
      labelText: {
        type: String,
        required: false
      },
      callback: {
        type: Function,
        required: false
      },
      id: {
        type: String,
        required: true
      },
      isCheckboxChecked: {
      },
      checkboxData: {
        type: Object,
        required: false,
      },
    },
    data: () => ({
      checkboxValue: false
    }),
    methods: {
      updateValue: function () {
        if (this.$props.callback) {
          this.$props.callback(this.$props.id, this.$props.checkboxData);
        }
      },
      checkCheckbox: function () {
        this.updateValue();
      }
    }
  };

1 Answer 1

1

Have you tried using computed properties to manage your dropdown list? That way you can add/remove the items that are toggled.

https://v2.vuejs.org/v2/guide/computed.html

e.g.

computed: {
  validYears() {
    if (this.presentYear) {
     return [];
    } else {
      return this.calculateDateRange(); // make this a vue method
    }
  },
}

I try to avoid watchers and prefer computed props and methods (the docs recommend this as well).

The computed prop will update anytime your props change (the presentYear changes), so you can re-render your list however you need.

I would also toggle components with v-show or v-if so if you want to swap a dropdown list with static text you can easily separate the logic.

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

3 Comments

I haven't given that too much thought but I think it might be something that could help me here. Would you be able to provide a brief example as to how I can go about it with a computed property?
Updated my comment with an example and some more details! hope it helps.
Thanks for this. I haven't implemented this exactly, but your answer certainly inspired me to get through this challenge.

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.