Ways to transfer selected options from a dropdown menu to a higher-level component

I am currently in the process of configuring a modal component that showcases various data from a specific record to the user. The user is provided with a Bulma dropdown component for each field, enabling them to make changes as needed. To streamline the code and avoid repetition, I placed the dropdown into its own component. However, I am facing an issue where the parent component needs to pass API data to the child component as a prop, but the child component also needs to notify the parent when a selection is made. This way, the parent can update the prop being passed and ensure consistency in the data before sending updates back to the API. I have explored options like using v-model, but existing examples do not seem suitable for my particular case.

<template>
  <div class="dropdown" :class="dropdownClass">
    <label class="dropdown-label">{{ label || "" }}</label>
    <div class="dropdown-trigger" @click="toggleDropdown">
      <button
        class="button ticket-tags is-fullwidth"
        :style="{
          'background-color': backgroundColor,
          color: textColor,
          border: borderStyle
        }"
      >
        <span>{{ firstItem || "" }}</span>
        <span class="icon is-small">
          <i class="bx bx-chevron-down"></i>
        </span>
      </button>
    </div>
    <div class="dropdown-menu">
      <div class="dropdown-content">
        <div
          class="dropdown-item"
          v-for="item in items"
          :key="item.data"
          @click="itemSelected"
        >
          {{ item.data }}
        </div>
      </div>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from "vue";

const dropdownComponent = defineComponent({
  name: "Dropdown",
  props: {
    label: {
      type: String
    },
    firstItem: {
      type: String,
      required: true
    },
    items: {
      type: Array
    },
    backgroundColor: {
      type: String
    },
    textColor: {
      type: String
    },
    borderStyle: {
      type: String
    }
  },
  emits: ["itemSelected"],
  setup: (props, context) => {
    const dropdownClass = ref("");
    const toggleDropdown = () => {
      dropdownClass.value =
        dropdownClass.value === "is-active" ? "" : "is-active";
    };
    const itemSelected = (item) => {
      dropdownClass.value = "";
      context.emit("itemSelected", item);
    };
    return {
      toggleDropdown,
      dropdownClass,
      itemSelected
    };
  }
});

The above code snippet illustrates how the dropdown works. The parent component supplies an array of options (items) and specifies which option should be displayed initially (firstItem). I am seeking a method for the child component to update the parent's firstItem value. It is possible that my approach is incorrect, so any guidance on this matter would be greatly appreciated. Thanks in advance!

Answer №1

Could you please demonstrate the workaround in your parent's vue-file? I'll be able to provide a solution once I have that information.

It seems that using setup() may not be the best approach in this case, especially since you want to trigger itemSelected() after the view has been rendered.

UPDATE:

You might already have a solution, but here is my recommendation:

methods: {
   itemSelected(item) {
     this.$emit("itemSelected", item)
   }
}

And within your element:

<div
   class="dropdown-item"
   v-for="item in items"
   :key="item.data"
   @click="itemSelected(item)"
   >
      {{ item.data }}
</div>

According to the documentation Setup | Vue.js, when setup is called, the component hasn't been created yet. Therefore, your emit function will not work as intended.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Why does the method of type assigning vary between actual and generic types?

There are no errors in the code shown below: type C = {b: string}; class Class { data: C; constructor(data: C) { this.data = data; } test() { const hack: C & {a?: any} = this.data; //no error } } However, when a g ...

Struggling to properly import the debounce function in ReactJS when using TypeScript

I am facing an issue while trying to properly import the debounce library into my react + typescript project. Here are the steps I have taken: npm install debounce --save typings install dt~debounce --save --global In my file, I import debounce as: impo ...

The data type 'A | B' cannot be assigned to type 'A & B'

What could be causing the compilation error in this code? type A = { n: number } type B = { s: string } type Thing = { a: A b: B } function update(obj: Thing, path: keyof Thing) { obj[path] = obj[path] } It seems like both sides of the assignment sh ...

Tips for avoiding errors when determining the length of a child node in Firebase within a vue.js application by utilizing the "Object.keys" function

Let's envision a Vue.js application where the data structure stored in firebase looks something like this: item: { name: itemName, childOne: { subChildA: true, subChildB: true }, childTwo: { subChildA: true, subChildB: true ...

The index type '{id:number, name:string}' is not compatible for use

I am attempting to generate mock data using a custom model type that I have created. Model export class CategoryModel { /** * Properties */ public id : number; public name : string; /** * Getters */ get Id():number{ return this.id; ...

What is the method to include a class in the "template" tag within vue?

Can someone please advise on how to attach a class to the "template" tag in Vue? <template #popover class: templateClass // Wishing to include a class here, is it feasible? > <router-link v-close-popover to="/somewhere" ...

Angular 8's array verification feature lacks the ability to recognize preexisting elements

I've been trying to add and delete items in an array when a user selects or deselects the same item. However, it appears that either my array is not working properly or there is a bug in my code causing it to fail. <div class="grp-input"> ...

The date error from day.js in Firefox is not valid

My date is formatted as 2022-01-27 09:23:48 UTC and I am trying to parse it into MMMM-DD-YYYY format (Jan-27-2022) using day.js. The parsing works well in Chrome, but Firefox returns an 'Invalid' result. import dayjs from "dayjs" const ...

Can someone please explain how to prevent Prettier from automatically inserting a new line at the end of my JavaScript file in VS Code?

After installing Prettier and configuring it to format on save, I encountered an issue while running Firebase deploy: 172:6 error Newline not allowed at end of file eol-last I noticed that Prettier is adding a new line at the end when formatting ...

Compatibility of Vue-apexcharts with different versions

Which versions are compatible with vue-apexcharts on platforms such as "Windows", "Linux", "Mac", "Android", "iOS", and "Tablet"? ...

The chart appears oversized in the vue js. How can I make it smaller in size?

I recently integrated a line chart from Chart JS into my Vue.js project, but the chart is taking up too much space on my webpage. I'm looking for ways to make it appear smaller and more compact. This is my first time working with charts in Vue.js, so ...

Double Calling of Angular Subscription

I am currently working with a series of observables that operate in the following sequence: getStyles() --> getPrices() Whenever a config.id is present in the configs array, getStyles() retrieves a style Object for it. This style Object is then passed ...

Vue Basic Components 'T' has not been declared

After updating to Vue 3.4.30, I encountered an issue while trying to use Generic components. When attempting to use T as a type for a property, I received an error message. Any guidance or suggestions on how to resolve this would be greatly appreciated. I ...

Guide to swapping out embedded objects within a TypeScript data structure

I am in need of modifying a TypeScript object by conducting a key search. It is important to note that the key may be repeated within the object, so I must ensure it belongs to the correct branch before making modifications to the corresponding object. To ...

typescript function intersection types

Encountering challenges with TypeScript, I came across the following simple example: type g = 1 & 2 // never type h = ((x: 1) => 0) & ((x: 2) => 0) // why h not never type i = ((x: 1 & 2) => 0)// why x not never The puzzling part is w ...

Tips for Sending Variables in HTTP Requests in Angular 9

'''Is there a way to pass fromDateTime and toDateTime as parameters in this link?''' export function MSALInterceptorConfigFactory(): MsalInterceptorConfiguration { const protectedResourceMap = new Map<string, Array& ...

Static Nuxt: Issue with Loading Fetched State on New Routes

I'm setting up a fully static web application using Nuxt, as detailed on this page In addition to the main site, I have a small blog that needs data from an API. To achieve this, I am utilizing the fetch hook. async fetch() { this.posts = await fet ...

Simplify an array in Javascript

I have a collection of objects structured in the following way: let list = [ { 'items': [ 'item 1', 'item 2' ] }, { 'items': [ 'item 3' ] } ] My goal is to flatte ...

Learn how to efficiently add multiple variables to all your SCSS files in Nuxt using the loaders prependData feature

I am using Nuxt 2.13 and sass-loader 8.0.2. I want to add two environment variables to my SCSS files. I have successfully added one variable using loaders in the build section of Nuxtjs: build: { loaders: { scss: { prependData: `$base_url ...

Are the frameworks Vue, Angular, and React known for

During a conversation, I came across an interesting viewpoint criticizing popular frameworks such as Angular, Vue, and React. It was argued that these frameworks have a significant disadvantage: apart from the API part that interacts with the server's ...