How to render File object to HTML element (using Vue.js) - javascript

I'm having some problems rendering an image in a HTML element. I think the solution might be simple for experienced front end devs.
I have a Vuetify component that lets user input a profile image:
<v-form>
<v-avatar size="144">
<v-icon hidden ref="default_icon" size="144">account_circle</v-icon>
<img ref="my_img" style="display: none;" :src="my_photo.name">
<v-btn #click="$refs.my_input.click()" class="img_btn" absolute right small fab dark color="pink">
<v-icon dark>add</v-icon>
</v-btn>
<input ref="my_input" hidden type="file" accept="image/*" #change="onFileChange($refs.my_input)">
</v-avatar>
</v-form>
When the element calls onFileChange it pass the HTML element to the function.
onFileChange(event) {
this.my_photo = event.files[0]
console.log(this.my_photo)
this.$refs.default_icon.style.display = "none"
this.$refs.my_img.style.display = "inline"
}
So now the function replaces the icon with the img tag. I want to fill the image tag with the image that the user inputs. this.my_photo is a File type variable.
Does anyone know how to do this?
Regards for everyone!

my_photo.name is literally just the name of the uploaded image. You need to convert the uploaded image to a valid format for the image src.
You can do this a couple ways using either FileReader.readAsDataURL() or URL.createObjectURL(). These create source representations that the image tag can use.
Keep in mind that if you plan on uploading this image to a server you will need to keep a reference to event.target.files[0].
Here an example using URL.createObjectURL().
new Vue({
el: "#app",
data: {
my_photo: '',
},
methods: {
onFileInput(event) {
const data = URL.createObjectURL(event.target.files[0]);
this.my_photo = data;
},
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
<input type="file" #change="onFileInput($event)">
<img :src="my_photo" alt="">
</div>

Related

Getting Outlook profile image in Vue as v-img src

I am trying to create a profile image that changes, depending on who is logged in so I cannot hardcode the email into the url
how would i go about this
html
<v-avatar size="128" absolute color="secondary">
<v-img:src="`https://outlook.office.com/api/v2.0/Users${email}/photo/$value`" />
</v-avatar>
computed
email() {
return this.staffMember.WorkEmail
},
Email is returned as devan#bsuregroup.co.za
but no image is being displayed
According to the API docs URL you need to query for photo looks like this:
GET https://outlook.office.com/api/v2.0/Users('{user_id}')/photo/$value
You need to change your URL in the v-img element:
<v-avatar size="128" absolute color="secondary">
<v-img:src="`https://outlook.office.com/api/v2.0/Users(${email})/photo/$value`" />
</v-avatar>

How to save image link in when using 'require' to display image in VueJS?

I am trying to create a page where I show Pizza items with their images. The Pizza object is saved in the DB with a field imgUrl. The image is not getting displayed but I see the alt text that I provided but I can see in the console that the image link is correct.
Right now, the imgUrl field in the database has data like ../assets/images/pizza.jpg. Should I instead save require(../assets/images/pizza.jpg) in the db. That looks weird. Here is the code, please look at the mounted method.
<template>
<div>
<div class="class">
<span><h1>All you can eat Menu.</h1></span>
<div class="container">
<div class="box" v-for="item in pizzaList" :key="item.id">
<div>
<img :src="item.imgUrl" alt="Image"/>
<div>
<a class="btn" #mouseenter="$event.currentTarget.style.background = '#EF6B7F'"
#mouseleave="$event.currentTarget.style.background = '#e31837' ">Buy Now</a>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
data () {
return {
pizzaList: []
}
},
mounted: function () {
axios.get('http://localhost:8081/api/pizza/all')
.then(response => {
this.pizzaList = response.data;
})
.catch(e => {
console.log(e);
})
}
}
</script>
I have already read
Vue and API: Displaying Image
Image path in Vue JS
How to reference static assets within vue javascript
but what these answers are telling is how to do when we have hardcoded the url, we should encapsulate it with require but they do not tell when we are getting the link from the DB, how do we put require in the html tag.
I hope my question was clear. Please ask for details if you need. thanks
The reason it was not working was because
Webpack's require() needs at least some part of the file path to be completely static and we should "make only part of the path dynamic"
that means you cannot put the entire image path in the DB and in the UI pass it to require and expect it to work
I replaced
<img :src="require(`${item.imgUrl}`)" alt="Image"/>
where item.imgUrl = '../assets/entities/pizza/pizza_1.jpg' (which is the entire image path relative to the component)
by
<img :src="require(`../assets${item.imgUrl}`)" alt="Image"/>
where item.imgUrl = '/entities/pizza/pizza_1.jpg'
This answer mentioned by Michal Levy up in the comments explains all this
https://stackoverflow.com/a/64208406/8147680

Why do background images load when navigating by anchor link but not by routerLink?

I have a feeling the answer to this question is quite simple, but I cannot find an answer to it anywhere. I am build a very simple app with Vue.js (v2.6.11) that consists of just two pages, a home page and another page with a form. Now, on both of these pages, there are several parallax containers made with MaterializeCSS. If you're unfamiliar, a parallax container is basically just a div with an image as its background, and when the user scrolls, the background image moves at a different rate than the foreground of the site.
My problem is that when I navigate from the home page to the page with the form using a Vue.js link, <router-link :to="{name: "FormPage"}>Form Page</router-link>, the images in the parallax containers DO NOT load. However, if I refresh the page, the images load fine and everything is well. Similarly, If I replace the <router-link> with a simple Form Page the images load fine, everything works as it should.
So my question is this: why don't my parallax container images load on the page navigated to with <router-link></router-link>, but then when I navigate to that same page with a the images do load? In other words, what is <router-link></router-link> doing that prevents my parallax container images from loading??
Any and all feedback would be appreciated. Otherwise, I hope you have a marvelous day, and thank you for you time in reading and or answering my question :)
--Update--
CODE:
This is the component on the homepage that contains the link in question:
<template>
<div id="index-banner" class="parallax-container" style="height: 400px;">
<div class="section no-pad-bot">
<div class="container">
<br><br>
<h1 class="header center white-text">{{ translations.title }}</h1>
<div class="row center">
<h5 class="header col s12 white-text light">{{ translations.subtitle }}</h5>
</div>
<div class="row center">
<!-- <router-link :to="{name: 'Generator', force: true }" class="btn-large waves-effect waves-light teal lighten-1 center-align">{{ buttonText }}</router-link> -->
{{ translations.buttonText }}
</div>
</div>
</div>
<div class="parallax"><img :src="img" alt="Unsplashed background img 1"></div>
</div>
</template>
<script>
export default {
name: 'Banner1',
props: {
translations: String,
img: String
},
}
</script>
<style>
</style>
This is the 'view' that is navigated to, containing the parallax containers in question:
<template>
<div>
<PageTitle
:translations="$t('generatorPage.components.pageTitle')"
img="/imgs/parallax5.jpeg"
/>
<SigForm
:translations="$t('generatorPage.components.sigForm')"
/>
<Separator
img="/imgs/parallax5.jpeg"
/>
</div>
</template>
<script>
import PageTitle from '#/components/banner/parallax/PageTitle'
import Separator from '#/components/banner/parallax/Separator'
import SigForm from '#/components/generator/SigForm'
export default {
name: 'Generator',
components: {
PageTitle,
SigForm,
Separator,
}
}
</script>
<style>
</style>
Here is the 'PageTitle' component with a parallax container:
<template>
<div class="parallax-container form-parallax-container">
<h1 class="white-text center">{{ translations.title }}</h1>
<div class="parallax"><img :src="img"></div>
</div>
</template>
<script>
export default {
name: 'PageTitle',
props: {
translations: String,
img: String
}
}
</script>
<style>
</style>
And here is the 'Separator' with a parallax container:
<template>
<div class="parallax-container form-parallax-container">
<div class="parallax"><img :src="img"></div>
</div>
</template>
<script>
export default {
name: 'Separator',
props: {
img: String
}
}
</script>
<style>
</style>
---UPDATE: Complete repo & sandboxed app---
Someone mentioned it would be eaiser if I provided a sandboxed app or whatever to debug it, so I just made the github repo public and also uploaded it to codesandbox.io. You'll notice that on codesandbox.io, the parallax images aren't even loading at all...on the homepage, on the form page, or upon refresh!
Ok so this is not the answer, but I needed to post some code to illustrate.
I have to confess that I'm not fully au-fait with JS frameworks, but I do know materializecss very well. I've been trying to help another user with a React based problem where the sidenav stops working when the react router is used - until he refreshes the page, when it works fine again.
So here's my hunch:
Parallax is a component that needs initialising like so:
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('.parallax');
var instances = M.Parallax.init(elems);
});
// Or with jQuery
$(document).ready(function(){
$('.parallax').parallax();
});
If you leave that initialisation code out, it won't work. And, taken from the docs for select fields dynamically added components need reinitialising.
You must initialize the select element as shown below. In addition,
you will need a separate call for any dynamically generated select
elements your page generates.
So my hunch is that when the page is re-rendered via a navigator, we get a new component added to the dom - but this is after the initialisation has already run. So that component is not initialised.
Could be wrong, hope I'm not for your sake more than mine. As I said, I don't know Vue or React very well at all, and my suggestions to run the init at each render didn't work for the React issue - but there are so many moving parts it's hard to rule out.

How to use an image as a button in Vue.js?

I'm trying to make a login button as a single-file-component in Vue.js (it's a Rails app with a Vue.js front-end). If you click this button, it's supposed to take you to the an external provider's login page.
How can I use an image as a button? I'm guessing you use v-on:click for the actual redirect, but I'm stuck there.
Right now, this code below shows a hardcoded button that looks like img(src="../assets/img/login_button.png"). You can click on it, but that's obviously not what I want. I want to show the actual png image, not the path.
// LoginButton.vue
<template lang="pug">
#login-button
<button v-on:click="redirect_to_login">img(src="../assets/img/login_button.png")</button>
</template>
<script lang="ts">
import { Vue, Component } from 'vue-property-decorator';
#Component
export default class LoginButton extends Vue{
redirect_to_login():void{ // I haven't written this method yet
}
}
</script>
Is there any reason you can't just use normal HTML image inside your button? I haven't used pug before.
<button v-on:click="redirect_to_login"><img src="../assets/img/login_button.png" /></button
Though since you're using Vue and not an actual HTML form you might not even need a button you could just add the click binding to the image instead
<img src="../assets/img/login_button.png" v-on:click="redirect_to_login" />
I am not familiar with pug, so I don't know what the correct syntax you'll need is. But you can use the <router-link> tag to set the route. For example (using Vuetify)
<router-link to="/">
<v-img src="/path/to/img.gif"/>
</router-link>
Either you can use:
<a #click="Redirect">
<img src='IMAGE_SRC' />
</a>
or
<img #click="Redirect" src='IMAGE_SRC'/>
new Vue({
el: '#app',
methods:
{
Redirect()
{
window.location.href = "https://jsfiddle.net/";
//or
//this.$router.push('LINK_HERE'); // if ur using router
}
}
})
Demo LINK:
https://jsfiddle.net/snxohqa3/5/

How to display an <img> in Vue.js only if the image url exists?

I'm getting a bunch of tweets from the Twitter API. Some tweets have images attached to them, some don't.
Currently, I use this code to display the image of a tweet:
<template lang="jade">
div Tweet text
img(:src='tweet.entities.media[0].media_url', width='100%')
</template>
<script>
import store from './store.js';
export default {
name: 'tweet',
data () {
return {
tweet : store.selectedTweet
}
}
}
</script>
The problem is that this only works if the tweet actually has at least one image. If it has no image, I get an exception because tweet.entities.media is undefined.
How can I fix this so that the <img> is only used if there is actually an image available in the tweet's entity value?
You could use v-if:
<template>
<div class="Tweet text">
<img :src="tweet.entities.media[0].media_url" width="100%" v-if="tweet.entities.media" />
</div>
</template>
Using v-if will stop the img element to be rendered.
In string templates, for example Handlebars, we would write a conditional block like this:
{{#if tweet.entities.media}}
img(:src='tweet.entities.media[0].media_url', width='100%')
{{/if}}
In Vue, we use the v-if directive to achieve the same:
<template>
<div class="Tweet text">
<img :src="tweet.entities.media[0].media_url" width="100%" v-if="tweet.entities.media" />
</div>
</template>
Here you find the Documentation

Categories

Resources