VueJS: Obtaining dynamic component information in method run via v-bind - javascript

I believe this is a relatively unique problem, and as such I'm having difficulty trying to solve it.
I'm creating a file manager-like solution in Vue, and I'm looking for certain folders/files to display a unique thumbnail (in my example, showing the Creative Cloud logo if the 'Creative Cloud' folder is found). In my app I am using a component to represent each file.
The file-grid Vue file reads as such (sorry for the mess, I've been trying to integrate multiple different solutions to see what sticks):
<template>
<div id="localMain">
<div id="filesGrid">
<File :fileName="file"
:imageAddress="findImage($event)"
id="file"
v-for="file in files"
:key="file.id"></File>
</div>
</div>
</template>
<script>
import File from './LocalMain/File';
export default {
data() {
return {
creativeCloud: 'static/logos/creative-cloud.svg',
blankThumb: 'static/code.svg',
files: [
'Creative Cloud',
'Documents',
...
],
};
},
components: {
File,
},
methods: {
findImage: function findImage(e) {
/* Get the name of the file/folder, and choose a thumbnail accordingly */
const name = e.target.dataset.fileName;
let image = this.blankThumb;
if (name === 'Creative Cloud') {
image = this.creativeCloud;
} else {
image = this.blankThumb;
}
return image;
},
},
};
</script>
<style scoped>
/* styling */
</style>
The file component itself looks like this:
<template>
<div id="file">
<img :src="imageAddress" alt="Logo" id="fileImg" />
<h3 v-if="display">{{ fileName }}</h3>
</div>
</template>
<script>
export default {
data() {
return {
display: false,
};
},
props: {
fileName: String,
imageAddress: String,
},
};
</script>
<style scoped>
/* styling */
</style>
I apologise for the ambiguity in this question, but I'm quite confused.

I might be missing something, but why not just v-bind the method with the file name as the argument?
eg.
Parent template
<File :fileName="file"
:imageAddress="findImage(file)"
id="file"
v-for="file in files"
:key="file.id"></File>
Parent Javascript
findImage: function findImage(name) {
var image = this.blankThumb;
if (name === 'Creative Cloud') {
image = this.creativeCloud;
}
return image;
},

Related

Image path to stored in Pinia not passing through to component

I'm creating a card carousel with a Spotify style thumbnail, (image as background, text on top). Content is stored in a Pinia store which I will be hooking up to Firebase eventually. I'm trying to set the image background but am getting this error
GET http://127.0.0.1:5173/%60$%7B%7Bcontent.image%7D%7D%60 404 (Not Found)
Here is my store code (condensed to the important bits)
export const useContentStore = defineStore('contentStore', {
state: () => {
return {
guides: [{
title: 'XX',
date: 'X',
description: "X",
image: './assets/images/content/thumbnail.png',
id: '1',
}]
}
}
})
Here is where I am trying to access that image path
<template>
<div class="card">
<img class="card-image" src="{{content.image}}"/>
<h1 class="title">{{content.title}}</h1>
<h2 class="subtitle"></h2>
</div>
</template>
<script setup>
/*
store
*/
import { useContentStore } from "#/stores/contentStore";
const contentStore = useContentStore();
/*
props
*/
const props = defineProps({
content: {
type: Object,
required: true,
},
});
</script>
And here is where the cards are being called
<template>
<div class="guides-container">
<h2 class="title">Guides</h2>
<div class="guides-list">
<GeneralCard
v-for="(content, index) in contentStore.guides"
:key="content.id"
:content="content"
/>
</div>
</div>
</template>
<script setup>
/*
imports
*/
import GeneralCard from "#/components/GeneralCard.vue";
/*
data
*/
const contentStore = useContentStore();
</script>
My gut instinct is that it's an issue with transferring the string through the store to the template, but I don't have any clue how to fix it. I've tried escaping the characters, using template literals on both the stored path and the image tag, played with URL() a bit, and I'm pretty sure it's not an issue with the actual path of the image (it works when I plug the path directly into the image tag)
Thanks for any help you can give!
The src attribute on the img is set improperly. It should be
<img class="card-image" :src="content.image"/>

Vue 2 Component Mounts on One Page, Throws TypeError on another but works if loaded on first page before

I have a popup component which renders a photo ID that works currently on one page and I am trying to also have the component visible on another page. When I add my component to another page it throws an error at me. Unsure what is causing the error. Stack suggests my cleanup function doesn't exist, it is a function written in the component.
If however I load the photoID popup from the page which already has the working component and then navigate to the second page and try to open the new component it will load fine until I refresh the page.
My Popup component
//popup.vue
<template>
<!--
Rendering of this component should be handled by the parent using a v-if.
Listen for event 'closeButtonPressed' to know when to stop rendering it.
-->
<div class="modal is-active">
<div class="modal-background" #click="$emit('closeButtonPressed')"></div>
<div class="modal-content">
<p class="image is-4by3">
<img class="photo-id-img" :src="photoIdObjectUrl">
</p>
</div>
<button class="modal-close is-large" aria-label="close" #click="$emit('closeButtonPressed')"></button>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex';
import utils from "../Utils/utils.js";
export default {
name: 'photoIdPopup',
props: {
clientId: {
type: Number,
required: true,
}
},
data: () => ({
/**
* This is a url we generate that points to a blob containing our photo
* id image. An img element's src attribute can be set to it to
* display the image.
*/
photoIdObjectUrl: null,
}),
destroyed() {
this.cleanUp();
},
methods: {
...mapActions({
getFile: "filestorage/getFile",
}),
async getPhotoIdObjectUrl() {
// Get photo id file from api.
const file = await this.getFile({
usercode: this.photoIdFile.usercode,
id: this.photoIdFile.id,
clientId: this.clientId,
});
// Convert the file to a blob.
const blob = new Blob([utils.str2bytes(file)]);
// Create a objectUrl from the blob for img element's src attribute.
return URL.createObjectURL(blob);
},
/** We have to cleanup the object urls we previously allocated. */
cleanUp() {
if (this.photoIdObjectUrl) {
URL.revokeObjectURL(this.photoIdObjectUrl);
this.photoIdObjectUrl = null;
}
},
async initializePhotoIdImage() {
this.photoIdObjectUrl = await this.getPhotoIdObjectUrl();
}
},
computed: {
...mapState({
photoIdFile(state) {
return state.filestorage['drLicense'];
}
}),
},
watch: {
photoIdFile: {
immediate: true,
handler(newPhotoIdFile) {
if (newPhotoIdFile) {
this.initializePhotoIdImage();
} else {
this.cleanup();
}
}
}
}
}
</script>
<style scoped>
.photo-id-img {
object-fit: contain;
}
</style>
How I'm calling the object on the new page, there is no difference in how I do it between this page and the page which has my working component.
//interview-summary.vue
<photoIdPopup
v-if="isPhotoIdShowing"
#closeButtonPressed="viewPhotoIdPressed"
:clientId="clientId"
/>
viewPhotoIdPressed() {
this.isPhotoIdShowing = !this.isPhotoIdShowing
Error Stack
Any help would be appreciated as I'm still learning Vue. My first assumption is that I'm missing an object in my state that I need to render the component properly but I'm not sure.

VueEditor document is not defined Nuxt.js

In my Nuxt.js project I installed vue2-editor package to be able to write articles with HTML. When I come to page, write something and press the button everything works correctly, but when I reload page, I get document is not defined error.
Here is the code:
<template>
<div>
<SideBar />
<div class='content'>
<h1>Write article</h1>
<client-only>
<VueEditor
v-model='articleContent'
/>
</client-only>
<div style='margin-top: 15px'><button #click='postArticle'>Post article</button></div>
</div>
</div>
</template>
<script>
import { VueEditor } from 'vue2-editor';
import SideBar from '../components/SideBar';
export default {
name: 'Articles',
components: {
SideBar,
VueEditor
},
data() {
return {
articleContent: null,
}
},
methods: {
postArticle() {
console.log(this.articleContent)
},
},
}
</script>
And the error looks like that:
Also in documentation I've found that for Nuxt.js projects vue2-editor should be added to modules, and I did it, but it still doesn't work:
modules: [
// https://go.nuxtjs.dev/axios
'#nuxtjs/axios',
'vue2-editor/nuxt'
],
You can try to load it dynamically:
<template>
<div>
<SideBar />
<div class='content'>
<h1>Write article</h1>
<client-only>
<VueEditor
v-model='articleContent'
/>
</client-only>
<div style='margin-top: 15px'><button #click='postArticle'>Post article</button></div>
</div>
</div>
</template>
<script>
import SideBar from '../components/SideBar';
export default {
name: 'Articles',
components: {
SideBar,
VueEditor: () => process.client ? (await import("vue2-editor")).VueEditor : ""
},
data() {
return {
articleContent: null,
}
},
methods: {
postArticle() {
console.log(this.articleContent)
},
},
}
</script>
Do follow the below steps the add that plugin into your Nuxt
There will be plugins folder just like pages and components, if not create one and add a js file into it vue2-editor.js.
Copy the below content inside vue2-editor.js
import Vue from "vue";
import Vue2Editor from "vue2-editor";
Vue.use(Vue2Editor);
Inside nuxt.config.js remove the 'vue2-editor/nuxt' from the modules and create a separate array called plugins as below
/*
** Plugins to load before mounting the App
*/
plugins: [{ src: "~/plugins/vue2-editor", mode: 'client' }],
Thats it you are done. Now you can start using it in any of the vue files like
<vue-editor placeholder="Write Something..." v-model="content"></vue-editor>

Dynamic background image based on javascript variable

In my style block I have code like this
<style lang="scss">
.item {
background: url('~#assets/images/i10.png');
}
</style>
As per my specific needs I need to load the image from the javascript variable thats being injected in html page. e.g in index.html file coming up from server it could be
itemURL = '/abc/def/def/img.png';
Something like:
<style lang="scss">
.item {
background: url([window.itemURL);
}
</style>
and then I need to use that url as background image of item.
I can't use document.getElementBy(xyz) as item is loading/unloading dynamically into DOM.
Note: Its vuejs project created via vue command line tools
u can use img tag instead of css style
<template>
<div>
<img
:src="url"
>
</div>
</template>
<script>
export default {
data() {
return {
url: null
}
},
mounted() {
this.url = injectImageUrl() // js function to inject url
}
}
</script>
Maybe you can use props? But I don't think it's possible to access the props from inside the style tag. The only way to do this is by using inline styling.
<template>
<div :style={ backgroundImage: 'url('+ imgUrl +')' }>
</div>
</template>
<script>
export default {
props: {
imgUrl: {
type: String,
}
},
}
</script>

Vuejs call other component's method with parameter

I have two components, the first one is for uploading a file and the second one to Show a file. Inside my Upload Component I would like to call the Preview Component and add a Parameter so that a method inside the Preview Component uses a value which is created inside the Upload Component.
So far I have done this:
UploadComponent.vue
<template>
…
<button #click="upload"></button>
<preview-component :url="this.location"></preview-component>
</template >
<script>
import PreviewComponent from '#/js/components/PreviewComponent';
export default {
components: {
'preview-component': PreviewComponent
},
props: ['url'],
data () {
return {
// ...
location: ''
}
},
methods: {
upload() {
// ... upload stuff then update the global var location
this.location = response.data.location;
},
}
}
</script>
This is my Preview Component:
<template>
<div id="body">
///...
</div>
</template>
<script>
export default {
props: ['url'],
methods: {
loadPdf (url) {
//
},
}
}
</script>
So far I am getting the error that url is not defined, so it actually does not sent the url from the UploadCOmponent to the PreviewComponent, how do I manage to sent it?
You got a ninja this in your UploadComponent's template.
It should be <preview-component :url="location"></preview-component>

Categories