Vue.js 3 SFC passing data to siblings

116 views Asked by At

I am trying to pass a prop between sibling elements (a card and an input) and so far it has not been successful.

I have a button nested within a card element. When someone is pressing a button, I emit an ID of the card to the button element. Then I want this to be displayed within my input element label.

My code for the button ButtonElement.vue component looks like this:

<script setup>
defineProps({
    editBtn: {
        type: String
    }
})
</script>


<template>
    <button type="button" class="btn btn-outline-light btn-sm ms-5">{{ editBtn }}</button>
</template>  

the card element vue file (CardElement.vue), looks as below:

<script setup>
import ButtonElement from './ButtonElement.vue'

defineProps({
  header: {
    type: String,
    required: true
  }
})
</script>

<template>
  <div class="col-sm-6 col-12 d-flex justify-content-center align-items-center">
    <div class="card text-white mb-3">
      <div class="card-header">
        {{ header }} 
        <ButtonElement @click="$emit('displayBtnId', header)" :id="header" edit-btn="Add item"></ButtonElement>
      </div>
      <div class="card-body">
        <p class="card-text">
        </p>
      </div>
    </div>
  </div>  
</template>

The input element, where I want to pass the id of the button on click is like that, InputElement.vue:

<script setup>
defineProps({
  inputLabel: {
    type: String
  },
})
</script>

<template>
  <div class="col-12 d-flex justify-content-center align-items-center">
    <div class="input-group">
  <span class="input-group-text">{{ inputLabel}}</span>
  <textarea class="form-control"></textarea>
</div>
  </div>  
</template>

I included the card, with the button inside within the app.vue and it looks like this:

<script setup>
import { ref } from 'vue';
import CardElement from './components/CardElement.vue';
import InputElement from './components/InputElement.vue';


const selectedHeader = ref('');
function displayBtnIdOnInput(header){
  console.log(header)
  
  selectedHeader = header;
  console.log('id ' + selectedHeader)
}
</script>

<template>
  <main>
    <div class="row mt-4 mb-4">
      <CardElement type="bg-primary" header="Typical"  v-on:displayBtnId="displayBtnIdOnInput"> hvkhbkjb</CardElement>
      <CardElement type="bg-warning" header="Non-typical" v-on:displayBtnId="displayBtnIdOnInput"> hvkhbkjb</CardElement>
    </div>
    <div class="row mt-4 mb-4">
      <InputElement> {{ selectedHeader }}</InputElement>
      //<InputElement input-label="selectedHeader "></InputElement>

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

I commented out the //, as in this way the label is 'selectedHeader ', rather than the variable.

Can someone please point me to a solution or some articles on how to do it best?

Many thanks!

1

There are 1 answers

1
fOURP On

Your code has several issues. Ref variables needed .value.

selectedHeader.value = header;

You did not define emits. You need to define them like you defined props. (Actually your $emit should work. But you forgot to catch the @emit on Card.vue. I am just used to defining them.)

const emit = defineEmits(['displayBtnId'])
<ButtonElement @click="emit('displayBtnId', header)" :id="header" edit-btn="Add item"></ButtonElement>

You also forgot to pass the props to the input elements to update the value..

<InputElement :input-label="selectedHeader"> {{ selectedHeader }}</InputElement>
<InputElement :input-label="selectedHeader"></InputElement>

I made a playground with your code and some fixes. Not sure if that's what you wanted as an end result but you could try creating your own playground next time. You have higher chances of getting an answer.

Check this playground