Angular ngFor - restriction to show on every item - javascript

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]">

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);" />

Vue 3 dynamic image

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"
/>

Dynamically add DIV element with varying values

I would like to create a div card dynamically with varying values depending on the result of my API. Currently, values keep overriding each other because they all share the same element ID. Is there a way for me to dynamically add all the values into their own cards?
res.forEach(x => {
const div = document.createElement("div");
div.className = "card mb-4 box-shadow";
div.innerHTML = `
<div class="card-header">
<h4 id="serverName" class="my-0 font-weight-normal"></h4>
</div>
<div class="card-body">
<h1 id="serverPrice" class="card-title pricing-card-title"></h1>
<p id="serverTraits" class="list-unstyled mt-3 mb-4"></p>
</div>`
document.getElementById("content").appendChild(div);
document.getElementById("serverName").innerHTML = x.name
document.getElementById("serverPrice").innerHTML = x.price + '$'
document.getElementById("serverTraits").innerHTML = x.traits
})
A simple way that works with your current solution is to simply append the index or a number behind your ids
e.g
<!-- your html code becomes something like this -->
<h4 id="serverName1" class="my-0 font-weight-normal"></h4>
<h4 id="serverName2" class="my-0 font-weight-normal"></h4>
<h4 id="serverName3" class="my-0 font-weight-normal"></h4>
When retrieving, likewise, append the index
document.getElementById("serverName" + index).innerHTML = x.name
This way, all your ids will be unique.
EDIT:
The following is an example of how you can append a number behind your id
innerHTML = `
<div class="card-header">
<h4 id="serverName` + 1 + `" class="my-0 font-weight-normal"></h4>
</div>
<div class="card-body">
<h1 id="serverPrice" class="card-title pricing-card-title"></h1>
<p id="serverTraits" class="list-unstyled mt-3 mb-4"></p>
</div>`;
Why do not generate the content dynamically before appending it to the "content" element?
Simple! no ...?
look at this
div.innerHTML = `
<div class="card-header">
<h4 id="serverName" class="my-0 font-weight-normal">${x.name}</h4>
</div>
<div class="card-body">
<h1 id="serverPrice" class="card-title pricing-card-title">${x.price}</h1>
<p id="serverTraits" class="list-unstyled mt-3 mb-4">${x.traits}</p>
</div>`
document.getElementById("content").appendChild(div);

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>

angular2 bootstrap dynamic carousel

I have a dynamic images coming from a json and doing *ngFor to loop through the objs and putting it in a carousel using bootstrap carousel, but I want to put a readmore link within the *ngFor so each item will have a read more.
I can't figure out how to do when a user click "readmore" it will scroll to its relative item showing about the image if that makes sense.
<div class="col-sm-4" *ngFor="let journey of Journey">
<div class="journey_block">
<div class="icon-workflow">
<div class="view view-fourth">
<img src="{{ journey.imageName }}" alt="">
<div class="mask">
Read More
</div>
</div>
<h4 class="journey_title">
<a [href]="journey.journey_url" *ngIf="journey.journey_url != 'javascript:;' " class="float-shadow">
{{journey.title}}
</a>
</h4>
</div>
</div>
My attempt is I thought I would then need to do for loop, I have 5 items in total in the json data.
getImg() {
this.http.get('./journey.json')
.map((res:Response) => res.json())
.subscribe(data => {
if(data) {
var jsonObj = JSON.parse(JSON.stringify(data));
this.Journey = jsonObj.journey;
for (var i = 0; i < this.Journey.length; i++) {
var element = this.Journey[i];
this.objCount = element;
console.log(this.objCount);
}
}
});
};
View full html structure of the carousel
Carousel structure
You need to have the index inside of the loop for making the data-slide-to attribute unique. This could be done by the predefined Angular2 value index.
Example
<!-- Angular 2.0 -->
<ul>
<li *ngFor="let item of items; let i = index">
{{i}} {{item}}
</li>
</ul>
In your code:
<div class="col-sm-4" *ngFor="let journey of Journey; let i = index">
<div class="journey_block">
<div class="icon-workflow">
<div class="view view-fourth">
<img src="{{ journey.imageName }}" alt="">
<div class="mask">
Read More
</div>
</div>
<h4 class="journey_title">
<a [href]="journey.journey_url" *ngIf="journey.journey_url != 'javascript:;' " class="float-shadow">
{{journey.title}}
</a>
</h4>
</div>
</div>

Categories