This question already has answers here:
How to import and use image in a Vue single file component?
(10 answers)
Closed 2 years ago.
I am trying to generate src link to each of my li items generated by v-for.
I have list of some Strings... ["Electronics","Furniture", "Cloths", "Sports", "Entertainment", "Others"] and in each tag I want to generate some with dynamically changing src.
For example:
First item is electronics so path would be #/assets/Electronics.png and image would be displayed
Second item is Furniture so path would be #/assets/Furniture.png
What do I need to do to show that img how do I need to define this path?
<ul class="menu-dropdown">
<li v-for="item in items" :key="item" class="center align-self-center">
<img class="float-left" :src="getPicture(item)" v-bind:alt="item" />
<h3>{{item}}</h3>
</li>
</ul>
<script>
export default {
name: 'Header',
props:{},
data() {
return {
items: ["Electronics", "Furniture", "Cloths", "Sports", "Entertainment", "Others"]
}
},
methods:{
getPicture(item){
return '#/assets/' + item + ".png"
}
}
}
</script>
In the data property
I think you should make array of object with name and src, then import every images.
<script>
import electronicSrc from "#/path/to/img/electronic";
import furnitureSrc from "#/path/to/img/furniture";
export default {
name: 'Header',
props:{},
data() {
return {
items = [{ category: "Electronics", src: electronicImg}, { category: "Furniture", src: furnitureImg}, { category: "Cloths", src: clothImg}, .. ];
}
},
}
</script>
Modify the template
<li v-for="item in items" :key="item" class="center align-self-center">
<img class="float-left" :src="item.src" v-bind:alt="item.category" />
<h3>{{ item.category }}</h3>
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed last month.
Improve this question
Hello there I could use some help!
My 14 year old niece has a science project. She has a numbered list of animals - dinosaurs - in an Excel spreadsheet. She asked me to help her, and I could not say no, but I am only a very lame beginner html programmer.
So I need to display the list of animals in the html page in two ways: In numerical order AND in classification order (carnivorous / herbivorous etc) together with a small picture of each animal.
The objective is to show them as in the annexed picture, one page in alphabetical order, and the other page in classification order (feeding habits, land or maritime, etc.)
enter image description here
I know how to create a html block, but then I would have to insert the dinos one by one, and my / her deadline is next week. The list has over two hundred dinos, so I can´t do it by hand. Then it ocurred to me there must be a way to get the data from the Excel and display it in html in the desired order (alphabetical or by characteristic), but I don´t know how to do this. I know this is basic stuff for you, but can anybody PLEASE help me? Thank you in advance!
Oh yes, the html blocks I am making are like this:
32 - TriceratopsTriassicoTriceratops
final result
instructions
open your excel file, and save it.
find the file of the excel in your desktop/folders.
go to the https://tableconvert.com/excel-to-json
drag the excel file to the website input to get the JSON
JSON is the simple key-value format, that we can use in javascript.
so we use this website to translate the excel to an easier format :)
here is the example excel I created (these are fake values because I am not an expert on dinos, but you can use your own values)
after pasting the excel/or dragging it, you will get the results in JSON format.
like you see below
copy the JSON code of the results.
paste the JSON inside a javascript file and assign it to a variable.
// this is an example
const dinoData = [{...}, {...}, {...}, {...}];
in the HTML we will create a wrapper container
<div id="container"></div>
inside the card, we will add the card divs
<div id="container">
<div class="card">...</div>
<div class="card">...</div>
<div class="card">...</div>
</div>
but with javascript.
so we can reuse the HTML by wrapping the code inside the <template>
<template>
<div class="card">...</div>
</template>
inside the cards, we will add some HTML tags that we add them with the info in JS
<template>
<div class="card">
<img class="image" />
<span class="name"></span>
<span class="type"></span>
<span class="weight"></span>
</div>
</template>
now we can get do a loop on the array by using forEach
dinoData.forEach((dino) => {
// do this test first, to check if all the things are correct
console.log(dino);
});
copy the card in javascript using .cloneNode(true)
const card = document.querySelector("#card-template").content;
dinoData.forEach((dino) => {
let newCard = card.cloneNode(true);
}
change the text inside the card by using .textContent
newCard.querySelector(".name").textContent = dino.name;
newCard.querySelector(".type").textContent = dino.type;
newCard.querySelector(".weight").textContent = dino.weight;
newCard.querySelector(".image").src = dino.image;
at the end add the card to the HTML by using .appendChild()
const container = document.querySelector("#container") ?? document.body;
container.appendChild(newCard);
we can implement now sorting code.
alphabetically
function sortAlfabetic(cards) {
const sorted = [...cards].sort((a, b) => {
return `${a.querySelector(".name").textContent}`.localeCompare(
`${b.querySelector(".name").textContent}`,
);
});
sorted.forEach((sortedCard, index) => {
sortedCard.classList.add(`order-${index}`);
});
}
As you see we used .sort() to order them alphabetically
also, another thing, don't use cards parameter directly but use [...cards] instead because this makes a copy and does not change the original one.
also for sorting strings, we used .localCompare() which returns us an index of the string character order.
example:
"a", "a" = 0
"a", "b" = -1
"a", "c" = -2
"c", "a" = 2
"d", "b" = 2
show only carnivorous
function showOnlyCarnivorous(cards) {
const sorted = sortAlfabetic(cards).filter((card) => {
return card.querySelector(".type").textContent == "carnivorous";
});
cards.forEach((card, index) => {
card.classList.add(`hidden`);
});
sorted.forEach((sortedCard, index) => {
sortedCard.classList.remove(`hidden`);
});
}
show only Herbivorous
function showOnlyHerbivorous(cards) {
const sorted = sortAlfabetic(cards).filter((card) => {
return card.querySelector(".type").textContent == "herbivorous";
});
cards.forEach((card, index) => {
card.classList.add(`hidden`);
});
sorted.forEach((sortedCard, index) => {
sortedCard.classList.remove(`hidden`);
});
}
complete code.
I added some styling using a framework but you can delete it if you want and style it like you want.
const dinoData = [{
name: "my dino",
type: "carnivorous",
weight: "1000kg",
image: "https://picsum.photos/559",
},
{
name: "another dino",
type: "herbivorous",
weight: "350kg",
image: "https://picsum.photos/560",
},
{
name: "alex dino",
type: "carnivorous",
weight: "500kg",
image: "https://picsum.photos/561",
},
{
name: "hello dino",
type: "carnivorous",
weight: "10kg",
image: "https://picsum.photos/562",
},
{
name: "minecraft dino",
type: "carnivorous",
weight: "957kg",
image: "https://picsum.photos/563",
},
{
name: "js dino",
type: "herbivorous",
weight: "486kg",
image: "https://picsum.photos/564",
},
{
name: "fish dino",
type: "carnivorous",
weight: "400kg",
image: "https://picsum.photos/565",
},
];
const container = document.querySelector("#container") ?? document.body;
const card = document.querySelector("#card-template").content;
dinoData.forEach((dino) => {
const newCard = card.cloneNode(true);
newCard.querySelector(".name").textContent = dino.name;
newCard.querySelector(".type").textContent = dino.type;
newCard.querySelector(".weight").textContent = dino.weight;
newCard.querySelector(".image").src = dino.image;
container.appendChild(newCard);
});
let cardArray = document.querySelectorAll(".card");
/* alfabetic button */
document.querySelector("#btn-alf").addEventListener("click", () => {
sortAlfabetic(cardArray);
});
/* carnivorous button */
document.querySelector("#btn-carn").addEventListener("click", () => {
showOnlyCarnivorous(cardArray);
});
/* herbivorous button */
document.querySelector("#btn-herb").addEventListener("click", () => {
showOnlyHerbivorous(cardArray);
});
function sortAlfabetic(cards) {
const sorted = [...cards].sort((a, b) => {
return `${a.querySelector(".name").textContent}`.localeCompare(
`${b.querySelector(".name").textContent}`,
);
});
sorted.forEach((sortedCard, index) => {
sortedCard.classList.remove("hidden");
sortedCard.classList.add(`order-${index}`);
});
return sorted;
}
function showOnlyCarnivorous(cards) {
const sorted = sortAlfabetic(cards).filter((card) => {
return card.querySelector(".type").textContent == "carnivorous";
});
cards.forEach((card, index) => {
card.classList.add(`hidden`);
});
sorted.forEach((sortedCard, index) => {
sortedCard.classList.remove(`hidden`);
});
}
function showOnlyHerbivorous(cards) {
const sorted = sortAlfabetic(cards).filter((card) => {
return card.querySelector(".type").textContent == "herbivorous";
});
cards.forEach((card, index) => {
card.classList.add(`hidden`);
});
sorted.forEach((sortedCard, index) => {
sortedCard.classList.remove(`hidden`);
});
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-50">
<div class="w-full p-4 grid md:grid-cols-2 gap-4">
<button id="btn-alf" class="bg-blue-500 p-4 w-full rounded-md text-lg font-bold text-white hover:bg-blue-700 transition">🔤 sort by alfabeth</button>
<div class="flex gap-4">
<button id="btn-carn" class="bg-blue-500 p-4 w-full rounded-md text-lg font-bold text-white hover:bg-blue-700 transition">🍖 carnivorous</button>
<button id="btn-herb" class="bg-blue-500 p-4 w-full rounded-md text-lg font-bold text-white hover:bg-blue-700 transition">🍏 herbivorous</button>
</div>
</div>
<div id="container" class="grid sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 2xl:grid-cols-7 gap-4 p-4"></div>
<template id="card-template">
<div
class="card bg-white grid shadow-lg rounded-md p-4 transition hover:-translate-y-1"
>
<img class="image w-full h-auto rounded-md" />
<span class="name">text1</span>
<span class="type">text2</span>
<span class="weight">text3</span>
</div>
</template>
<script src="./script.js"></script>
</body>
</html>
Can someone give me a clue, how to bind a variable value from a .model created?
I have used ng for in a div, then I can interpolate values from a .model.ts using:
ngFor let list of lists
then i {{name.list}}
But in other div, I just can show a dynamic name of a .model.ts, like name.list.
How can I do this?
Thanks
If you have in your component some data like:
usersList = [
{ name: "Michael", id: 1 },
{ name: "Linda", id: 2 }
];
In your template html you should do something like this:
<h2>List of users</h2>
<ul *ngIf="userList.length">
<li *ngFor="let user of userList">
Hello {{user.name}} (id: {{user.id}})
</li>
</ul>
<div *ngIf="!userList.length">No users</div>
I have the below structure, where I have my images data in the json format which has the links to the assets folder. Where all the images are placed. I was thinking to use this way of using images for testing as in future we will have images somewhere in the web and will fetch from the there based on the similar JSON:
- app
- core
- data
- img.json
- layout
- test.component.ts
- assets
- images
img.json:
{
"items" : [
{
"img": "/assets/images/test1.png",
"alt" : "Image 1"
},
{
"img": "/assets/images/test2.png",
"alt" : "Image 2"
},
{
"img": "/assets/images/test3.png",
"alt" : "Image 3"
}
]
}
test.component.ts:
import images from '../../data/img.json';
export class SlideshowComponent implements OnInit {
showNavigationArrows = false;
showNavigationIndicators = false;
items = [0, 1, 2].map((n) => images);
constructor(config: NgbCarouselConfig) {
// customize default values of carousels used by this component tree
config.showNavigationArrows = true;
config.showNavigationIndicators = true;
}
}
HTML:
<ngb-carousel *ngIf="items" [showNavigationArrows]="showNavigationArrows"
[showNavigationIndicators]="showNavigationIndicators">
<ng-template ngbSlide *ngFor="let item of items">
<div class="picsum-img-wrapper">
<img [src]="item" alt="Random slide">
</div>
</ng-template>
</ngb-carousel>
I am unable to connect the images to the HTML, any help would be great.
assuming your tsconfig is properly configured to import json (your ts compiler would throw errors at you if not)
you should be able to do this with:
items = images.items; // not sure why you had that index -> map structure?
and
<ng-template ngbSlide *ngFor="let item of items">
<div class="picsum-img-wrapper">
<img [src]="item.img" alt="{{ item.alt }}"> <!-- access the url and use the alt text -->
</div>
</ng-template>
extra based on comments:
if you want to optionally show a video tag, I'd recommend somehting like this:
items = images.items.map(i => Object.assign({}, i, {isVideo: i.img.endsWith('.mov')})) // this only works for mov obviously
template:
<ng-template ngbSlide *ngFor="let item of items">
<div class="picsum-img-wrapper">
<img *ngIf="!item.isVideo" [src]="item.img" alt="{{ item.alt }}"> <!-- simple ngIf to show right tag -->
<video *ngIf="item.isVideo" [src]="item.img" alt="{{ item.alt }}" controls></video>
</div>
</ng-template>
This is my version of Angular CLI:
Angular CLI: 7.3.9
Node: 12.2.0
OS: win32 x64
Angular: 8.0.2
While making an Angular 8 application, I am trying to use nested FormGroups which correspond to the following object:
const Boilerplate: any = {
1: {
desc: "section1",
content: {
1: "question 1.a:",
2: "question 1.b:",
3: "question 1.c"
}
},
2: {
desc: "section2",
content: {
4: "question 2.a:",
5: "question 2.b:",
6: "question 2.c",
7: "question 2.d"
}
}
}
There is an inner FormGroup of FormControls for section 1 and section 2, and an outer FormGroup holding the two inner formgroups. This is defined in the component.ts.
In the component.html, I am trying to iterate through the outer FormGroup's inner FormGroups, and print the inner FormControls. This is the code I have so far:
<form [formGroup]="sectionGroup">
<div *ngIf="boilerplate">
<div *ngFor="let section of boilerplate | keyvalue">
{{ boilerplate[section.key].desc }}
<div formGroupName="{{section.key}}">
<div *ngFor="let question of boilerplate[{{section.key}}]">
<-- things -->
</div>
</div>
</div>
</div>
The line <div *ngFor="let question of boilerplate[{{section.key}}]"> fails with an error message of:
Unexpected token {, expected identifier, keyword, or string
I have tried the following solutions, none of which have worked for me:
<div *ngFor="let question of {{boilerplate}}.{{section.key}}">
<div *ngFor="let question of {{boilerplate[section.key]}}">
<div *ngFor="let question of {{boilerplate[{{section.key}}]}}">
<td *ngFor="let question of Section">{{boilerplate[[section.key]]}}</td>
I have tried a variety of other {} and [] combinations and orders, and I realize now that nested interpolation is non-parsable.
Does anyone have a suggestion of how I can achieve this? I am using nested FormGroups because it is possible I will have additional layers of sections in the future. The format of the Boilerplate object can be changed if it would make the problem solvable (because I defined it, myself).
EDIT
The following was the solution that resolved this issue:
<div *ngFor="let question of boilerplate[section.key].content | keyvalue">
{{question.value}}
</div>
I try like below,
<div [formGroup]="formGroup">
<div *ngIf="boilerplate">
<div *ngFor="let section of boilerplate | keyvalue">
{{ boilerplate[section.key].desc }}
<div>
<div *ngFor="let question of boilerplate[section.key].content | keyvalue">
{{ question | json }}
</div>
</div>
</div>
Output is like below,
section1
{ "key": "1", "value": "question 1.a:" }
{ "key": "2", "value": "question 1.b:" }
{ "key": "3", "value": "question 1.c" }
section2
{ "key": "4", "value": "question 2.a:" }
{ "key": "5", "value": "question 2.b:" }
{ "key": "6", "value": "question 2.c" }
{ "key": "7", "value": "question 2.d" }
You need to use a keyValue filter pipe then you could just have the following syntax, this will let you use ngFor* to iterate though objects rather than arrays.
<div *ngFor="let question of boilerplate | keyValue">
{{ question.key }} - {{ question.value }}
</div>
You can then do the same for the nested objects inside until you have the correct data displayed. This is not supported in all versions of Angular, but definitely fine in 8.
Where you have Objects with the key as a number, I would look to manipulate that into an array which would help you keep this a little more simple. Allowing you to use traditional *ngFor
The answer from schoolcoder is great, I just would like to post another example for people in the future with the same problem.
I have an object Block that holds a list of Transactions and I want to show it on my page using two *ngFor's
Block model class:
export class Block {
hash: string;
previousBlockHash: string;
transactions: Transaction[]; <<<<<<<<<<<
merkleRoot: string;
tries: number;
timestamp: number;
}
Transaction model class
export class Transaction {
hash: string;
text: string;
senderHash: string;
signature: string;
timestamp: number;
}
How I show it on my page:
Blocks:
<div class="container">
<ul class="list-group">
<li class="list-group-item" *ngFor="let block of blocks | keyvalue">
Hash: {{blocks[block.key].hash}}<br>
Previous block hash: {{blocks[block.key].previousBlockHash}}<br>
Merkle root: {{blocks[block.key].merkleRoot}}<br>
Tries: {{blocks[block.key].tries}}<br>
Timestamp: {{blocks[block.key].timestamp}}<br>
Transactions in this block:
<ul class="list-group">
<li class="list-group-item" *ngFor="let transaction of blocks[block.key].transactions">
{{[block.key]}}<br>
Hash: {{transaction.hash}}<br>
Text: {{transaction.text}}<br>
SenderHash: {{transaction.senderHash}}<br>
Signature: {{transaction.signature}}<br>
Timestamp: {{transaction.timestamp}}
</li>
</ul>
</li>
</ul>
</div>
I create a json file like
{ "tests": { "CHE": { "Failover": [ "Standalone Box Restart" ],
"Smoke": [ "All Domains Are Published", "No FID Duplication", "PE and
RIC Mangling", "Real Time Updates - FTN", "Only One Response Message
Per Constituent", "LIVE-STANDBY-LIVE Switch" ] }, "Queries": {
"Queries": [ "Get Services For Region" ] } } }
How to show on the HTML like a tree really hurry up. Thank you
Like That:
enter image description here
You can try like this way.
First of all you need to create pipe using ng generate pipe testPipe (this will also import the dependency in app.module.ts file) for converting the object to array for looping through the elements.
test-pipe.pipe.ts
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'keys'
})
export class TestPipePipe implements PipeTransform {
transform(value, args:string[]) : any {
let keys = [];
for (let key in value) {
keys.push({key: key, value: value[key]});
}
return keys;
}
}
In your template file place below mentioned code.
<div *ngFor="let item of data | keys">
<ul>
<li>
{{item.key}}
<ul *ngFor="let inItem of item.value | keys">
<li>
<input type="checkbox" name="">{{inItem.key}}
<ul *ngFor="let ininItem of inItem.value | keys">
<li>
<input type="checkbox" name="">{{ininItem.key}}
<ul *ngFor="let inininItem of ininItem.value | keys">
<li>
<input type="checkbox" name="">{{inininItem.value}}
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
in your component file you can right like.
data = { "tests": { "CHE": { "Failover": [ "Standalone Box Restart" ], "Smoke": [ "All Domains Are Published", "No FID Duplication", "PE and RIC Mangling", "Real Time Updates - FTN", "Only One Response Message Per Constituent", "LIVE-STANDBY-LIVE Switch" ] }, "Queries": { "Queries": [ "Get Services For Region" ] } } }