Dynamically change Image -> React component - reactjs

I have an array data which is passed to a reusable component.
const data = [
{
title: "A",
source: "facebook",
},
{
title: "B",
source: "youtube",
},
{
title: "C",
source: "twitter",
},
];
This is how my re-useable component looks like :
import facebook from "../../images/facebook.png";
import youtube from "../../images/youtube.png";
import twitter from "../../images/twitter.png";
function NumberBox({ data }) {
return (
<>
{data.map((item) => (
<>
<div className="title">{item.title}</div>
<img src={item.source} className="image" />
</>
))}
</>
);
}
I want to dynamically change the img element based on the data from props...like facebook icon, Twitter icon etc. With the code I have written here, i get blank image icon against {item.source} all the time but if i replace {item.source} with {facebook} it works properly. Can someone tell me what I'm doing wrong here?
Thanks.

The string "facebook" is not the same as the image facebook, which will be resolved by webpack to be the full url to the image. You can do it in two ways, one using a map:
image_map = {
facebook: facebook,
...
}
<img src={image_map[data.source}]>
Other way is to place the url in data:
import facebook from '../images/facebook.png'
data = [
title: 'facebook',
image: facebook // Notice: no quotes
]

source: twitter Source must be a reference to a variable( you imported img source), not a string
const data = [
{
title: 'A'
source: facebook // facebook but not 'facebook'
},
{
title: 'B'
source: youtube
},
{
title: 'C'
source: twitter
}
];

In your code item.source is a string (like 'facebook'), and has no relation with the image imported import facebook from '../../images/facebook.png';
The easy and clean way is setting the image in data, by importing:
import facebook from '../../images/facebook.png';
const data = [
{
title: 'A',
source: 'facebook',
image: facebook,
},
... or usign a public url:
const data = [
{
title: 'A',
source: 'facebook',
image: 'https://domain/public-url-to-image.jpg',
},
and later:
<img src={data.image} />

item.source is a string not a source path to a file. To resolve this issue you can check which item.source is and use the source from the import statement like following:
function NumberBox({ data }) {
return (
<>
{data.map((item) => (
<>
<div className="title">{item.title}</div>
{item.source === 'facebook' && <img src={facebook} className="image" />}
{item.source === 'twitter' && <img src={twitter} className="image" />}
{item.source === 'youtube' && <img src={youtube} className="image" />}
</>
))}
</>
);
}

You are referencing a string which happens to be "facebook", "youtube" or "twitter" it is not an image file. If you use the imported image which name is "twitter" then it will show the image. You have to update your data array to reference the image variable. Remove the quote marks and it should work. Example how to use with links. Your data should be
const data = [
{
title: "A",
source: facebook,
},
{
title: "B",
source: youtube,
},
{
title: "C",
source: twitter,
},
];
https://codepen.io/shnigi/pen/MWvpMeE

Related

react-data-table-component ouput data in ExpandComponent

Hello good people on the Internet. I am using react-data-table-component library and I want to output something when a row is expanded, when the first row is expanded it should should show this is row one and the second this is row two like that but i cant figure out how to do it. Any help is appreciated?
this is how the library works :
<DataTable
title="Movie List"
columns={columns}
data={completedProducts}
expandableRows
expandableRowsComponent={ExpandedComponent}
pagination
/>
the expandableRowsComponent props renders out what is shown on expanding in this case ExpandedComponent,which takes the data prop as a parameter
const ExpandedComponent =({ data }) => {
// i would like to show the index of the current expanded row here
});
};
how to i do it?
the row and columns work perfectlty and data is rendered out as expected
updated image with array data
I have extracted this data from a bigger api data as follows
specifically the bp_product_information array
Here is a sample for pulling an item off data to display in the row where the data has child records
import "./styles.css";
import DataTable from "react-data-table-component";
const columns = [
{
name: "Name",
selector: (row) => row.name
},
{
name: "Species",
selector: (row) => row.species
}
];
const data = [
{
id: 1,
name: "Fluffy",
species: "cat",
hobbies: ["cleaning", "meowing", "chasing mice"]
},
{
id: 2,
name: "Boomer",
species: "dog",
hobbies: ["barking", "chewing", "eating"]
}
];
export default function App() {
const ExpandedComponent = ({ data }) => {
return data && data.hobbies ? (
data.hobbies.map((item) => <div>{item}</div>)
) : (
<div>no data</div>
);
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<DataTable
title="Pet List"
columns={columns}
data={data}
expandableRows
expandableRowsComponent={ExpandedComponent}
pagination
/>
</div>
);
}
Here is a link to their Storybook with more examples.
https://jbetancur.github.io/react-data-table-component/?path=/story/expandable-basic--basic

using react-draft-wysiwyg converted to html

I am using react WYSIWYG for the first time in a custom email template. i need to draft template messages that will be sent as email body. from WYSIWYG editor, i can achive this. during the extraction of html from draft-js, i am unable to return jsx or html that will be rendered as body when the email is sent. before i send the email itself, i first tried rendering the value extracted from the editor, but istead, it renders stringified html, when i try using draft to markdown, this work but html formatting is lost, which is also what am not looking for. below is my code
import React, { useState } from "react";
import { Editor } from "react-draft-wysiwyg";
import { EditorState, convertToRaw } from "draft-js";
import "../../node_modules/react-draft-wysiwyg/dist/react-draft-wysiwyg.css";
import "./editor.css";
import draftToHtml from "draftjs-to-html";
import draftToMarkdown from 'draftjs-to-markdown';
const EditorBook = () => {
const [editorState, setEditorState] = useState(EditorState.createEmpty());
const text = draftToHtml(convertToRaw(editorState.getCurrentContent()))
return (
<div>
<Editor
editorState={editorState}
editorClassName="editor-class"
onEditorStateChange={setEditorState}
placeholder="enter text reminders ..."
mention={{
separator: " ",
trigger: "#",
suggestions: [
{ text: "APPLE", value: "apple", url: "apple" },
{ text: "BANANA", value: "banana", url: "banana" },
{ text: "CHERRY", value: "cherry", url: "cherry" },
{ text: "DURIAN", value: "durian", url: "durian" },
{ text: "EGGFRUIT", value: "eggfruit", url: "eggfruit" },
{ text: "FIG", value: "fig", url: "fig" },
{ text: "GRAPEFRUIT", value: "grapefruit", url: "grapefruit" },
{ text: "HONEYDEW", value: 'honeydew', url: "honeydew" },
],
}}
/>
<button
onClick={() =>
console.log(
draftToHtml(convertToRaw(editorState.getCurrentContent()))
)
}
>
console.log me
</button>
<div>
{text}
</div>
</div>
);
};
export default EditorBook;
when console loged, this is what appears to the console:
<p>here is sample text</p>
now this same text, is what is displayed to the frontend "as a string" yet i just want the text only to be displayed like so:
const text = draftToHtml(convertToRaw(editorState.getCurrentContent()))
when i do this in the react JSX,
<div>
{text}
</div>
i get this in the browser:
here is sample text
when i use the "draftToMarkdown" i get what i want, but formating is lost like this:
const honey = draftToMarkdown(convertToRaw(editorState.getCurrentContent()))
when console logged
<p>this is a sample text</p>
<p>hello every one. (this statement should be on the second line)</p>
result on the browser:
this is a sample text hello every one. (this statement should be on the second line)
I understand the the is an inline block element but i want it in a way that when the keyboard 'Enter' is press, and some text followed, it should appear as a newline in the browser. how can i achieve this ?

Gatsby fetching Wordpress Custom Post Types and create pages

I read the documentation and tried several tutorials, but I am stuck on fetching custom post types with GatsbyJS.
I tried several approaches, but none of them are working as expected. I always receive a 404.
This is a part of the snippet I am using, which works fine with pages and posts, but not with a custom post type.
The projects pages should be created under a project subfolder/path. Like: example.com/project/my-first-project
The part of the gatsby-node.js looks like that:
const createSinglePages = async ({ posts, gatsbyUtilities }) =>
Promise.all(
posts.map(({ previous, post, next }) =>
// createPage is an action passed to createPages
// See https://www.gatsbyjs.com/docs/actions#createPage for more info
gatsbyUtilities.actions.createPage({
// Use the WordPress uri as the Gatsby page path
// This is a good idea so that internal links and menus work 👍
path: post.uri,
// use the blog post template as the page component
component: path.resolve(
`./src/templates/${post.__typename.replace(`Wp`, ``)}.js`
),
// `context` is available in the template as a prop and
// as a variable in GraphQL.
context: {
// we need to add the post id here
// so our blog post template knows which blog post
// the current page is (when you open it in a browser)
id: post.id,
// We also use the next and previous id's to query them and add links!
previousPostId: previous ? previous.id : null,
nextPostId: next ? next.id : null,
},
})
)
);
The src/template/project.js file looks like this:
import React from "react";
import { Link, graphql } from "gatsby";
import Image from "gatsby-image";
import parse from "html-react-parser";
import Layout from "../components/Layout";
import Seo from "../components/Seo";
const ProjectTemplate = ({ data: { post } }) => {
const featuredImage = {
fluid: post.featuredImage?.node?.localFile?.childImageSharp?.fluid,
alt: post.featuredImage?.node?.alt || ``,
};
return (
<Layout>
<Seo title={post.title} description={post.excerpt} />
<article
className="blog-post"
itemScope
itemType="http://schema.org/Article"
>
<header>
<h1 itemProp="headline">{parse(post.title)}</h1>
<p>{post.date}</p>
{/* if we have a featured image for this post let's display it */}
{featuredImage?.fluid && (
<Image
fluid={featuredImage.fluid}
alt={featuredImage.alt}
style={{ marginBottom: 50 }}
/>
)}
</header>
{!!post.content && (
<section itemProp="articleBody">{parse(post.content)}</section>
)}
</article>
</Layout>
);
};
export default ProjectTemplate;
export const pageQuery = graphql`
query ProjectById(
# these variables are passed in via createPage.pageContext in gatsby-node.js
$id: String!
) {
# selecting the current post by id
post: wpProject(id: { eq: $id }) {
id
content
title
date(formatString: "MMMM DD, YYYY")
featuredImage {
node {
altText
localFile {
childImageSharp {
fluid(maxWidth: 1000, quality: 100) {
...GatsbyImageSharpFluid_tracedSVG
}
}
}
}
}
}
}
`;
Is the Gatsby API creating a subfolder automatically, or do I need to define that somewhere for each post type?
Any help appreciated!
You define the "subfolder" under the path field in:
gatsbyUtilities.actions.createPage({
path: post.uri,
component: path.resolve(
`./src/templates/${post.__typename.replace(`Wp`, ``)}.js`
),
context: {
id: post.id,
previousPostId: previous ? previous.id : null,
nextPostId: next ? next.id : null,
},
})
You just need to do something like:
path: `projects/${post.id}`
Check the slashes and trailing slashes here.
You cna replace projects for your dynamic project type if you fetch that information for a more automatic approach (assuming it's post.__typename).
In order to use Custom Post Types with WPGraphQL, you must configure the Post Type to show_in_graphql using the following field:
show_in_graphql : true
While Registering a new Custom Post Type
This is an example of registering a new "docs" post_type and enabling GraphQL Support.
add_action( 'init', function() {
register_post_type( 'docs', [
'show_ui' => true,
'labels' => [
//#see https://developer.wordpress.org/themes/functionality/internationalization/
'menu_name' => __( 'Docs', 'your-textdomain' ),
],
'show_in_graphql' => true,
'hierarchical' => true,
'graphql_single_name' => 'document',
'graphql_plural_name' => 'documents',
] );
} );

React img src from object

How to exract image source from object for img src ?
I have constant defined like this:
const DUMMY_DATA = [
{
name: "Frozen",
image: "../../assets/categories/Frozen.png",
categories: [],
},
{
name: "Baby Care",
image: "../../assets/categories/BabyCare.png",
categories: [],
},
{
name: "Bakery",
image: "../../assets/categories/Bakery.png",
categories: [],
},
]
I want to map over the array and render a list of each object like the below:
const categories = DUMMY_DATA.map((item) => {
return (
<li key={item.name} className={classes.category}>
<img src={item.image} alt="category" />
<span>{item.name}</span>
</li>
);
});
return (
<nav>
<ul className={classes.navBox}>{categories}</ul>
</nav>
);
unfortunately it doesn't work
I would suggest importing the images instead of using paths.
import image1 from '../path/image-1.png'
import image2 from '../path/image-2.png'
import image3 from '../path/image-3.png'
const DUMMY_DATA = [
{
...
image: image1,
},
{
...
image: image2,
},
{
...
image: image2,
}
]
The reason for this is that when your React application is compiled, the relative paths to access those images will be different.
If you really want to use paths instead of importing, I'd suggest using absolute paths but it's not recommended.
I tried to replicate your code in CodeSandBox and it seems everything is syntactically correct. Problem seems to exist in the image paths within your dummy data.

Images from array in an object not displaying using React.js

I am having problems rendering images from array in carousel. Here is what I am doing
This is my object that has the array I want to map
export const data = [
{
id: 1,
name: "Some name ",
desc: "Some desc",
img: ("../../images/secondary/placeholder.jpg"),
},]
export const projectsData = {
1: {
title: "Some title 2",
subtitle: 'Some subtitle 2',
description: 'Lorem 2 ',
images: [
("../../images/photos2/2osnova1.png"),
("../../images/photos2/2osnova2.png"),
("../../images/photos2/2osnova3.png"),
("../../images/photos2/2presek1.png"),
("../../images/photos2/2presek2.png"),
("../../images/photos2/2pogled1.png"),
("../../images/photos2/2pogled2.png"),
("../../images/photos2/2pogled3.png")
]
}
}
here is the component
import React, { Component } from "react";
import Carousel from "react-bootstrap/Carousel";
import ControlledCarousel from "./ControlledCarousel";
import { useParams } from "react-router-dom";
import { projectsData } from "./dataapp";
export default function Appartments() {
let { id } = useParams();
let curProject = projectsData[id];
return (
<div>
<div className="left-wrapper">
<h1>{curProject.title}</h1>
<h2>{curProject.subtitle}</h2>
<p>{curProject.description}</p>
</div>
<div className="right-wrapper">
<ControlledCarousel images={curProject.images} />
</div>
</div>
);
}
and here is the carousel I want to display them in
import React, { Component, useState } from "react";
import Carousel from "react-bootstrap/Carousel";
function ControlledCarousel(images) {
const [index, setIndex] = useState(0);
console.log(images.images);
const handleSelect = (selectedIndex, e) => {
setIndex(selectedIndex);
};
return (
<div>
{images.images.map((projectsDataApp, index) => {
return (
<div>
<Carousel activeIndex={index} onSelect={handleSelect} indicators={false}>
<Carousel.Item interval={1000000} >
<img src={`${projectsDataApp.images}`} alt="" className="imgdummy" />
</Carousel.Item>
</Carousel>
</div>
);
})}
</div>
);
}
I tried placing the images both in src and public, also tried importing them from Imgur and Google Images, but nothing works. And there is no error message and when I console.log the images, it shows the array.
so there is many problems it seems like :
you are putting a list inside the src attribute which is wrong
additionally it seems like you are trying to access images the aren't stored in the 'public' directory which isn't visible to the browser... in case of storing images in the 'src' dir you should import them first and use the values imported as the src file...
to post an image in a file you should import it, or access a file that exist in the public directory :
for example :
import imgSrc from '../../images/photos2/2osnova1.png"'
function Image(){
return <img src={imgSrc}/>
}
for your case (if you did put it in public) :
try to render many components for each img src:
instead of:
<Carousel.Item interval={1000000} >
<img src={`${projectsDataApp.images}`} alt="" className="imgdummy" />
</Carousel.Item>
do:
{projectsDataApp.images.map(imageSrc=><Carousel.Item interval={1000000} >
<img src={`${imageSrc}`} alt="" className="imgdummy" />
</Carousel.Item>)}
There are a couple of errors with your code. First, the way you're handling props and there are images of images everywhere. I cleaned it up a bit and renamed a few variables to make more sense. Your img's src were undefined that's why you couldn't display the images.
I checked the code with images from unsplash. The code below works fine. If you want to host the images from the public folder, make sure the path is correct. If there is an images folder inside the public folder, your path will look like this: /images/something.jpg.
You also don't want to have two variables named index accessible from the same scope. I also changed them.
Another error was how you wanted to include the images inside the Carousel. You should have one Carousel component, and many Carousel.Item components with the images inside. So you need to map over the images array inside the Carousel component. Also, in React, if you iterate over an array, you need to add a key prop. In this case it's <Carousel.Item key={i} ....
const projectsData = {
1: {
title: "Some title 2",
subtitle: "Some subtitle 2",
description: "Lorem 2 ",
images: [
"https://source.unsplash.com/WLUHO9A_xik/800x450",
"https://source.unsplash.com/PLsEI2ZOrGA/800x450",
"https://source.unsplash.com/L8o2sIPSOnc/800x450",
"https://source.unsplash.com/6Pg2ms04ouM/800x450",
"https://source.unsplash.com/7ZWVnVSaafY/800x450",
"https://source.unsplash.com/O6RPWul11XI/800x450",
"https://source.unsplash.com/LcnNWTCkzUU/800x450"
]
}
};
function ControlledCarousel({ images }) {
const [index, setIndex] = useState(0);
const handleSelect = (selectedIndex, e) => {
setIndex(selectedIndex);
};
return (
<Carousel activeIndex={index} onSelect={handleSelect} indicators={false}>
{images.map((image, i) => (
<Carousel.Item key={i} interval={1000}>
<img src={image} alt="" className="imgdummy" />
</Carousel.Item>
))}
</Carousel>
);
}
function App() {
let { id } = useParams();
let curProject = projectsData[id];
return (
<div>
<div className="left-wrapper">
<h1>{curProject.title}</h1>
<h2>{curProject.subtitle}</h2>
<p>{curProject.description}</p>
</div>
<div className="right-wrapper">
<ControlledCarousel images={curProject.images} />
</div>
</div>
);
}
There's a simple way to do this.
const Images = [
{
id: 0,
image: require("../../Assets/Images/Icons/atom.png").default,
},
];
export default Images;
Replace your own image/icon at location from src folder ✌
I found the problem in my array it should be like this
1: {
title: "Some title 2",
subtitle: 'Some subtitle 2',
description: 'Lorem 2 ',
images: [
{
image: "../../images/photos2/2osnova1.png"
},
{
image: "../../images/photos2/2osnova1.png"
}, {
image: "../../images/photos2/2osnova1.png"
},
]
}
}
instead of my previous
export const projectsData = {
1: {
title: "Some title 2",
subtitle: 'Some subtitle 2',
description: 'Lorem 2 ',
images: [
("../../images/photos2/2osnova1.png"),
("../../images/photos2/2osnova2.png"),
("../../images/photos2/2osnova3.png"),
("../../images/photos2/2presek1.png"),
("../../images/photos2/2presek2.png"),
("../../images/photos2/2pogled1.png"),
("../../images/photos2/2pogled2.png"),
("../../images/photos2/2pogled3.png")
]
}
}

Resources