Vue 3 props are not passed to the child element - vuejs3

I'm trying to pass an object to a child element as a prop, but I get an arr[0] val instead of { id: 1, name: 'General' }.
There I bind prop value, currentRoom is a const with Object.
<input-message :currentRoom="currentRoom"/>
currentRooms value is correct there and equals {id: 1, name: 'General'}.
In child element I try to get props that way:
const props = defineProps({
currentRoom: Object
});
The whole code:
container.vue
<template>
<AppLayout title="Dashboard">
<template #header>
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
Chat
</h2>
</template>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
<message-container :room="currentRoom"/>
<input-message :currentRoom="currentRoom" :customText="'blablabla'"/>
</div>
</div>
</div>
</AppLayout>
</template>
<script setup>
import AppLayout from '../../Layouts/AppLayout.vue';
import MessageContainer from "./messageContainer.vue";
import InputMessage from "./inputMessage.vue";
import {defineComponent} from "vue";
defineComponent([
AppLayout,
MessageContainer,
InputMessage
])
let chatRooms = [];
let currentRoom = [];
let messages = [];
const getRooms = () => {
axios.get('/chat/rooms')
.then( response => {
chatRooms = response.data;
setRoom(response.data[0]);
})
.catch(error => {
console.log(error);
})
}
const setRoom = (room) => {
currentRoom = room;
// If I console.log currentRoom here, it is displayed correctly!
console.log(currentRoom)
getMessages();
}
const getMessages = () => {
axios.get('/chat/rooms/' + currentRoom.id + '/messages')
.then(response => {
messages = response.data;
})
.catch(error => {
console.log(error);
});
}
getRooms();
</script>
inputMessage.vue
<template>
<div class="relative h-10 m-1">
<div style="border-top: 1px solid #e6e6e6;" class="grid grid-cols-6">
<input
type="text"
v-model="message"
#keyup.enter="sendMessage"
placeholder="Say something..."
class="col-span-5 outline-none p-1"
/>
<button
#click="sendMessage"
class="place-self-end bg-gray-500 hover:bg-blue-700 p-1 mt-1 rounded text-white">
Send
</button>
</div>
</div>
</template>
<script setup>
const props = defineProps({
currentRoom: Object
// customText: Text
});
console.log(props.currentRoom);
</script>

UPDATE
You currentRoom data property is not reactive. So, I guess, it triggers no updates to the props. You should define it this way:
const currentRoom = reactive({});
or
const currentRoom = ref({});
In case of ref() you have then change the value of the ref like this
currentRoom.value = room;
Hope it helps.
Your currentRoom is an Array. That's why you get [] in the console, when your array is empty.
Check your axios request if you get any data at all. (Browser DevTools Network Tab)
Generally, you should pass one room item to your currentRoom prop or threat your prop as array.
Like this:
<table border=1>
<tbody>
<tr v-for="(room, index) in props.currentRoom">
<td>{{index}}</td>
<td>{{room.id}}</td>
<td>{{room.name}}</td>
</tr>
</tbody>
</table>
Here is a working playground

Just do it right way and it will work.
const { createApp, ref } = Vue;
const MyComponent = {
props: {
currentRoom : {
type: Object,
default: {}
}
},
setup(props) {
console.log(`props.currentRoom: ${JSON.stringify(props.currentRoom)}`)
},
template: `<div class="MyComponent">currentRoom: {{JSON.stringify(currentRoom)}}</div>`
}
const App = {
components: {
MyComponent
},
setup() {
const rooms = ref([]);
const addRoom = () => { rooms.value.push( {id: rooms.value.length + 1, name: 'General'} ); }
return { rooms, addRoom }
}
}
const app = createApp(App)
app.mount('#app')
.MyComponent {
border: 1px solid grey;
padding: 12px;
margin: 4px;
}
<div id="app">
App.rooms: {{rooms}}<hr/>
rooms[0]: <my-component :current-room="rooms[0]"></my-component>
rooms: <my-component v-for="room in rooms" :current-room="room"></my-component>
<button type="button" #click="addRoom()">Add Room</button>
</div>
<script src="https://unpkg.com/vue#3/dist/vue.global.prod.js"></script>

Related

getServerSideProps pass Undefined value

Sticker.ts
import React from "react";
import Image from "next/image";
import {GetServerSideProps, InferGetServerSidePropsType } from 'next';
import Product from "models/Product";
import currencyFormatter from "lib/currencyFormatter";
import mongoose from "mongoose";
import handler from "pages/api/pincode";
// const Sticker = (props: any) => {
const Sticker = ({products}) => {
// const products = JSON.parse((props?.products));
console.log("list of product "+ products)
return (
<div>
<section className="text-gray-600 body-font">
<div className="container px-5 py-24 mx-auto">
<div className="flex flex-wrap -m-4 justify-centr">
{/* {products?.map((dt: any, idx: number) => */}
{/* <div className="lg:w-1/4 md:w-1/2 p-4 w-full" key={idx}> */}
<div className="lg:w-1/4 md:w-1/2 p-4 w-full" >
{/* <a href={`./product/${dt?.category}/${dt?.id}`} className="block relative h-68 rounded overflow-hidden"> */}
<a href="./product/{category}/slug[jhbjh]" className="block relative h-68 rounded overflow-hidden">
<Image
alt="ecommerce"
className="object-cover cursor-pointer object-center w-full h-full block"
src="https://m.media-amazon.com/images/I/61SFAM62ucL._SL1280_.jpg"
width="100"
height="100"
/>
</a>
<div className="mt-4">
<h3 className="text-gray-500 text-xs tracking-widest title-font mb-1">
Home Decor
</h3>
<h2 className="text-gray-900 title-font text-lg font-medium">
Paper Plane Design Quote and Motivational Posters 12X18
</h2>
<p className="mt-1">{currencyFormatter(179)}</p>
</div>
</div>
{/* )} */}
</div>
</div>
</section>
</div>
);
};
export async function getServerSideProps(context) {
if(!mongoose.connections[0].readyState){
await mongoose.connect(process.env.MONGO_URI)
}
let products = await Product.find()
return {
// props: { products },
props: { products : JSON.parse(JSON.stringify(products)) },
}
}
export default Sticker;
_app.tsx
import React, { useEffect, useState } from 'react'
import { NextUIProvider, useSSR } from '#nextui-org/react';
import '../styles/globals.css'
import Navbar from '../modules/body/Navbar';
import Footer from '../modules/body/Footer';
import theme from "../themes";
import { AppProps } from 'next/app';
// import SideNavbar from '../mainComponent/SideNavbar'
function MyApp({ Component, pageProps }: AppProps) {
const [cart, setCart] = useState<object>({})
const [subTotal, setSubTotal] = useState<number>(0)
const { isBrowser } = useSSR();
useEffect(() => {
try {
if (localStorage.getItem("cart")) {
setCart(JSON.parse(localStorage.getItem("cart") || ""))
saveCart(JSON.parse(localStorage.getItem("cart") || ""))
}
} catch (error) {
console.log(error);
localStorage.clear()
}
}, [])
const saveCart = (myCart: object) => {
localStorage.setItem("cart", JSON.stringify(myCart))
// let keys = Object.keys(myCart);
const subt = Object.values(myCart).reduce((acc, curr) => acc + curr?.price * curr?.qty,0);
setSubTotal(subt)
}
const addToCart = (itemCode, qty, price, name, size, variant) => {
let newCart = cart;
if (itemCode in cart) {
newCart[itemCode].qty = cart[itemCode].qty + qty
}
else {
newCart[itemCode] = { qty: 1, price, name, size, variant }
}
setCart(newCart)
saveCart(newCart)
}
const removeFromCart = (itemCode, qty, price, name, size, variant) => {
let newCart = JSON.parse(JSON.stringify(cart));
if (itemCode in cart) {
newCart[itemCode].qty = cart[itemCode].qty - qty
}
if (newCart[itemCode]["qty"] <= 0) {
delete newCart[itemCode]
}
setCart(newCart)
saveCart(newCart)
}
const clearCart = () => {
setCart({})
saveCart({})
}
return isBrowser && (
<NextUIProvider theme={theme}>
<Navbar key={subTotal} cart={cart} addToCart={addToCart} removeFromCart={removeFromCart}
clearCart={clearCart} subTotal={subTotal} />
{/* <SideNavbar /> */}
<Component cart={cart} addToCart={addToCart} removeFromCart={removeFromCart}
clearCart={clearCart} subTotal={subTotal} {...pageProps} />
<Footer />
</NextUIProvider>
)
}
export default MyApp
I tried every method posted on the browser but still it shows undefined. If you help me to find out the solution of this problem then i will be very happy and feel blessed with this coding environment. please solve this as soon as possible. My whole project is stucked because of this error.

props is undefined when passing from parent to component in next js

I have /pages/profile.js which calls the LovedOne element, passing values from props.
Debugging shows that these values are valid when passed
import React from "react";
import LovedOne from "../components/loved_one";
export const Profile = ({ loved_ones }) => {
const [session, loading] = useSession();
if (loading) return <div>loading...</div>;
if (!session) return <div>no session</div>;
return (
<Layout>
{session && (
<>
<img src={session.user.image} className="avatar" />
<h1>{session.user.name}</h1>
</>
)}
{loved_ones.map((loved_one, index) => (
<LovedOne
key={index}
firstname={loved_one.firstname}
surname={loved_one.surname}
email={loved_one.email}
/>
))}
<style jsx>{`
.avatar {
width: 220px;
border-radius: 10px;
}
`}</style>
</Layout>
);
};
However in /components/loved_one.js my props is undefined
import React, { useState, useRef } from "react";
export const LovedOne = ({ props }) => {
const [setActive, setActiveState] = useState("");
const [setHeight, setHeightState] = useState("0px");
const content = useRef();
function toggleAccordion() {
setActiveState(setActive === "" ? "active" : "");
setHeightState(
setActive === "active" ? "0px" : `${content.current.scrollHeight}px`
);
}
return (
<div>
<div className="row">
<button
className={`collection-item ${setActive}`}
onClick={toggleAccordion}
>
<i className="fas fa-plus teal-text"></i>
</button>
<div className="col s2">
{props.firstname} {props.surname}
</div>
<div className="col s2">{props.email}</div>
</div>
<div ref={content} style={{ maxHeight: `${setHeight}` }}>
<span>some stuff</span>
</div>
</div>
);
};
export default LovedOne;
I've tried passing single variables, and passing the entire loved_ones object. I get the same problem.
Any help much appreciated!
Have you tried passing props instead of {props} ?
lose brackets, try this way:
export const LovedOne = (props) => {

How to catch click event with addEventListener

I am having a modal with button inside. Unfortunatly, it's not properly working. During the build I got an error : TypeError: Cannot read property 'addEventListener' of null
Below is the code:
import React from "react";
import { Modal } from "react-bootstrap";
import '../../assets/styles/Login.css';
class LoginRegisterModal extends React.Component {
constructor(props, context) {
super(props);
this.state = {show: false};
}
componentDidMount(){
const signUpButton = document.getElementById('signUp');
const signInButton = document.getElementById('signIn');
const container = document.getElementById('container');
signUpButton.addEventListener('click', () => {
container.classList.add('right-panel-active');
});
signInButton.addEventListener('click', () => {
container.classList.remove('right-panel-active');
});
}
....
render() {
const styleModal = {
marginTop: "15%",
marginLeft: "30%",
padding: 0,
width:770,
height:480,
backgroundColor:"#ffffffff",
borderRadius:21.5,
}
return (
<Modal show={this.state.show} style={styleModal} >
<div class="container" id="container">
<div>
.....
</div>
<div class="overlay-container">
<div class="overlay">
<div class="overlay-panel overlay-left">
<h1>Sign in.</h1>
<p>
Nice to see you again.Login and continue the journey.
</p>
<button class="ghost" id="signIn">Sign In</button>
</div>
<div class="overlay-panel overlay-right">
<h1>Hey, new friend!</h1>
<p>New to the Village? Sign up and start your journey</p>
<button class="ghost" id="signUp">Sign Up</button>
</div>
</div>
</div>
</div>
</Modal>
);
}
}
export default LoginRegisterModal;
I have tried adding a if condition before the addListener but it's just fixing the error but not working.
Also I have tried to replace by onClick instead but it's not working the code
signUpButton = () => {
container.classList.add('right-panel-active');
}
but container is not known..
Any idea?
Thanks
Your code should be inside component did mount method componentDidMount(). That's because when you look for a element with id "signUp" it doesn't exist yet. I don't encourage you to do what you are doing. A better approach would be <button onClick={myMethod}>

TypeError: results.map is not a function Function.renderemployeeTable

I was trying to display api data using reactJs Application. i used the following code but i keep getting the following error
TypeError: results.map is not a function
Function.renderemployeeTable
export class FetchData extends Component {
static displayName = FetchData.name;
constructor(props) {
super(props);
this.state = { results: [] };
}
componentDidMount() {
fetch('urll', {
method: 'GET',
headers: {
'api-key': 'api-key'
}
})
.then(results => results.json())
.then(data => this.setState({ results: data }));
}
static renderemployeeTable(results) {
return (
<div class="container-fluid" class="row" fluid={true}>
{
results.map(results =>
<div class="col-sm-3" key={results.Employee_Number}>
<div class="card our-team" >
<div class="card-body">
<p class="card-text">{results.first_name}</p>
<p class="card-text">{results.last_name}</p>
</div>
</div>
Detail
</div>
)
}
</div>
);
}
render() {
let contents = this.state.loading
? <p><em>Loading...</em></p>
: FetchData.renderemployeeTable(this.state.results);
return (
<div>
<h1 id="tabelLabel" >-</h1>
{contents}
</div>
);
}
async populateemployeeData() {
const response = await fetch('table');
const data = await response.json();
this.setState({ results: data, loading: false });
}
}
but i get this error message
TypeError: results.map is not a function
Function.renderemployeeTable
This is the output of console.log(results).
"data": {
"Table": [
{
"id": 14258,
"first_name": "yibgeta",
"last_name": "solans",...
}]}],
Now it will work------
constructor(props) {
super(props);
this.state = { results: [] };
}
componentDidMount() {
fetch('http://web.api.services/api/v2/tultula/employees/all', {
method: 'GET',
headers: {
'api-key': '7cefc4163dula77bf0f41ba741c'
}
})
.then(results => results.json())
.then(data => this.setState({ results: data }));
}
render() {
if(this.state.result != null && this.state.result!= undefined){
return (
<div class="container-fluid" class="row" fluid={true}>
{
this.state.results.map(results =>
<div class="col-sm-3" key={results.Employee_Number}>
<div class="card our-team" >
<div class="card-body">
<p class="card-text">{results.first_name}</p>
<p class="card-text">{results.last_name}</p>
</div>
</div>
Detail
</div>
)
}
</div>
);}
let contents = this.state.loading
? <p><em>Loading...</em></p>
: FetchData.renderemployeeTable(this.state.results);
return (
<div>
<h1 id="tabelLabel" >-</h1>
{contents}
</div>
);
}
async populateemployeeData() {
const response = await fetch('table');
const data = await response.json();
this.setState({ results: data, loading: false });
}
}
Did you have ever try to write down like this?
data => this.setState({
results: data.Table
})
Or
results.Table.map(result => ...)
Try
{
results.Table && results.Table.map( result =>...)
}
This will ensure that the array exists and then you can use map function on it.
Try in this way:-
import React, { Component } from "react";
class Example extends Component {
constructor(props) {
super(props);
this.state = { results: [] };
}
componentDidMount() {
fetch("url", {
method: "GET",
headers: {
"api-key": "api-key"
}
})
.then(results => results.json())
.then(data => this.setState({ results: data }));
}
renderemployeeTable(results) {
return (
<div className="container-fluid" className="row" fluid={true}>
{results.map(results => (
<div className="col-sm-3" key={results.Employee_Number}>
<div className="card our-team">
<div className="card-body">
<p className="card-text">{results.first_name}</p>
<p className="card-text">{results.last_name}</p>
</div>
</div>
<a href="#" className="btn btn-primary">
Detail
</a>
</div>
))}
</div>
);
}
render() {
let contents = this.state.loading ? (
<p>
<em>Loading...</em>
</p>
) : (
this.renderemployeeTable(this.state.results)
);
return (
<div>
<h1 id="tabelLabel">-</h1>
{contents}
</div>
);
}
async populateemployeeData() {
const response = await fetch("table");
const data = await response.json();
this.setState({ results: data, loading: false });
}
}
export default Example;

How do I push new data in an array stored in Firestore

I've got my data stored in Firestore as follows:
Its data is retrieved as follows:
created () {
db.collection('cards').where('user', '==', this.user)
.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
const data = {
'id': doc.id,
'group_name': doc.data().group_name,
'group': doc.data().group,
'size': doc.data().group.length
}
this.cards.push(data)
})
})
}
And finally rendered in the following way:
<div v-for="(card, groupIndex) in cards" v-bind:key="card.id" class="card-group">....</div>
All works as desired. The thing is how do I add a new slot with data to the group-array in firestore. After having searched the internet it seems that it's not possible to push new data in an array stored in firestore. Is this true or are there possibilities?
If not possible do I need to store my data as an object and how do I v-for true its content?
below the complete code:
<template>
<div id="dashboard">
<div style="margin-bottom: 50px">
<div v-for="(card, groupIndex) in cards" v-bind:key="card.id" class="card-group">
<div :id="card.group_name" class="card-group-header" #click="toggleChild" >{{card.group_name}}
<div class="group-count-label"> {{card.size}} </div>
<div class="right">
<div :id="card.group_name + 'B'" class="dropdown-arrow"></div>
<div style="margin-right:10px;font-size:15px">⋮</div>
</div>
</div>
<div class="card-group-items hidden-group" :id="card.group_name + 'A'">
<div v-for="(value, index) in card.group" v-bind:key="index" class="collection-item">
<div :id="card.group_name + index" class="card-group-item-header" #click="toggleItem" >
<div class="card-group-item-header-text">
<div class="card-group-item-header-text-front">{{value.front}}</div>
<div class="card-group-item-header-text-back">{{value.back}}</div>
</div>
<div class="right">
<div :id="card.group_name + index + 'B'" class="dropdown-arrow-b"></div>
<div style="margin:7px 10px 0px 0px;font-size:15px">⋮</div>
</div>
</div>
<!-- ITEM -->
<div :id="card.group_name + index + 'A'" class="card-group-item">
<div>
<div class="textbox-tip">Front</div>
<input type="text" class="card-group-item-input" :value="value.front" spellcheck="false">
</div>
<div>
<div class="textbox-tip">Back</div>
<input type="text" class="card-group-item-input" :value="value.back" spellcheck="false">
</div>
<!-- CARD EXAMPLES -->
<div class="card-group-examples">
<div class="card-group-example-header"><div>Examples</div><div class="card-group-example-header-plus" #click="addExample(groupIndex,index)">+</div></div>
<div v-for="(v, i) in value.examples" v-bind:key="i">
<div>
<div class="textbox-tip">Example {{i+1}}</div>
<input type="text" class="card-group-item-input" :value="v.example" spellcheck="false">
</div>
<div>
<div class="textbox-tip">Answer {{i+1}}</div>
<input type="text" class="card-group-item-input" :value="v.answer" spellcheck="false">
</div>
</div>
</div>
<div class="card-group-item-footer">
<button class="button" #click="saveUpdate(groupIndex,index,card.id)" >SAVE CHANGES</button>
</div>
</div>
</div>
</div>
</div>
</div>
<button class="button" #click="test" >SAVE new</button>
<div class="footer">
<p>Footer</p>
</div>
</div>
</template>
<script>
import db from './firebaseInit'
export default {
name: 'dashboard',
data () {
return {
cards: [],
user: 'kikker'
}
},
created () {
db.collection('cards').where('user', '==', this.user)
.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
const data = {
'id': doc.id,
'group_name': doc.data().group_name,
'group': doc.data().group,
'size': doc.data().group.length
}
this.cards.push(data)
})
})
},
methods: {
toggleChild (i) {
var x = document.getElementById(i.target.id + 'A')
var y = document.getElementById(i.target.id + 'B')
if (x.style.display === 'none' || x.style.display === '') {
x.style.display = 'block'
y.style.webkitTransform = 'rotate(45deg)'
y.style.margin = '5px 5px 0px 0px'
} else {
x.style.display = 'none'
y.style.webkitTransform = 'rotate(-45deg)'
y.style.margin = '7px 5px 0px 0px'
}
},
toggleItem (i) {
var x = document.getElementById(i.target.id + 'A')
var y = document.getElementById(i.target.id + 'B')
if (x.style.display === 'none' || x.style.display === '') {
x.style.display = 'block'
y.style.webkitTransform = 'rotate(45deg)'
y.style.margin = '13px 5px 0px 0px'
} else {
x.style.display = 'none'
y.style.webkitTransform = 'rotate(-45deg)'
y.style.margin = '15px 5px 0px 0px'
}
},
addExample (x, y) {
this.cards[x].group[y].examples.push({
})
},
saveUpdate (x, y, z) {
console.log(z)
db.collection('cards').doc(z).update({
'age': 13,
'favorites.color': 'Red'
})
.then(function () {
console.log('Document successfully updated!')
})
.catch(function (error) {
alert('Error updating document: (The document probably doesn\'t exist.: )', error)
})
},
test () {
console.log('vd')
db.collection('cards').doc('BdSxtZL8V4S576i2BTRs').update({
group: firebase.firestore.FieldValue.arrayUnion({ back: 'bla', front: 'blabla' })
})
}
}
}
</script>
firebaseInit.js
import firebase from 'firebase'
import 'firebase/firestore'
import firebaseConfig from './firebaseConfig'
const firebaseApp = firebase.initializeApp(firebaseConfig)
export default firebaseApp.firestore()
firebaseConfig.js
export default {
apiKey: 'blabla',
authDomain: 'blabla',
databaseURL: 'blabla',
projectId: 'blabla',
storageBucket: 'blabla.appspot.com',
messagingSenderId: 'blabla',
appId: 'blabla',
measurementId: 'G-blabla'
}
UPDATED CONTENT:
firebaseInit.js
import firebase from 'firebase'
import 'firebase/firestore'
import firebaseConfig from './firebaseConfig'
const firebaseApp = firebase.initializeApp(firebaseConfig)
export default firebaseApp.firestore()
const db = firebaseApp.firestore()
const fieldValue = firebaseApp.firestore.FieldValue
export { db, fieldValue }
dahsboard.vue
<template>
<div id="dashboard">
<div style="margin-bottom: 50px">
<div v-for="(card, groupIndex) in cards" v-bind:key="card.id" class="card-group">
<div :id="card.group_name" class="card-group-header" #click="toggleChild" >{{card.group_name}}
<div class="group-count-label"> {{card.size}} </div>
<div class="right">
<div :id="card.group_name + 'B'" class="dropdown-arrow"></div>
<div style="margin-right:10px;font-size:15px">⋮</div>
</div>
</div>
<div class="card-group-items hidden-group" :id="card.group_name + 'A'">
<div v-for="(value, index) in card.group" v-bind:key="index" class="collection-item">
<div :id="card.group_name + index" class="card-group-item-header" #click="toggleItem" >
<div class="card-group-item-header-text">
<div class="card-group-item-header-text-front">{{value.front}}</div>
<div class="card-group-item-header-text-back">{{value.back}}</div>
</div>
<div class="right">
<div :id="card.group_name + index + 'B'" class="dropdown-arrow-b"></div>
<div style="margin:7px 10px 0px 0px;font-size:15px">⋮</div>
</div>
</div>
<div :id="card.group_name + index + 'A'" class="card-group-item">
<div>
<div class="textbox-tip">Front</div>
<input type="text" class="card-group-item-input" :value="value.front" spellcheck="false">
</div>
<div>
<div class="textbox-tip">Back</div>
<input type="text" class="card-group-item-input" :value="value.back" spellcheck="false">
</div>
<div class="card-group-examples">
<div class="card-group-example-header"><div>Examples</div><div class="card-group-example-header-plus" #click="addExample(groupIndex,index)">+</div></div>
<div v-for="(v, i) in value.examples" v-bind:key="i">
<div>
<div class="textbox-tip">Example {{i+1}}</div>
<input type="text" class="card-group-item-input" :value="v.example" spellcheck="false">
</div>
<div>
<div class="textbox-tip">Answer {{i+1}}</div>
<input type="text" class="card-group-item-input" :value="v.answer" spellcheck="false">
</div>
</div>
</div>
<div class="card-group-item-footer">
<button class="button" #click="saveUpdate(groupIndex,index,card.id)" >SAVE CHANGES</button>
</div>
</div>
</div>
</div>
</div>
</div>
<button class="button" #click="test" >SAVE new</button>
<div class="footer">
<p>Footer</p>
</div>
</div>
</template>
<script>
import { db, fieldValue } from './firebaseInit'
export default {
name: 'dashboard',
data () {
return {
cards: [],
user: 'kikker'
}
},
created () {
db.collection('cards').where('user', '==', this.user)
.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
const data = {
'id': doc.id,
'group_name': doc.data().group_name,
'group': doc.data().group,
'size': doc.data().group.length
}
this.cards.push(data)
})
})
},
methods: {
toggleChild (i) {
var x = document.getElementById(i.target.id + 'A')
var y = document.getElementById(i.target.id + 'B')
if (x.style.display === 'none' || x.style.display === '') {
x.style.display = 'block'
y.style.webkitTransform = 'rotate(45deg)'
y.style.margin = '5px 5px 0px 0px'
} else {
x.style.display = 'none'
y.style.webkitTransform = 'rotate(-45deg)'
y.style.margin = '7px 5px 0px 0px'
}
},
toggleItem (i) {
var x = document.getElementById(i.target.id + 'A')
var y = document.getElementById(i.target.id + 'B')
if (x.style.display === 'none' || x.style.display === '') {
x.style.display = 'block'
y.style.webkitTransform = 'rotate(45deg)'
y.style.margin = '13px 5px 0px 0px'
} else {
x.style.display = 'none'
y.style.webkitTransform = 'rotate(-45deg)'
y.style.margin = '15px 5px 0px 0px'
}
},
addExample (x, y) {
this.cards[x].group[y].examples.push({
})
},
saveUpdate (x, y, z) {
console.log(z)
db.collection('cards').doc(z).update({
'age': 13,
'favorites.color': 'Red'
})
.then(function () {
console.log('Document successfully updated!')
})
.catch(function (error) {
alert('Error updating document: (The document probably doesn\'t exist.: )', error)
})
},
test () {
console.log('vd')
db.collection('cards').doc('BdSxtZL8V4S576i2BTRs').update({
group: fieldValue.arrayUnion({ back: 'bla', front: 'blabla' })
})
}
}
}
</script>
If I correctly understand your question, you should use the arrayUnion() method: "each specified element that doesn't already exist in the array will be added to the end (of the array)".
See more detail in the documentation.
For that you need to:
Change your firebaseInit.js file to:
import firebase from 'firebase'
import 'firebase/firestore'
import firebaseConfig from './firebaseConfig'
firebase.initializeApp(firebaseConfig)
const db = firebase.firestore();
const fieldValue = firebase.firestore.FieldValue;
export { db, fieldValue };
Adapt your component code as follows:
<script>
import { db, fieldValue } from './firebaseInit'
export default {
name: 'dashboard',
data () {
return {
cards: [],
user: 'kikker'
}
},
created () {
db.collection('cards').where('user', '==', this.user)
.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
const data = {
'id': doc.id,
'group_name': doc.data().group_name,
'group': doc.data().group,
'size': doc.data().group.length
}
this.cards.push(data)
})
})
},
methods: {
//....
test () {
console.log('vd')
db.collection('cards').doc('BdSxtZL8V4S576i2BTRs').update({
group: fieldValue.arrayUnion({ back: 'bla', front: 'blabla' })
})
}
}
}
</script>
Then, if you want to reflect the addition in your front-end there are many possibilities with Vue.js (re-fetch the collection, set a listener, push it to a local array at the same time you write to Firestore, etc.). You need to give more detail on what is your exact functional requirement.

Resources