I've been stuck for 5 hours, 'im a beginner and use Vue since 2 days ago.
I just want to pass the addCrew function that pushes the value of an input in the crewArray that has id and name objects from the parent component (main.vue) to the child component (form.vue) when the "add" button is clicked. The problem is that I have created an addCrew function in the parent component (main.view) and the input is in the child component (form.vue), is there any way to get the values of input (v-model) from the child component (form.vue) to be used in the addCrew() function in the parent component (main.vue) so that the add button can work.
The addCrew() function of the add button simply says: if the input (v-model="label") is empty, the button cannot be pressed, otherwise if the input is filled (e.g. David) then the input with the string David will be added to the crewArray after the add button is clicked and the string in the input is automatically removed if the button is clicked. This is my Github : https://github.com/Darkheadbanger/WildCodeSchool_with_vue Someone please unblock me.
Parent component: Main.vue
<script setup>
import Form from "./Form.vue";
import Member from "./Member.vue";
import { defineProps, onMounted, ref } from "vue";
defineProps({});
// Je dois passer label dans le component enfant form dans le v-model: "label"
const crewArray = [
{
id: 1,
name: "Eleftheria",
},
{
id: 2,
name: "Davidthos",
},
];
const label = ref(""); // correpsond a v-model="label"
function getData() {
console.log("passed 1");
if (label.value.trim() === "") {
console.log("passed 2");
return;
} else {
console.log("passe 3");
console.log({ crewArray });
console.log("value", label);
console.log("label values", label.value);
crewArray.unshift(label.value.trim());
if (label.value.trim() !== "") {
label.value = "";
}
}
if (JSON.parse(localStorage.getItem("crew-member")) === null) {
localStorage.setItem("crew-member", JSON.stringify(crewArray));
} else {
localStorage.setItem("crew-member", JSON.stringify(crewArray));
}
}
onMounted(() => {
if (localStorage.getItem("crew-member") !== null) {
let pushCrew = crewArray.unshift(localStorage.getItem("crew-member"));
console.log(pushCrew);
}
if (localStorage.getItem("crew-member") === null) {
localStorage.setItem("crew-member", JSON.stringify(crewArray));
}
// addrCew();
});
</script>
<template>
<div>
<!-- New member form -->
<h2>Ajouter un(e) Argonaute</h2>
<!-- Form component enfant -->
<!-- v-label="label" et v-bind ou :label="label" pour créer une propre pour que cela sois transferable à l'enfant -->
<!-- :label="label"
-->
<Form Argonaute="Nom de l'Argonaute" v-model="label" :getData="getData" />
<!-- Member list -->
<h2>Membres de l'équipage</h2>
<section >
<div v-for="(members, index) in crewArray" :key="index">
<Member :members="members" />
</div>
</section>
</div>
</template>
Child component: Form.vue
<script setup>
import { defineProps } from "vue";
const props = defineProps({
// Nom de l'Argonaute
Argonaute: { type: String, required: true },
getData: { type: Function },
// Props label pour réccuperer le label dans la function addArray
label: { type: String, required: true },
});
// Je dois passer l'input de l'enfant au parents en utilisant emit car props ne fonctionne que pour parent enfant
</script>
<template>
<!-- New member form -->
<!-- v-on et @ le même -->
<!-- v-on:submit.prevent="getData()" -->
<form v-on:submit.prevent="getData()" >
<label for="addName">{{ Argonaute }}</label>
<!-- :value="props.label" pour récuperer le label du props qui se trouve dans le component forms -->
<!-- J'aimerais que cela se connecte et quand on clique le bouton ajouter, va ajouter l'input que l'utilisateur mis dans le tableau addCrew -->
<input
id="addName"
name="addName"
type="text"
autocomplete="off"
placeholder="Charalampos"
:value="props.label"
/>
<!-- v-model="label" -->
<button
id="button-add"
role="button"
type="submit"
:disabled="label === ''"
v-on:click.prevent="getData()"
>
Ajouter
</button>
</form>
<!-- Member list -->
</template>
CodePudding user response:
if you want to fire a function of the parent component i suggest using a simple emit from the child. The parent will listen to this emit and then can easily execute a function, for example the getData().
Thus the in the form.vue emit a event when clicked on the button like so
<script>
export default {
methods: {
onClick() {
this.$emit('on-click');
}
}
</script>
--------
<button
id="button-add"
role="button"
type="submit"
:disabled="label === ''"
@click="onClick"
>
then listen for the emit in the parent component like so.
<Form Argonaute="Nom de l'Argonaute" v-model="label" @on-click="getData"/>
note that you should always use kebab-case when listening for events and emitting events. also look at the documentation of vue listening to child components
CodePudding user response:
What you want to do is pass a parameter when you emit from the child component, this means that the $emit(...)
method should have two parameters, one for the name of the method that the parent component will call, and the second for the data that you want to transmit. For example, if the child component has a data member called 'memberName', then you can bind that data member to the input using v-model="memberName"
. Then if the same child component emits an addMember
method, then in the emit method call pass in both the emit function name and the memberName parameter:
<button type="submit" @click.prevent="$emit('addMember', memberName)">
Add Member
</button>
The whole child component, say named Form2.vue, could look like:
<script>
export default {
emits: ["addMember"],
data() {
return {
memberName: "",
};
},
};
</script>
<template>
<form>
<label for="addName"> Argonaute: </label>
<input
type="text"
id="addName"
placeholder="Jason"
v-model="memberName"
/>
<button type="submit" @click.prevent="$emit('addMember', memberName)">
Add Member
</button>
</form>
</template>
A simple Member2.vue component:
<script>
export default {
props: {
member: Object,
},
};
</script>
<template>
<li>{{ member.id }}) {{ member.name }}</li>
</template>
and the main App.vue:
<script>
import Member2 from "./components/Member2.vue";
import Form2 from "./components/Form2.vue";
export default {
components: { Member2, Form2 },
data() {
return {
crewArray: [
{ id: 1, name: "Eleftheria" },
{ id: 2, name: "Davidthos" },
],
};
},
methods: {
addMember(memberName) {
// get maximum id, and then make a new id that is 1 larger
let max = -1;
let maxArray = this.crewArray.reduce((prev, current) => {
if (current.id > prev.id) {
return current;
} else {
return prev;
}
});
let newId = maxArray.id 1;
// add new crew member to the crew array
this.crewArray.push({
id: newId,
name: memberName,
});
},
},
};
</script>
<template>
<div>
<h2>Add an Argonaut</h2>
<p>
<Form2 @add-member="addMember"></Form2>
</p>
<!-- form2 here -->
<h2>Crew Members</h2>
<ul>
<Member2
v-for="crewMember in crewArray"
:key="crewMember.id"
:member="crewMember"
>
</Member2>
</ul>
</div>
</template>
<style scoped>
ul {
list-style: none;
}
</style>