How to make a image clickable using document.getElementById in reactjs - javascript

I am currently using the Twitch API, where I have created a file that renders the game cover image by searching. I want the user to be able to click the game image, which will redirect them to their proper Twitch Links
Search Response
My code for the game image rendering looks like this:
render() {
const { game } = this.props
return (
<div className="GameDetails">
<img src={this.formatImageUrl(game.box_art_url)} alt="" />
<p>{game.name} </p>
<p>ID: {game.id}</p>
</div>
)
}
}
export default GameImage
I tried out:
render() {
const { game } = this.props
return (
<div className="GameDetails">
<img src={this.formatImageUrl(game.box_art_url)} alt="" onClick${"https://www.twitch.tv/directory/game/${document.getElementById("SearchName").value}"}/>
<p>{game.name} </p>
<p>ID: {game.id}</p>
</div>
)
}
}
export default GameImage
Which gives me an error.
The "SearchName" value is what the user types in the search bar for the game, therefore I want to send them to the respectable twitch pages when clicked.

Of course you will receive an error, because firstly you've misspelled $ with = and secondly, onClick prop expects a function which will handle the action after clicking the image.
Suggested approach:
handleClick = () => {
// logic when user clicks on image
// https://www.twitch.tv/directory/game/${document.getElementById("SearchName").value}
}
render() {
const { game } = this.props
return (
<div className="GameDetails">
<img src={this.formatImageUrl(game.box_art_url)} alt="" onClick={this.handleClick} />
<p>{game.name} </p>
<p>ID: {game.id}</p>
</div>
)
}
export default GameImage
Edit: It's kinda difficult to understand what you really want to achieve, however if you want that img to work as a link, you should consider using a element instead. Just wrap your img tag as well as p into a.
render() {
const { game} = this.props
const link = `https://www.twitch.tv/directory/game/${document.getElementById("SearchName").value}`;
return (
<div className="GameDetails">
<a href={link}>
<img src={this.formatImageUrl(game.box_art_url)} alt="" onClick={this.handleClick} />
<p>{game.name} </p>
<p>ID: {game.id}</p>
</a>
</div>
)
}

If all you want to do is go to another site by clicking on the image simply wrap it in an HTML anchor with the url as the href attribute. Hover over the images (don't click on them) to see the URL in the browser status bar.
function App({ data }) {
return data.map(game => <Details game={game} />);
}
function Details({ game }) {
return (
<div className="gameDetails">
<a href={game.twitch_url}>
<img src={game.box_art_url} />
</a>
</div>
);
}
const data = [
{ id: 1, twitch_url: 'http://game1.com', box_art_url: 'https://dummyimage.com/100x100/000/fff' },
{ id: 2, twitch_url: 'http://game2.com', box_art_url: 'https://dummyimage.com/100x100/555/fff' },
];
ReactDOM.render(
<App data={data} />,
document.getElementById('container')
);
.gameDetails {
display: inline-block;
padding: 0.3em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="container"></div>

Related

Reactjs Passing a component in other component

I'm trying to pass a custom component into another component, the parent component should works like a wrapper putting the custom component in a special section at the end, but I'm having this error Uncaught Error: Objects are not valid as a React child (found: object with keys {...}). If you meant to render a collection of children, use an array instead. I read a lot of posts but those solutions doesn't work, here the most similar question but doesn't work for me.
Passing an icon component to another component in ReactJS
Wrapper
function Wrapper(props: Props) {
const { title, icon, content } = props
return (
<div className={ Styles.wrapperContainer }>
<h1>{ title }</h1>
{
icon &&
<img src={`/assets/images/${icon || 'notification-bell-icon.svg'}`} alt="" />
}
{ content } // <-
</div>
)
}
calling the Wrapper component
<Wrapper
title="My tittle"
content={<Button text="press me" type={ButtonTypes.DEFAULT} />}
/>
Button Component
function Button(props: Props){
const { type, text, icon } = props
return (
<span className={`${Styles.buttonContainer} ${Styles[type]}`}>
{
type === ButtonTypes.ICON_BUTTON ?
<img src={`/assets/images/${icon}`} alt=""/> :
(
icon ?
<><LineIcon icon={icon}/>{ text }</> :
{ text }
)
}
</span>
)
}
Okay guys, thanks for your help, I found a problem with the <Button /> Component, I changed like this n' it works, adding <></> tag over the { text } works too.
Thanks
function Button(props: Props){
const { type, text, icon } = props
return (
<span className={`${Styles.buttonContainer} ${Styles[type]}`}>
{
type === ButtonTypes.ICON_BUTTON ?
<img src={`/assets/images/${icon}`} alt=""/> :
(
<>
{ icon && <LineIcon icon={icon}/> }
{ text }
</>
)
}
</span>
)
}

Search bar stopping props from changing

On my site, the <ArticleList> is supposed to update when one navigates between columns. This works when you go from the home page to a column, or from an article to a column. But if you go from column to column, it doesn't work. The page doesn't update at all, but the url changes. The links to each column stay the same, as they are part of the <Layout> component, which every page has.
Edit
I figured out now that I can just use <a> and omit <Link> entirely, but this would slow down the page navigation.
Edit 2
This is part of my <Layout> component where I render the links to the columns:
<nav className={layout.columnContainer}>
{columns.map(({ id, name }) =>
this.props.currentColumn ? (
<a key={id} href={`/columns/${name}`}>
{name}
</a>
) : (
<Link key={id} href="/columns/[name]" as={`/columns/${name}`}>
<a>{name}</a>
</Link>
),
)}
</nav>
Edit 3
My minimal reproducible example is on GitHub, and I get the same unexpected results.
Edit 4
I found that the reason it wasn't working was I implemented a search bar that put the children prop in a state and modified this.
Constructor:
constructor(props) {
super(props);
this.searchArticlesKeyType = this.searchArticlesKeyType.bind(this);
this.state = {displayedMain: props.children};
}
Inside the render method are the column links (nav) and the problematic search input element.
<nav className={layout.columnContainer}>
{
columns.map(({id, name}) => (
<Link key={id} href="/columns/[name]" as={`/columns/${name}`}><a>{name}</a></Link>
))
}
</nav>
<div className={layout.search}>
<input type="search" name="q" onKeyUp={this.searchArticlesKeyType} />
</div>
async searchArticlesKeyType(e) {
// Some code
this.setState({
displayedMain: <ArticleList articles={JSON.stringify(filteredArticles)}/>
// More code
});
}
I think your main issue here is the way you're implementing the search feature, you don't want to store components in state instead you need to pass the search text to the articlelist component and do the filtering there.
There are several ways to implement communication between 2 unrelated components, it could be via context, redux, or even make a portal in the layout to render the seach input from the column component, but in this case I think the best option is to store the search text in the url:
First make the input event update the url using next/router, your layout will look like this:
import { useRouter } from 'next/router'
...
function Layout(props) {
const {columns} = props;
const { push, asPath, query } = useRouter()
const searchArticlesKeyType = (e) => {
const q = e.target.value;
const [url] = asPath.split('?');
push(`${url}?q=${q}`, undefined, { shallow: true });
}
return (
<div>
...
<div>
<input type="search" name="q" defaultValue={query.q} onKeyUp={searchArticlesKeyType} />
</div>
...
</div>
)
}
And then you do the filtering in articlelist component
import Link from "next/link";
import { useRouter } from 'next/router'
export default function ArticleList(props) {
const { query } = useRouter();
const q = query.q || "";
const filteredArticles = props.articles.filter(
(item) => item.title.includes(q) || item.body.includes(q)
);
return (
<ul className="grid">
{filteredArticles.map((item) => (
<div key={item.id}>
<Link
key={item.id}
href="/articles/[title]"
as={`/articles/${item.title}`}
>
<a>
<p>
<strong>{item.title}</strong>
</p>
<p>{item.body.substring(0, 100)}</p>
</a>
</Link>
</div>
))}
</ul>
);
}

ReactJS Replace Broken Image with a Different Element

Is it possible to replace a broken image with a separate element entirely in reactJS?
My current code uses the onError() function to set a broken image's src
<img src={user.avatar} onError={e => e.target.src = '/static/image.png'} />
What I'd like to do is replace it with some text instead. Something like:
<img src={user.avatar} onError={() => this.replace() } />
replace function(){
return <div class='some-class'>Image not found</div> // Would replace the image element
}
Note* The user.avatar property will always be defined, and I'm not looking to use the alt attribute
Here's how I might do it for a simple image component. We just change what we return if there was an error.
export function UserImageComponent({user}){
const [isError,setIsError] = useState(false);
if(isError){
return <div class='some-class'>Image not found</div> // Would replace the image element
}
return <img src={user.avatar} onError={() => this.setIsError(true) } />
}
You can use this strategy:
class Image extends React.Component {
constructor() {
super();
this.state = {};
this.fallback = () => {
this.setState({ failed: true });
};
}
render() {
if (this.state.failed) {
return <div classname='some-class'>Image not found</div>;
} else {
return <img src={this.props.src} onError={this.fallback} />;
}
}
}
const brokenUrl = 'url.png';
const url = 'https://picsum.photos/536/354';
const app = (
<div>
<h2>Broken image:</h2>
<Image src={brokenUrl} />
<h2>Working image:</h2>
<Image src={url} />
</div>);
ReactDOM.render(app, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>

ReactJS - Java Script: Image is not properly showing inside a <div>

I am building a boat visualizer using AISHub and the external database Contentful.
All the vessels I am interested are injected into a table. When I click on the table I locate the marker (vessel) on the map and the image of that vessel pops up on a sidebar on the right of the map as shown below:
The problem I have is that I should also visualize the image of the vessel, but unfortunately I only visualize a weird icon as shown below:
Below the code:
class Sidebar extends React.Component {
state = {
ships: []
};
async componentDidMount() {
let response = await Client.getEntries({
content_type: 'cashmanCards'
});
const ships = response.items.map((item) => {
const { name, slug, type, company, description, images, companylogo } = item.fields;
return {
name,
slug,
type,
company,
description,
images,
companylogo
};
});
this.setState({
ships
});
}
getFilteredShips = () => {
if (!this.props.activeShip) {
return this.state.ships;
}
return this.state.ships.filter((ship) => this.props.activeShip.name.toLowerCase() === ship.name.toLowerCase());
};
render() {
return (
<div className="map-sidebar">
{this.props.activeShipTypes}
<pre>
{this.getFilteredShips().map((ship) => {
console.log(ship);
return (
<Card className="mb-2">
<CardImg />
<CardBody>
<div className="row">
{/* <div className="column"> */}
<img className="image-sizing-primary" src={ship.companylogo} alt="shipImage" />
</div>
<div>
<img className="image-sizing-secondary" src={ship.images} alt="shipImage" />
</div>
<CardTitle>
<h3 className="thick">{ship.name}</h3>
</CardTitle>
<CardSubtitle>{ship.type}</CardSubtitle>
<CardText>
<br />
<h6>Project Details</h6>
<p>For a description of the project view the specification included</p>
</CardText>
<div class="btn-toolbar">
<SpecsButton />
<Link to="/vessels/Atchafalaya" className="btn btn-primary">
Go to vessel
</Link>
</div>
</CardBody>
</Card>
);
})}
</pre>
</div>
);
}
}
export default Sidebar;
What I have done so far:
1) I console.log() the problem that could be the cause of that weird icon and the result (the value) of the command was a strange path. I can confirm that the command is correct. Also I should say that those images are currently held by an external container called Contentful. Below the path after console log:
Am I missing something from the path?
I am not sure how to move on as all other checks seems correct and this one is the only one that is ringing some bells to me.
Thanks for pointing in the right direction for solving this issue.
#Emanuele , could you please try this instead ?
src = {ship.images.fields.file.url}

Passing div data from map in other component

I am creating Test component using Carousel component.
In Carousel component I am passing div with data from props.But I want to pass img src from testData props as follows.
export default class Test extends Component {
render() {
const { testData } = this.props;
return (
<div>
<Carousel>
{
testData.length && testData.map((a) => (
<div><img src=
{a.link} />
</div>
)
)
}
</Carousel>
</div>
);
}
}
testData = [{"link":"/test1.jpg"},
{"link":"/test2.jpg"},
{"link":"/test3.jpg"}
]
When I do this as follows then it is working fine.
<div> <img src="/test1.jpg" /></div>
<div> <img src="/test2.jpg" /></div>
<div> <img src="/test3.jpg" /></div>
What I am doing wrong using testData.
Regular JavaScript comments are not allowed in JSX:
//<div> <img src="/test1.jpg" /></div>
//<div> <img src="/test2.jpg" /></div>
//<div> <img src="/test3.jpg" /></div>
To comment in JSX you must wrap in { }.
{ /*<div> <img src="/test1.jpg" /></div>
<div> <img src="/test2.jpg" /></div>
<div> <img src="/test3.jpg" /></div>*/ }
import React, { Component } from 'react'
import {Carousel} from 'react-bootstrap'
export default class Test extends Component {
render() {
const testData = [{"link":"/test1.jpg"},
{"link":"/test2.jpg"},
{"link":"/test3.jpg"}]
return (
<Carousel>
{testData.length && testData.map((a) =>
(<div>
<img src={a.link} />
</div>))}
</Carousel>
);
}
}
This piece of code is working fine, So I think the problem lies in how you are passing testData through props.
If you could provide the code where you are passing the testData as props a solution can be found out.
I finally got the issue.
In first case when I am using static data as
testData = [{"link":"/test1.jpg"},
{"link":"/test2.jpg"},
{"link":"/test3.jpg"}
]
It will get showed to page every time component rendered.
But in second case
const { testData } = this.props;
testData is set by API call.So it will not get fetched when component rendered first.To resolve this issue I did this
if (!caurosalData.length) {
return null;
}
Now it is working fine

Categories