Vue 3 dynamic image - javascript

I am using a v-for to load data on cards. The image is not showing up and not sure why.
I though :src = "'item.img'" or :src = "{{item.img}}" would work, but neither are working.
Here is my code
<div v-for="(item, index) in basicData" :key="index">
<transition class="slide">
<div v-if="index >= start && index < end" class="card">
<div class="card-body">
<h5 class="card-title">{{item.title}}</h5>
<img
:src="'item.img'"
class="card-img-top"
:alt="'item.img'"
style="margin: 20px 5px"
/>
<p class="card-text">Some quick example text.</p>
</div>
</div>
</transition>
and here is the screen shot
When I hard code src="../assets/featured/pizzaOne.jpeg"
the image appears.

You can create method or computed property:
methods() {
getImage(imagePath) {
return require(imagePath);
}
}
Then in template call that method:
<img
:src="getImage(item.img)"
class="card-img-top"
:alt="item.img"
style="margin: 20px 5px"
/>

Related

How can I store a string without duplicating it?

There are 2 cards panels, and I would like to change the image of the card when I hover over it, then when I leave it I want to come back to the initial image.
First time it works for each image, but when I try to hover second time it duplicates my string where I store the path..
HTML CODE
<div class="col-lg d-flex justify-content-center mb-4">
<div class="card border-0"">
<img src="img/slide-1.jpg" class=" card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">Image 1</h5>
</div>
</div>
</div>
<div class="col-lg d-flex justify-content-center mb-4">
<div class="card border-0"">
<img src="img/slide-1.jpg" class=" card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">Image 2</h5>
</div>
</div>
</div>
JQUERY CODE
(function ($) {
"use strict"; // Start of use strict
var image_product;
var image_product_path="/Users/paul/Desktop/Site/";
$(".card-img-top").on({
mouseenter: function () {
image_product = $(this).attr("src");
$(this).attr("src","/Users/paul/Desktop/Site/img/slide-3.jpg");
},
mouseleave: function () {
$(this).attr("src",image_product_path+image_product);
}
});
})(jQuery); // End of use strict
The error that is triggered second time when I try to hover over the cards:
[Error] Not allowed to load local resource: file:///Users/paul/Desktop/Site//Users/paul/Desktop/Site/img/slide-1.jpg
The error that is triggered third time when I try to hover over the cards:
[Error] Not allowed to load local resource: file:///Users/paul/Desktop/Site//Users/paul/Desktop/Site//Users/paul/Desktop/Site//Users/paul/Desktop/Site/img/slide-1.jpg
AND SO ON
There are n cards panels, and I would like to change the image of the
card when I hover over it, then when I leave it I want to come back to
the initial image.
Set the original image into a data attribute, then on mouse out switch it back.
(function($) {
$(".card-img-top").on({
mouseenter: function() {
$(this).data('original', $(this).attr("src"));
$(this).attr("src", "https://via.placeholder.com/300/09f/000.png");
},
mouseleave: function() {
$(this).attr("src", $(this).data('original'));
}
});
})(jQuery);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="col-lg d-flex justify-content-center mb-4">
<div class="card border-0">
<img src="https://via.placeholder.com/300/09f/fff.png" class=" card-img-top " alt="... ">
<div class="card-body ">
<h5 class="card-title ">Image 1</h5>
</div>
</div>
</div>
If you want a different image for each different card then set it into a data attribute.
(function($) {
$(".card-img-top").on({
mouseenter: function() {
$(this).data('original', $(this).attr("src"));
$(this).attr("src", $(this).data('hover-image'));
},
mouseleave: function() {
$(this).attr("src", $(this).data('original'));
}
});
})(jQuery);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="col-lg d-flex justify-content-center mb-4">
<div class="card border-0">
<img src="https://via.placeholder.com/100/09f/fff.png" data-hover-image="https://via.placeholder.com/100/09f/000.png" class=" card-img-top " alt="... ">
<div class="card-body ">
<h5 class="card-title ">Image 1</h5>
</div>
</div>
</div>
<div class="col-lg d-flex justify-content-center mb-4">
<div class="card border-0">
<img src="https://via.placeholder.com/100/07f/aaa.png" data-hover-image="https://via.placeholder.com/100/05f/333.png" class=" card-img-top " alt="... ">
<div class="card-body ">
<h5 class="card-title ">Image 2</h5>
</div>
</div>
</div>
Here's what the src attribute and your image_product variable contain at the different phases:
Phase
src
image_product
before first run
img/slide-1.jpg
undefined
first mouseenter
/Users/paul/Desktop/Site/img/slide-3.jpg
img/slide-1.jpg
first mouseleave
/Users/paul/Desktop/Site/img/slide-1.jpg
img/slide-1.jpg
2nd mouseenter
/Users/paul/Desktop/Site/img/slide-3.jpg
/Users/paul/Desktop/Site/img/slide-3.jpg
2nd mouseleave
/Users/paul/Desktop/Site/Users/paul/Desktop/Site/img/slide-1.jpg
/Users/paul/Desktop/Site/img/slide-3.jpg
In your handlers functions, you keep storing whatever is in src into image_product when the mouse enters.
The second time you mouseenter, image_product already contains the full path, but in your mouseleave function you keep prepending the path every time.
Please check a link
https://stackoverflow.com/a/18032363/3526623
The solution from the link above without Jquery
function hover(element) {
element.setAttribute('src', 'http://dummyimage.com/100x100/eb00eb/fff');
}
function unhover(element) {
element.setAttribute('src', 'http://dummyimage.com/100x100/000/fff');
}
<img id="my-img" src="http://dummyimage.com/100x100/000/fff" onmouseover="hover(this);" onmouseout="unhover(this);" />

How to check if all the input values are equal to my data?

I have 32 items in my array, all of them have these properties: id, word, image. User has to guess what's in all the images and write their guess in inputs (so 32 inputs in total). I need to check if the input equals my arrays property "word" and then when clicked a button (type submit, all my pic's and inputs are in a form) display some text for example "Oops! Guess again" if wrong and "Yay! You got it correctly" if right. The text should appear below every input. I displayed all the pictures and inputs with a forEach, and i'm using bulma framework for this page:
const wordBox = info.forEach((words) => {
mainColumns.innerHTML += `
<div class="column is-one-quarter">
<div class="card">
<div class="card-image">
<figure class="image is-4by3">
<img src=${words.image} alt="Placeholder image">
</figure>
</div>
<div class="card-content">
<div class="media">
<div class="media-content">
<input class="input" id="text" type="text" placeholder="Įvesk žodį">
</div>
</div>
<div class="content">
Content
</div>
</div>
</div>
</div>`;
});
Any ideas?
This is how it should look like (the result should appear in content place)
Something like this
I use change instead of a button click
const info = [
{word:"flower",image:"flower.gif"},
{word:"boat",image:"boat.gif"}
];
const mainColumns = document.getElementById("mainColumns");
mainColumns.innerHTML = info.map(({image,word}) =>
`<div class="column is-one-quarter">
<div class="card">
<div class="card-image">
<figure class="image is-4by3">
<img src=${image} alt="Placeholder image">
</figure>
</div>
<div class="card-content">
<div class="media">
<div class="media-content">
<input class="input" data-word="${word}" type="text" placeholder="Įvesk žodį">
<span class="correct hide">Yay</span>
<span class="wrong hide">NOO</span>
</div>
</div>
<div class="content">
Content
</div>
</div>
</div>
</div>`).join("");
mainColumns.addEventListener("change",function(e) {
const correct = [...mainColumns.querySelectorAll("[data-word]")].map(input => {
if (input.value) {
const correct = input.value === input.dataset.word;
parent = input.closest("div");
parent.querySelector(".correct").classList.toggle("hide",!correct)
parent.querySelector(".wrong").classList.toggle("hide",correct);
return correct ? 1 : 0;
}
else return 0;
}).reduce((a,b)=>a+b);
document.getElementById("correct").innerText = correct;
})
#mainColumns { display:flex; }
.hide { display: none; }
<div id="mainColumns"></div>
Correct: <span id="correct"></span>
What you can do is to filter the word array with word from the input value. Then check if the length is equal zero, No match, if the length is greater than one, then there is a match.
const status = wordBox.filter(item => item.word === inputWord)
I'd move towards keeping the objects and the HTML separate, binding the HTML to the object and vice versa. This means including a couple more properties to your array elements.
let info = [{
image: 'flower.png',
word: 'flower',
content: '',
guess: ''
}];
function bindWords() {
info.forEach((words) => {
mainColumns.innerHTML = `
<div class="column is-one-quarter">
<div class="card">
<div class="card-image">
<figure class="image is-4by3">
<img src=${words.image} alt="Placeholder image">
</figure>
</div>
<div class="card-content">
<div class="media">
<div class="media-content">
<input class="input" data-word="${words.word}" type="text" placeholder="Įvesk žodį" value="${words.guess}">
</div>
</div>
<div class="content">
${words.content}
</div>
</div>
</div>
</div>`;
});
}
bindWords();
check.addEventListener('click', () => {
info = Array.from(document.querySelectorAll('.card')).map(el => ({
image: el.querySelector('img').src,
word: el.querySelector('.input').dataset.word,
guess: el.querySelector('.input').value,
content: el.querySelector('.input').value === el.querySelector('.input').dataset.word ?
'Correct' : 'Incorrect'
}));
bindWords();
});
<div id="mainColumns"></div>
<button id="check">Check Answers</button>

how to rendering data from api in vue.js

I am new to vue.js I am going to make a news app using a API.
In here I used v-for to iterate some codes. I think there is a problem in v-for. because it gives error. error has been included end of this question.
I used following codes to show search results
<template>
<div class="col-md-12">
<div>
<h2>Results</h2>
<div class="card mb-3" v-for="item in resultList">
<img class="card-img-top" src="" alt="Card image cap" height="100" width="200">
<div class="card-body">
<h5 class="card-title">{{ item.name }}</h5>
<p class="card-text">This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.</p>
<div class="button">
<button type="button" class="btn btn-primary">Show more</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default{
props: ['resultList']
}
</script>
following codes used to get the api data(search api data)
<template>
<div class="container1">
<div class="form-group row">
<label for="exampleInputPassword1">Search Music</label>
<div class="col-lg-10">
<input type="text" class="form-control" id="exampleInputPassword1" placeholder="Type here"
#input="keypressed">
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default{
data () {
return {
newset: []
}
},
methods: {
keypressed () {
var key = event.target.value
axios.get('http://newsapi.org/v2/everything?q=' + key +
'&sortBy=publishedAt&apiKey=b5ac77726d0a4460bd82b57210b2efb7')
.then(response => {
this.newset = response.data.articles
})
.catch(e => {
this.error.push(e)
})
this.$emit('newDataset', this.newset)
}
}
}
</script>
but it gives an error. error is
https://google.com/#q=vue%2Frequire-v-for-key Elements in iteration expect to have 'v-
bind:key'
directives
src\components\ResultArea.vue:5:5
<div class="card mb-3" v-for="item in resultList">
^
You need to add :key binding:
<div class="card mb-3" v-for="(item, index) in resultList" :key="index">
key value should be unique for every item. If your list items has any id it is good idea to use this id here:
<div class="card mb-3" v-for="item in resultList" :key="item.id">
To give Vue a hint so that it can track each node’s identity, and thus reuse and reorder existing elements, you need to provide a unique key attribute for each item. check the link for better understanding
https://v2.vuejs.org/v2/guide/list.html#Maintaining-State

Testing for Nested divs using Vue Test Utils

So I have this shallowMounted vue component:
<div class="card p-relative">
<div class="card-header">
<div class="card-title h4">
a cute title
<!---->
<!---->
</div>
</div>
<!---->
<div class="card-body">
<h3 class="circle" style="background-color: rgb(237, 15, 59);"></h3>
</div>
<div>
<h6 class="card-body">Value: 35</h6>
</div>
</div>
I am doing a shallowMount:
const wrapper = shallowMount(Component, { proposData: { 'shape': 'circle'}})
Later trying to find all the classes, so I can somehow find the class circle. But what I got:
const results = wrapper.classes()
console.log(results) // ['card', 'p-relative']
How to find the h3 or class 'circle' :/
Completely Noob to frontend. Please forgive for using wrong vocabulary.
As mentioned in https://vue-test-utils.vuejs.org/api/selectors.html to access direct descendants.
I did the following:
const shape = wrapper.find('.card-body > h3')
console.log(shape.classes()) //['circle']

Angular ngFor - restriction to show on every item

I have got following code in my component.html. ( I am new to angular )
<div class="card" *ngFor="let item of galleries;"
(mouseenter)=" setBackground(item?.image?.fullpath)"
(mouseover)="showCount = true; getImagesCount(item.path);" (mouseleave)="showCount = false">
<img class="card-img-top" [routerLink]="['/'+item.path]"
[src]="item?.image?.fullpath ? path + '0x156/' + item?.image?.fullpath : defaultImage"
alt="Card image cap">
<div class="card-block">
<h4 class="card-title imagesCount"></h4>
<h4 class="card-title title">{{item.name}}</h4>
<img class="closeIcon" src="../../../assets/images/close.png" alt="" (click)="removeGallery(item);">
<span class="animated fadeInUp" *ngIf="showCount">{{imagesCount}}</span>
</div>
</div>
Down in the code i have *ngIf="showCount where i am trying to show how many images gallery have. But issue is that it is shown on every card, but i want it to show only on current card that i enter my mouse with.
You should specify your *ngIf in:
<span class="animated fadeInUp" *ngIf="showCount">{{imagesCount}}</span>
because actually you will get for every item in your galleries list.
Here is an idea, how you can specify that:
Step 1: Add new variable to your component.ts
currentItem: number;
Step 2: add index to your ngFor
*ngFor="let item of galleries; let index = index;"
Step 3: Extend your (mouseover) and (mouseleave) events
Add currentItem and fill with data.
(mouseover)="showCount = true; currentItem = index; getImagesCount(item.path);"
(mouseleave)="showCount = false; currentItem = null;"
Step 4: Change you *ngIf in span with itemsCount
<span class="animated fadeInUp" *ngIf="showCount && currentItem == index">{{imagesCount}}</span>
Now you have a spicified solution.
I would suggest you to create an extra key i.e. showCount inside item object.
item = {
...,
showCount: false
}
than use that key for showing and hiding showCount in the HTML.
<div class="card" *ngFor="let item of galleries;"
(mouseenter)=" setBackground(item?.image?.fullpath)"
(mouseover)="item[showCount] = true; getImagesCount(item.path);"
(mouseleave)="item[showCount] = false">
<img class="card-img-top" [routerLink]="['/'+item.path]"
[src]="item?.image?.fullpath ? path + '0x156/' + item?.image?.fullpath : defaultImage"
alt="Card image cap">
<div class="card-block">
<h4 class="card-title imagesCount"></h4>
<h4 class="card-title title">{{item.name}}</h4>
<img class="closeIcon" src="../../../assets/images/close.png" alt="" (click)="removeGallery(item);">
<span class="animated fadeInUp" [hidden]="item[showCount]">{{imagesCount}}</span>
</div>
</div>
I would approach this by making your 'showCount' variable into an array, and comparing *ngIf to the array value:
Some small tweaks:
<div class="card" *ngFor="let item of galleries; let idx=index">
....
(mouseover)="showCount[idx]=true
(mouseleave)="showCount[idx]=false
</div>
...
<span class="animated fadeInUp" *ngIf="showCount[idx]">

Categories