Home > database >  How to push a prop passed from a parent component to an array in the child component?
How to push a prop passed from a parent component to an array in the child component?

Time:10-21

I have 3 components. One parent component and two child components. The two child components are siblings.

Parent Component

 <template>
  <div >
    <div >

        <Modal :popupTitle="popupTitle" @addLocation="addLocation($event)"/>
        
        <BinInfo :newBinLocation="newBinLocation"/>

        <button data-bs-toggle="modal" data-bs-target="#staticBackdrop">Add new bin</button>
    </div>
  </div>  
 </template>

<script>


export default {
    data(){
      return{
        popupTitle:"Add New Bin Location",
        newBinLocation: '',
      }
   },
   methods:{
     addLocation(newBinLocation){
       this.newBinLocation = newBinLocation
     }
   },
  components:{
      Navigation,
      TopBtns,
      BinInfo,
  }
}
</script>


In one child, which is the listing component, I am showing a listing from an array

Listing Component

<template>
<div >
    <h2>Bins - Location</h2>
    <h5 v-if="bins.length==0">There are no bin locations added</h5>
    <table  v-if="bins.length > 0">
        <thead>
        <tr>
            <th scope="col">#</th>
            <th scope="col">Location</th>
            <th scope="col" >Action</th>
        </tr>
        </thead>
        <tbody>
        <tr v-for="(bin, index) in bins" :key="index">
            <th scope="row">{{index   1}}</th>
            <td><input ref="inputField" type="text" :value="bin.binlocation" :disabled="bin.disabled" @change="editedLocation=$event.target.value"></td>
            <td >
            <div >
                <button @click="btnEdit(index)"><fa icon="edit" /> Edit</button>
                <button @click="btnUpdate(index)"><fa icon="edit" /> Update</button>
                <button @click="btnDelete(index)"><fa icon="trash" /> Delete</button>
            </div>
            </td>
        </tr>
        </tbody>
    </table>
    <div >
        <router-link to="/bins">View More</router-link>
    </div>
</div>
{{newBinLocation}}

</template>

<script>
export default {
    data(){
        return{
            bins:[
                {
                    binlocation: '11 Garden Block, New City',
                    disabled: true
                },
                {
                    binlocation: 'Ali Towers, Lahore',
                    disabled: true
                },
                {
                    binlocation: 'The Mall Road',
                    disabled: true
                }
            ],
            editedLocation: null,
        }
    },
    props:['newBinLocation'],
    methods:{
        btnDelete(index){
           this.bins.splice(index, 1)
        },
        btnEdit(index){
         this.bins[index].disabled = !this.bins[index].disabled;
         this.editedLocation = this.bins[index].binlocation
         /*if(this.bins[index].disabled === false){
             console.log(this.$refs.inputField)
         }*/
        },
        btnUpdate(index){
           this.bins[index].binlocation = this.editedLocation
           this.bins[index].disabled = !this.bins[index].disabled
           console.log(this.bins[index].binlocation)
        },
        btnAdd(){
            let newLocation = {
                binlocation: this.newBinLocation,
                disabled: true
            }
            this.bins.push(newLocation)
        }
    },
}
</script>

<style scoped>
.table-responsive{
    margin-bottom:25px;
}
h2{margin:0 0 15px;}
.action-btn button{
    border:0;
    background:#003594;
    color:#fff;
    margin-left:15px;
    padding:3px 15px;
}
.action-btn button:hover{
    background:#3490dc
}
input{
    background-color:none;
    border:0;
    color:#000;
}
</style>

and in the second child component, I have created a modal which I am using to add a new list.

Modal Component

<template>
  <div  id="staticBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
  <div >
    <div >
      <div >
        <h5 >{{popupTitle}}</h5>
        <button type="button"  data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div >
        <p><input type="text" v-model="addBinLocation"></p>
      </div>
      <div >
        <button @click="btnAdd" type="button" >Add Location</button>
      </div>
    </div>
  </div>
</div>
</template>

<script>
export default {
    props:['popupTitle'],
    data(){
      return{
        addBinLocation: ''
      }
    },
    methods:{
      btnAdd(){
        this.$emit('addLocation', this.addBinLocation)
    }
  }
}
</script>

<style>

</style>

I am able to add and receive the values but how can I add the new prop into the existing array so that it is added in the list.

CodePudding user response:

There is a way to add the newBinLocation with a computed property in the Listing Component, but it isn’t the cleanest way to do this.

You made a architecture error by declaring the bins array in the Listing Component. The parent component should be the one aware of the data. the Listing Component is only here to print a list.

You should pass the array from the Parent Component as a props. This way the Listing Component will be easily reusable.

Once you’ve done that it’s easy to add an new item to the array.

Here is an example

Parent component

 <template>
  <div class="wrapper">
    <div class="main-content">

        <Modal :popupTitle="popupTitle" @addLocation="addLocation($event)"/>
        
        <BinInfo :bins="bins"/> <-- You need to pass the array instead of newBinLocation -->

        <button data-bs-toggle="modal" data-bs-target="#staticBackdrop">Add new bin</button>
    </div>
  </div>  
 </template>

<script>


export default {
    data() {
      return {
        popupTitle:"Add New Bin Location",
        bins:[
                {
                    binlocation: '11 Garden Block, New City',
                    disabled: true
                },
                {
                    binlocation: 'Ali Towers, Lahore',
                    disabled: true
                },
                {
                    binlocation: 'The Mall Road',
                    disabled: true
                }
          ],
      }
   },
   methods:{
     addLocation(newBinLocation){
       this.bins.push(newBinLocation) // You just have to push the new value
     }
   },
  components:{
      Navigation,
      TopBtns,
      BinInfo,
  }
}
</script>
  • Related