dynamic import of images react - reactjs

I am trying to dynamically render images from a local folder within my project
The object structure looks like this
{
id: 2,
text: 'How would you describe your level of influence in management of the farm?',
type: 'cardChoice',
choices: [
{
id: 1,
text: 'I am the primary decision maker',
questionId: 'Hm?',
value: 'I am the primary decision maker',
image: '1.jpg',
},
{
id: 2,
text: 'I hent',
questionId: 'Hrm?',
value: 'I',
image: '2.jpg',
},
{
id: 3,
text: 'I arm',
questionId: '?',
value: 'Irm',
image: '3.jpg',
},
],
},
In my component I select the folder that contains the images const baseUrl = '../../assets/images/CNA'
After that, in my return I try to render the images
<img src={`${baseUrl}'${questionChoice.image}'`} alt={questionChoice.text} />
The page renders, but my image isn't loading and it's showing my alt instead
Heres my full component
const CardChoiceQuestions = ({ cardChoiceArray, currentAnswer, updateCurrent, submitAnswer }) => {
const { id, value } = currentAnswer
const baseUrl = '../../assets/images/CNA'
return (
<ButtonContainer>
{cardChoiceArray.map(questionChoice => {
return (
<Button
active={questionChoice.id === id}
type="button"
key={questionChoice.id}
onClick={() => {
const answer = { id: questionChoice.id, value: questionChoice.value }
updateCurrent(answer)
submitAnswer()
}}
>
<p>{questionChoice.text}</p>
<img src={`${baseUrl}${questionChoice.image}`} alt={questionChoice.text} />
</Button>
)
})}
</ButtonContainer>
)
}

I don't have my laptop in front of me but a few things I noticed. Do you need a slash "/" after your base url? Also, the string concatenation should be completed in one set of brackets after the $ sign. Not sure if that's the issue try a few console.log(string path) amd verify it is going where you think it is. It looks like the path may be wrong. You may be better off conditional rendering images as opposed to building a dynamic url but either way it should render on change.

<img src={`${baseUrl}/${questionChoice.image}`} alt={questionChoice.text} />
use like this

Leaving this here in case someone comes across this...
<img src={require(`../../assets/images/CNA/${questionChoice.image}`)} alt={questionChoice.text} />
Not sure why I can't use ${baseUrl} but this works for now.

Related

Display nested JSON data using React

I'm displaying a Facebook feed, I've mapped the array that I've got from a JSON file to display the data, and so far so good.
let feedDisplay = feedArray.map((fbPost, index) => {
console.log(fbPost.attachments)
return (
<div key={index} >
<img src={fbPost.full_picture} />
<p>
{fbPost.message}
</p>
</div>
);
});
Now I want to display the data I get from fbPost.attachments which is an object with an array containing yet another object. I don't know what method I should use to access and display this.
{
data: [
{
description: 'some description',
media: { image: { src: 'source' } },
title: 'title',
},
],
};
What I want to display is everything inside data - description, media and title.

How to give Image src dynamically in react js?

I am trying to give image name in src dynamically. I want to set image name dynamically using variable with path. but I am not able to set src correctly. I tried solutions on stackoverflow but nothing is working.
I tried to give path like this
<img src={`../img/${img.code}.jpg`}></img>
<img src={'../img/' + img.code + '.jpg'}></img>
<img src={'../img/{img.code}.jpg'}></img>
my images are saved in src/img path
if i give path like this
<img src={require('../img/nokia.jpg')}/>
image is showing
I know this question is asked before but nothing is working for me.
Please help me how can I set image path?
if you dont want to require the image then you have to put all your images into public folder and then
<img src={`../img/${img.code}.jpg`}></img>
this method will work.
You can still use require
<img src={require(`./img/${img.code}.jpg`)}/>
It's not recommended to manually add images to the public folder. See this answer here: https://stackoverflow.com/a/44158919/1275105
One pretty simple solution:
// images.js
const images = [
{ id: 1, src: './assets/image01.jpg', title: 'foo', description: 'bar' },
{ id: 2, src: './assets/image02.jpg', title: 'foo', description: 'bar' },
{ id: 3, src: './assets/image03.jpg', title: 'foo', description: 'bar' },
{ id: 4, src: './assets/image04.jpg', title: 'foo', description: 'bar' },
{ id: 5, src: './assets/image05.jpg', title: 'foo', description: 'bar' },
...etc
];
export default images;
You can then import it form another component like this:
// MyComponent.js
import images from './images'
//...snip
{ images.map(({id, src, title, description}) => <img key={id} src={src} title={title} alt={description} />)
Dynamic require doesn't seems to be clean and also eslint isn't happy with it (not sure why)
Other two approaches if images are stored in public folder :
const imgNameWithPath = '/fullImageNameWithPath.jpg'
Using env
<img src={process.env.PUBLIC_URL + imgNameWithPath} />
Using location origin:
<img src={window.location.origin + imgNameWithPath} />
If you guys get the path from the database for multiple images and need to use in single tag, you can follow the below method.
step 1 : Please make sure the images are in public folder.
step 2 : Update your path should start from public not from src.
step 3 : Make sure to verify that the path should be using like a variable. If your images path should be using in variable imgPath. You can use your code like var imgPath = '/img/pic.jpeg'
"src={imgPath}"
I hope this will help you..

how to access an object element in a vue js list (nuxt)

I have an array of object like that :
{ id: 33617,
datePublication: 1532266465,
dateUpdate: 1532266574,
headline: 'An headline title here',
images: [ [Object] ] },
{ id: 33614,
datePublication: 1532265771,
dateUpdate: 1532271769,
headline: 'another super headline article',
images: [ [Object], [Object], [Object], [Object], [Object] ] }
so i iterate that way on my vue js template :
<v-flex v-for="(ip, i) in ips" :key="i" xs12 sm6 >
<v-card>
<v-card-media
:src="ip.images[0].url"
height="200px"
/>
<v-card-title primary-title>
<div>
<h3 class="headline mb-0">{{ ip.headline }}</h3>
<div>Located two hours south of Sydney in the <br>Southern Highlands of New South Wales, ...</div>
</div>
</v-card-title>
<v-card-actions>
<v-btn flat color="orange">Share</v-btn>
<v-btn flat color="orange">Explore</v-btn>
</v-card-actions>
</v-card>
</v-flex>
And here is my associated script :
var api = "https://my api.org/news/fr-FR/2018-25-07";
export default {
data() {
return {};
},
layout: "no-live",
async asyncData({ app }) {
const ips = await app.$axios.$get(api);
console.log(ips);
return { ips };
}
};
Each object in the images array should return me an id and an url, so i want to take that url as a source in my image but i have this error : Cannot read property '0' of undefined
it seems i need to do another loop over the images array, is there a proper way to do that with vue JS ?
if you have any objects in ips that doesn't have images, you would get that error,
you can try to add a conditional to not have an error in rendering
<v-card-media
v-if="ip.images && ip.images[0]"
:src="ip.images[0].url"
height="200px"
/>
I usually add a <pre>{{ip}}</pre> in these cases to see what's going on.
Try put v-if="ip.images" on v-card-media component. You will assure the images are not empty and loaded.

Is there a way to add headings separating data in react-virtualized

I have a <List /> inside an <InfiniteLoader />, inside an <AutoSizer />, also <WindowScroller /> and <WindowScroller /> 😁 (wow, so much hocs there) but for simplicity, I think my question could fit the same with a simple <List /> Component.
I'm not sure if there is a way to render some kind of separator or heading like a title for the section (piece of data) rendered below.
Since each item have a prop that allow to group the data in chunks, and I am receiving this data ordered and grouped like:
[
{
item: 1,
name: 'Banana',
kind: 'fruits',
},
{
item: 2,
name: 'Apple',
kind: 'fruits',
},
{
item: 3,
name: 'Watermelon',
kind: 'fruits',
},
{
item: 4,
name: 'Dog',
kind: 'animals',
},
{
item: 5,
name: 'Cat',
kind: 'animals',
},
{
item: 6,
name: 'Horse',
kind: 'animals',
},
//...
]
the idea is to render something like:
<ul>
<li className="fullWidth">
<h3>Fruits</h3>
</li>
<li>Banana</li>
<li>Apple</li>
<li>Watermelon</li>
<li className="fullWidth">
<h3>Animals</h3>
</li>
<li>Dog</li>
<li>Cat</li>
<li>Horse</li>
</ul>
Making some calculation in rowRenderer method?
Or, since I am wrapping the <List /> in an <InfiniteLoader /> I could pass an argument when fire loadMoreRows, but anyway I think I have to do some calculation in rowRenderer, the responsible for the final render.
This is possible, although much easier if your data is pre-sorted so that groups aren't interleaved. You basically have 2 options:
Pre-flatten your data into an array of 2 types of items. One type is a header and the other type is a child. If you want headers to be a different size than regular rows you'll need to also provide a rowHeight getter function that's able to distinguish between a header item and a child and return a different value. Your rowRenderer will also need to do the same.
Compare the current datum's "kind" to the one that came before it and include a header with the rendered row if they are different. This approach also requires a custom rowHeight getter but does not require any data flattening so it may be easier/faster. The only downside is that your header and row item will be within the same div (or li) if you approach this way.
Here's an example of option 2: https://plnkr.co/edit/l22Ir7?p=preview
And here is the relevant code bits:
function includeHeader(index) {
return (
index === 0 ||
list[index].kind !== list[index - 1].kind
);
}
function rowHeight({ index }) {
return includeHeader(index)
? ROW_HEIGHT_WITH_HEADER
: ROW_HEIGHT;
}
function rowRenderer({ index, isScrolling, key, style }) {
const datum = list[index];
return (
<div
className='Row'
key={key}
style={style}
>
{includeHeader(index) && (
<h3>{...}</h3>
)}
<div>{...}</div>
</div>
);
}

Angular2: How do you properly bind to nested data?

I have a component I'm going to use as a shell for multiple choice questions to load into. Here's how the component is set up so far
component
import { Component } from '#angular/core';
export class Answers{
id: string;
answer: string;
}
const answers: Answers[] = [
{
id: 'exp01q',
answer: 'Its fine as is.'
},
{
id: 'exp02q',
answer: 'I want to make minor adjustments.'
},
{
id: 'exp03q',
answer: 'I want to change my image'
},
{
id: 'exp04q',
answer: 'Ive never wanted to use a particular image until now.'
}
];
#Component({
moduleId: module.id,
selector: 'multi-radio-btn',
templateUrl: 'multi-rad-btn.component.html',
styleUrls: ['multi-rad-btn.component.css']
})
export class MultiRadioBtnShell {
question = 'How do you feel about your current image?';
id = 'exp-img-q';
name = 'exp-ques1';
ans = answers;
}
HTML Template
<h3>radio button shell</h3>
<div class="row justify-content-center">
<fieldset [attr.id]='id' class="card col-8 justify-content-center">
<label class="ques-title">
{{question}}
</label>
<div class="row answer-row-section justify-content-center">
<div *ngFor="let answers of ans" class="col col-12 answer-row justify-content-center">
<div class="col justify-content-center">
<input type="radio"
[attr.id]="answers.id"
[attr.name]="name"
[attr.value]="answers.answer" hidden />
<label [attr.for]="answers.id" class="col ques-ans-title" style="background-color: #4b73a0;">
{{answers.answer}}
</label>
</div>
</div>
</div>
</fieldset>
</div>
The reason it's set up like this now is because the way I was trying to do it at first wasn't working so I went to the Tour of Heroes tutorial to follow along with how they loaded all the heroes. The problem was coming from answer not being defined. So I rigged that part up the same way they did the heroes just for the sake of doing something I'm able to follow just to be sure I get the mechanics of how things load.
The original way I tried to do it was with this
// I had this right above the component
export class ExpQ{
question: string;
id: string;
name: string;
answers:[
{
id: string;
answer: string;
}
]
}
// I had this in the component's class
export const expq: ExpQ[] = [
{
question: 'How do you feel about your current image?',
id: 'exp-img-q',
name: 'exp-ques1',
answers:[
{
id: 'exp01q',
answer: 'Its fine as is.'
},
{
id: 'exp02q',
answer: 'I want to make minor adjustments.'
},
{
id: 'exp03q',
answer: 'I want to change my image'
},
{
id: 'exp04q',
answer: 'Ive never wanted to use a particular image until now.'
}
]
}
]
I was calling it in the html with
{{expq.question}}, {{expq.name}}, {{expq.answers.id}}, {{expq.answers.answer}}, etc.
at first with just loading the question it worked fine, but as I got to the answers: part it started breaking. I came across this https://scotch.io/tutorials/using-angular-2s-model-driven-forms-with-formgroup-and-formcontrol and seen the syntax for the addresses: part was pretty much the same as how I needed to structure my data. So I remade everything to resemble that. I still had no luck getting it to work.
Ultimately I'm going to be sending the questions through the parent component with #input and #output as well as a couple other tricks I came across. But before I can even think about that I need to get a handle on how to put the data all into one source so that it properly reads the nested bits of data. All the examples I come across are simple single tier bits of data, so I'm not sure on the syntax I need to use. How can I make this work?
You can define your model like so:
export interface Answer {
id: string;
answer: string;
}
export interface Question {
id: string;
name: string;
question: string;
answers: Answer[];
}
Then your component could have this to test
question1: Question = {
id: 'q1',
name: 'q1',
question: 'Does TypeScript rule?',
answers: [
{ id: 'a1', answer: 'Yes' },
{ id: 'a2', answer: 'Of Course' },
{ id: 'a3', answer: 'Duh' }
]
};
Of course the names don't have to be the same but I think this gives you a better idea of how to model nested data.
Then to display it you will need to iterate over nested structures. Look up the *ngFor directive. You will want to iterate over your answers in this case. Ex:
<div *ngFor="let answer of question1.answers">
{{answer.id}} - {{answer.answer}}
</div>
Need to flatten the objects,
Params :
Objects : at least n>0 array off JSON objects (dose not matter is circular)
target : {}
path : ""
Note : make sure the Objects Array passed in is n>0 at least
flatten(objects, target, path) {
let me = this;
let retArray = [];
for(let x=0; x < objects.length; x++) {
let object = objects[x];
path = path || '';
target={};
target = me.flattenHelper(object, target, path);
retArray.push(target);
}
return retArray;}
..
flattenHelper(object, target, path){
let me = this;
Object.keys(object).forEach(function (key) {
console.log("key : "+ key + " : object : " + (object[key] && typeof object[key] === 'object') + " path : " + path);
if (object[key] && typeof object[key] === 'object') {
me.flattenHelper(object[key], target, path + key);
}
target[path + key] = object[key];
console.log(target);
});
return target;}

Resources