I haven't quite seen other questions which try to answer what I'm doing and I'm not sure if it's just that I'm not searching for the correct verbage so I'll explain what's going on.
I'm trying to develop an interface where the user can drag or input an image with vue. I also have a component which I've made called Card which is a bit of vue and bulma for a card-like object. The Card component has two props, title and content. Very straight forward to use when what you want to fill in the title and content properties are pre-loaded text or image data.
However, what I want to do is place another vue component inside the Card (a PictureInput component from vue-picture-input on npm). I'm trying to do this by passing it as the content prop. I have read the vue documentation on reactive props and dynamic components, but neither really talk about this use case.
Code:
Card.vue:
<template>
<div class="card is-size-7-mobile is-fluid">
<div class="card-header">
<a class="card-header-title">
<span class="is-info">{{this.title}}</span>
</a>
<span v-if="this.isExpanable">
<a class="card-header-icon card-toggle">
<span class="icon" @click="arrowClick">
<span v-if="!this.open">
<font-awesome-icon :icon="['fas', 'angle-down']"></font-awesome-icon>
</span>
<span v-else>
<font-awesome-icon :icon="['fas', 'angle-up']"></font-awesome-icon>
</span>
</span>
</a>
</span>
</div>
<slide-up-down :active="this.open" :duration="400" v-if="this.isExpanable">
<div v-if="this.open" class="card-content is-size-7-mobile">
<div class="content">{{this.content}}</div>
</div>
</slide-up-down>
<div v-else>
<div class="content">{{this.content}}</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
open: false
};
},
props: {
title: "",
content: null,
isExpanable: false
},
methods: {
arrowClick(event) {
this.open = !this.open;
}
}
};
</script>
<style scoped>
.card {
border-radius: 1em;
background-color: transparent !important;
border-color: transparent !important;
}
.card-header {
box-shadow: transparent;
}
</style>
ImageInput.vue:
<template>
<div class="content">
<Card :title="makeCardTitle()" :content="makeCardContent()"/>
</div>
</template>
<script>
import PictureInput from 'vue-picture-input';
import Card from './Card';
import Vue from 'vue';
export default {
name: 'ImageInput',
components: {
PictureInput,
Card
},
props: {
idx:{
type:Number,
default: 0
}
},
data() {
return {
pictureComponent: "PictureInput"
}
},
methods: {
makeCardTitle: function(){
return "page ".concat(String(this.idx))
},
makeCardContent: function(){
var PictureInputClass = Vue.extend(PictureInput);
var pictureInputInstance = new PictureInputClass();
return pictureInputInstance
}
}
}
</script>
<style scoped>
</style>
As you can see with the ImageInput.vue code I've tried to dynamically construct the PictureInput object and pass it as the prop content to Card but it doesn't work, I get two errors one being a "Cyclic object value" in Card and the other being that the PictureInputClass object doesn't have a toJSON method, which I'm guessing some part of the vue framework expects. I've also tried just doing:
<Card :title="makeCardTitle()" :content="PictureInput"/>, but I end up getting errors about how the PictureInput isn't defined but is referenced during render. Maybe I can change content to a named <slot></slot> but I'm not sure if that's what I want either.
The reason I'm going through all of this is that I really appreciate how Vue is designed to allow components to be re-used and re-integrated into each other when creating an interface. I obviously could just take (most of) the template from Card and re-configure it for this case but I wanted to see if there was an easier way to get the PictureInput component to be a child of the Card component.