React, load images local from json - json

Yes, this question may be duplicated from other questions, but I couldn't find solution for this problem.
I create something simple
1 component that read a json and load image.
The json
{
"images": [
{
"id": 1,
"url": "../assets/images/slider/croissant-other.jpg",
"description": "Croissant"
},
{
"id": 2,
"url": "../assets/images/slider/croissant-3570.jpg",
"description": "Croissant 3570"
}
]
}
The component
import React from "react";
import jsonCarrousel from "../data/carrousel.json";
function Carrousel() {
return (
<div>
{jsonCarrousel.images.map((image, i) => (
<div className="item" key={i}>
<img src={require(`${image.url}`)} alt={image.description} key={i} />
</div>
))}
</div>
);
}
export default Carrousel;
The example in live
https://codesandbox.io/s/stupefied-fast-1zfdj
The error:
/src/assets/images/slider/croissant-other.jpg hasn't been transpiled yet.

Compiled code will look into /public to find your images. You should move your assets to /public instead of src. (manually or by bundle tool)
Also, image source should be src={`${image.url}`}
https://codesandbox.io/embed/elastic-solomon-1ul1o

This is a more descriptive solution.
To load images dynamically from a local JSON file, you need to put the images that you would like to use in the JSON file, inside a folder in the public folder (you can name it whatever you like). E.g. public/images/imgage.png.
You can then render it with:
You can import it in your JSON like so:
{
"images": [
{
"id": 1,
"url": "/images/imgage.png"
}
]
}
...
<img src={require(`${image.url}`)} alt={image.description} key={i} />
...
create-react-app has a public folder by default.
The folder structure would look something like this:
└───public
│ └───images
│ │ image.png
│
└───src
│ yourfiles.js
Alternatively, you can import the images that are in the src folder, directly in the react component to render them:
import img from "./imgage.png";
const component = () => <img src={img} />

{
"images": [
{
"id": 1,
"url": "https://image.freepik.com/free-photo/image-human-brain_99433-298.jpg",
"description": "Croissant"
},
{
"id": 2,
"url": "https://www.belightsoft.com/products/imagetricks/img/core-image-filters#2x.jpg",
"description": "Croissant 3570"
}
]
}
Code changed
function Carrousel() {
return (
<div>
{jsonCarrousel.images.map((image, i) => (
<div className="item" key={i}>
<img src={image.url} alt={image.description} key={i} />
</div>
))}
</div>
);
}

Related

How to display Markdown files containing HTML syntax in Gatsby?

I am using Markdown file to generate pages for gatby. In order to control the style of pictures, I use html syntax. However, the page generated by gatsby does not display the html part.
This is my markdown file:
---
......frontmatter......
---
......content......
<table>
<tr>
<td><img src="./images/2018/zotero/ZoteroWebDAV.png"></td>
<td><img src="./images/2018/zotero/ZoteroExts.png" width=100%></td>
</tr>
</table>
......content......
Everything else is rendered normally, however, neither the table nor the pictures in it are displayed. Here is my gatsby-config.js.
{
resolve: `gatsby-transformer-remark`,
options: {
excerpt_separator: `<!-- endexcerpt -->`,
plugins: [
// 'gatsby-remark-relative-images',
{
resolve: `gatsby-remark-images`,
options: {
maxWidth: 1200,
},
},
{
resolve: `gatsby-remark-image-attributes`,
options: {
dataAttributes: true
}
},
],
},
},
What can I do to make the html part in Markdown render normally?
You can use as well the built-in dangerouslySetInnerHtml property or any markdown parser like markdown-to-jsx.
Using the first approach, following Gatsby's guides:
import React from "react"
import { graphql } from "gatsby"
export default function Template({data}) {
const { markdownRemark } = data // data.markdownRemark holds your post data
const { frontmatter, html } = markdownRemark
return (
<div className="blog-post-container">
<div className="blog-post">
<h1>{frontmatter.title}</h1>
<h2>{frontmatter.date}</h2>
<div
className="blog-post-content"
dangerouslySetInnerHTML={{ __html: html }}
/>
</div>
</div>
)
}
export const pageQuery = graphql`
query($id: String!) {
markdownRemark(id: { eq: $id }) {
html
frontmatter {
date(formatString: "MMMM DD, YYYY")
slug
title
}
}
}
`
Because you haven't shared your query I've used the one in the guide but tweak it as you wish. As you can see, everything that is in the end of the frontmatter is html:
<div
className="blog-post-content"
dangerouslySetInnerHTML={{ __html: html }}
/>
Using the second approach, and following the previous query structure, the html should be rendered as:
import Markdown from 'markdown-to-jsx';
import React from 'react';
<Markdown>{html}</Markdown>
If there's any hindrance I'd say that the second approach is better because, as the dangerouslySetInnerHTML name suggests, you are potentially exposing your site to XSS (Cross-Site Scripting), while the second approach sanitizes the implementation.

Binding JSON URL to IMG in Vue 3

I'm building an app in Vue 3 that lists local stores. To add and remove stores I've made a JSON file that lists them, including a URL to an image icon (SVG). The JSON file is imported in my Vue component and lists the stores correctly. However, this is not the case for the image files, see code below.
JSON
[
{
"storeName": "Kapper",
"storeId": "s0001",
"imgUrl": ""
},
{
"storeName": "Manicure",
"storeId": "s0002",
"imgUrl": ""
},
{
"storeName": "Supermarkt",
"storeId": "s0003",
"imgUrl": "../../assets/icons/021-grocery.svg"
]
VUE
<template>
<ul class="storeList">
<li class="store" v-for="data in $options.stores" v-bind:key="data">
{{data.storeName}}
<img :src="data.imgUrl"/>
</li>
</ul>
</template>
<script>
import stores from './stores.json'
export default {
stores: stores,
}
</script>
<style lang="scss" scoped>
#import './styles.scss';
</style>
Some things I found out:
Hardcoding the URL seems to work fine
Placeholders from the web also seems to work fine (e.g https://picsum.photos/200 works perfectly)
Other file extensions such as .png also don't work
Changing the directory of the icons is what worked for me in the end. Changed the icons from the "assets" folder to the "public" folder.

How to display data using a for loop in Timeline (Material-UI) - React

I have a data in the form of json as given below:
[
{
"module_id": 2,
"module_type": "Instructional",
"module_name": "Introduction and Course Overview",
"duration": 30,
"course": {
"course_id": 1,
"course_name": "AWS"
}
},
{
"module_id": 1,
"module_type": "Instructional",
"module_name": "Quiz",
"duration": 20,
"course": {
"course_id": 1,
"course_name": "AWS"
}
}
]
Now, I have the following code in react and I want to render it on timeline:
Timeline Code (Material - UI)
return(
<Timeline align="alternate">
<TimelineItem>
<TimelineSeparator>
<TimelineDot color="primary">
<LaptopMacIcon />
</TimelineDot>
<TimelineConnector />
</TimelineSeparator>
<TimelineContent>
<Paper elevation={3} className={classes.paper}>
<Typography variant="h6" component="h1">
**Here, I want to display the module_name i.e Introduction and Course Overview and Quiz**
</Typography>
</Paper>
</TimelineContent>
</TimelineItem>
<TimelineItem>
)
Please help on how to do the same, I want the timeline to have the laptop icon with something like this
Introduction and Course Overview
|
|
Quiz
Thank you in advance :)
You have to map your json to <TimelineItem />, which you can do by writting a function as below
const getModules = () => {
return res.map((r, i) => {
const className = i % 2 === 0 ? "custom-even-class" : "custom-odd-class";
return (
<TimelineItem classes={{ alignAlternate: className }} key={r.module_id}>
<TimelineSeparator>
<TimelineDot />
<TimelineConnector />
</TimelineSeparator>
<TimelineContent>{r.module_name}</TimelineContent>
</TimelineItem>
);
});
};
This function will return list of <TimelineItem /> and to render it you can call this function within your render function, as shown below
return (
<Timeline align="alternate">
<TimelineItem>
<TimelineSeparator>
<TimelineDot>
<LaptopMacIcon />
</TimelineDot>
<TimelineConnector />
</TimelineSeparator>
<TimelineContent></TimelineContent>
</TimelineItem>
{getModules()}
</Timeline>
);
After this you will see timeline like this
Now as you mentioned you want your timeline to look like this, with starting Item as laptop icon, we have to use alternate timeline, and by default implementation all even item will be displayed in left and odd items will be displayed in right of the timeline, as you can see from above image.
Introduction and Course Overview
|
|
Quiz
So to modify it as per your question, I implemented a hacky way to modify the default CSS
and made it look like as below
you can check the final code here https://codesandbox.io/s/recursing-fire-nbpmu?file=/src/styles.css

How can i access to 'download_url' in json using vuejs

i want to get 'tags' and 'download url' inside meta, i cannot access to 'download_url' in json how i can do it, as a backend i am using wagtail cms, and is it good to use vue js with wagtail cms (headless cms)
<template>
<div>
<div>
<b-card-group deck v-for="item in results" :key="item.id">
<b-card
>
<b-card-text>
<div v-for="block in item.body" :key="block.id">
<div v-if="block.type == 'heading'">
<h2>{{block.value}}</h2>
</div>
<div v-if="block.type == 'image'">
<img :src="'http://127.0.0.1:8000/api/v2/images/' + block.value">
</div>
<div v-if="block.type == 'paragraph'">
<h2 v-html="block.value">{{block.value}}</h2>
</div>
</div>
</b-card-text>
>
</b-card>
</b-card-group>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'Home',
data () {
return {
results: null
}
},
mounted () {
axios.get('http://127.0.0.1:8000/api/v2/pages/?type=news.NewsPage&fields=intro,body,image_thumbnail')
.then((response) => (
this.results = response.data.items
))
}
}
</script>
here is json api. i accessed till id of image and do not know what to do next
{
"id": 3,
"meta": {
"type": "wagtailimages.Image",
"detail_url": "http://localhost/api/v2/images/3/",
"tags": [
"gadget",
"phone",
"samsung"
],
"download_url": "/media/original_images/affordable_new_9-7-inch_ipad_group_fan2_1_1.png"
},
"title": "affordable_new_9-7-inch_ipad_group_fan2 1 (1).png",
"width": 528,
"height": 357
}
Assuming that response.data.items is the json you showed above, you can extract just what you want from there. Right now, your component has the whole response.data.items in this.response. So if you want all of it there, keep that.
You can store the 'tags' and 'download url' to your component by adding two new pieces of data ie add them to your data:
data () {
return {
results: null,
tags: null,
downloadUrl: null
}
... and then set those in your response block from the request's response like this.
mounted () {
axios.get('http://127.0.0.1:8000/api/v2/pages/?type=news.NewsPage&fields=intro,body,image_thumbnail')
.then((response) => (
this.results = response.data.items
this.tags = response.data.items.meta.tags
this.downloadUrl = response.data.items.download_url
))
}
When dealing with nested response objects like this, it can help to make a local variable with the data and add it that way. Also, if you dont need the whole response, you can avoid storing it and just store the data from the response that you want to your component here. If you wanted to get something from your this.response, you're going to have to go deep into it. It would be cleaner to just pull out only what you need, and then use it in your code with just one {{myStuffIPulledOut}} vs {{response.thingIWantBefore.actualThing.}}

Using a image path in a JSON object to dynamically render image in component

I am running into an issue that seems to be "similar" to other issues dealing with a JSON object in React, though I can not seem how to translate these answers. I am creating a small game inside of React (not React Native). I am able to call my JSON object and pull text, though, when it comes to pulling an image path, it will not render. To get a basic idea of this game (that was in HTML/ JS) take a look at this link for the overall functionality.
Here is the Issue, I have a dynamically rendering set of objects based on state in the parent Component (GameLogic.js). I am then passing state down to the great-great-grandchild elements where it will render a two photos. These photo paths are stored in a local JSON file (I can read strings from the characters.json file in a console.log at this level). Though it can read the path (via console.log), it is not rendering these images. I am how ever able to render these images as long as I am not stringing together a long dynamic path.
Here is the file structure:
-components folder
|-GameLogic.js (parent element that handles the render)
|-Bandersnatch.js (child element)
|-NewComponents folder
|-ImageContainer.js (grandChild element)
|-ImageSquare.js (great grandChild element)
-images folder
|-snatch_images folder (yes... I know how bad this sounds...)
|-escape_snatch.png
|-The rest of the images (there are about 20)
-characters.json
-App.js
JSON example: I need the file path at Array[0].scene[0].choiceOneImg
[
{
"name": "Giraffe",
"alive": true,
"active": true,
"staticImg": "images/characters/static/static_giraffe.png",
"animatedImg": "images/characters/animated/animated_giraffe.png",
"cagedImg": "images/characters/caged/caged_giraffe.png",
"scene": [
{
"used": false,
"backgroundImg": "images/BG_images/zooBG.png",
"question": "........." ,
"answerTrue": ".......",
"answerFalse": ".......",
"choiceOne": "RUN FOR IT!",
"choiceTwo": "Stay loyal",
"choiceOneImg": "../images/snatch_images/escape_snatch.png",
"choiceTwoImg": "images/snatch_images/stay_snatch.png",
"incorrectResult": 0,
"correctAnswer": "choiceOne",
"correct": true
},
Here is the Parent, GameLogic.js that passes the currentCharacter, sceneLocation from the state that is constantly changing:
import React, { Component } from "react";
import Snatch from "./Bandersnatch";
import characters from "../characters.json";
class GameLogic extends Component {
state ={
unlockedCharacters : 0,
currentCharacter : 0,
sceneLocation : 0,
points : 0,
showCaracterSelect: true,
showMessage: false,
showSnatch: false,
showCanvas: false,
}
componentDidMount() {
}
render() {
return (
<Snatch
sceneLocation = {this.state.sceneLocation}
currentCharacter = {this.state.currentCharacter}
choiceOneAlt = "ChoiceOne"
choiceOneImg = {characters[this.state.currentCharacter].scene[this.state.sceneLocation].choiceOneImg}
choiceTwoAlt = "ChoiceTwo"
choiceTwoImg = {characters[this.state.currentCharacter].scene[this.state.sceneLocation].choiceTwoImg}
/>
)
}
}
export default GameLogic;
Then this is passed to the child component, Bandersnatch.js:
import React, { Component } from "react";
import characters from "../characters.json";
import { HeaderH2, ImageContainer, ImageSquare, ImageText, ProgressBar, Timer } from "./NewComponents/AllComponents";
const Snatch = (props) => {
return (
<>
<title>Decision Time</title>
<div className="w3-container">
<div className="container">
<HeaderH2 text="What Would You Like To Do?" />
<div className="row">
<ImageContainer
sceneLocation = {props.sceneLocation}
currentCharacter = {props.currentCharacter}
choiceOneAlt = {props.choiceOneAlt}
choiceOneImg = {props.choiceOneImg}
choiceTwoAlt = {props.choiceTwoAlt}
choiceTwoImg = {props.choiceTwoImg}
/>
{/* <ProgressBar /> */}
{/* <ImageText
sceneLocation = {props.sceneLocation}
currentCharacter = {props.currentCharacter}
/> */}
</div>
</div>
</div>
</>
);
}
export default Snatch;
Which is then passed to ImageContainer:
import React, { Component } from "react";
import ImageSquare from "./ImageSquare";
import characterObject from "../../characters.json";
const ImageContainer = (props) => {
return (
<>
<div className="col-md-6 optionOneclassName">
<ImageSquare
imgsrc={props.choiceOneImg}
altText={props.choiceOneAlt}
/>
</div>
<div className="col-md-6 optionTwoclassName">
<ImageSquare
imgsrc={props.choiceTwoImg}
altText={props.choiceTwoAlt}
/>
</div>
</>
)
};
export default ImageContainer;
And then finally accepted in the ImageSquare.js:
import React from "react";
const ImageSquare = (props) => { // passing in the img src
return (
<img src={props.imgsrc} alt={props.altText} height="600" width="600" />
)
};
export default ImageSquare;
Thank you so much for your help! I am not sure if it is easier, but the repo is here
Use require to load the image. Passing path to img directly won’t work. Either you need import or require to load the image
You need to add ../ before path
Change
import React from "react";
const ImageSquare = (props) => { // passing in the img src
return (
<img src={props.imgsrc} alt={props.altText} height="600" width="600" />
)
};
export default ImageSquare;
To
import React from "react";
const ImageSquare = (props) => { // passing in the img src
const path = "../"+props.imgsrc;
return (
<img src={require(path)} alt={props.altText} height="600" width="600" />
)
};
export default ImageSquare;