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}
Related
I have a page in left side div items like item's image,title,its details, address ex. And on the right side I have a map (Leaflet Map) showing markers of address which taking from all of these left side items. Now I want to display marker location on map when mouse hover to the left information with its address. Shortly you can see live example in airbnb.com
I am using React Leaflet for map and React as you see. But data doesn't fetch from db yet, it is dummy data. Address is defined with lat and lng coords
Bikes.js
import { BIKES, BikeTypes, BikeSize } from '../../data'
const Bikes = () => {
return <div className="bikes-page">
<div>
<hr className="bike-bottom-line" />
<BikesList items={BIKES} />
</div>
<div className="bikes-map">
<MapContainer style={{ height: '50rem' }} coords={BIKES} mapZoom={9} />
</div>
</div>
}
export default Bikes
MapContainer.js (Component made with react-leaflet)
const MapContainer = (props) => {
const DEFAULT_LATITUDE = 40.500;
const DEFUALT_LANGITUDE = 49.500;
return (
<Map style={props.mapStyle} center={[DEFAULT_LATITUDE, DEFUALT_LANGITUDE]} zoom={props.mapZoom || 7} >
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution='© OpenStreetMap contributors'
/>
{
props.coords ?
props.coords.map(mark => {
return <Marker
position={[mark.location.lat, mark.location.lng]}
icon={biker}
key={mark.id} >
<Popup className="popup">
<Link to={`/b/${mark.id}`} className="popup-container">
<img src={mark.images[0]} alt={mark.title} />
<div className="popup-container__title">
<h3> {mark.title} </h3>
{mark.size}" · {mark.price.first}azn/s
</div>
</Link>
</Popup>
</Marker>
}) : null
}
</Map >
)
}
export default MapContainer
BikesList.js (left side - List)
const BikesList = (props) => {
if (props.items.length === 0) {
return <h2>Elan tapılmadı</h2>
}
return (
<ul className="bikes-list">
{props.items.map((bike) => (
<BikeItem
key={bike.id}
id={bike.id}
image={bike.images[0]}
title={bike.title}
city={bike.city}
size={bike.size}
price={bike.price.first}
creator={bike.creator}
maxLength={24}
/>
))}
</ul>
)
}
export default BikesList
I found a solution myself. It was easy :) Here it is:
First , in the Bikes.js file, I made an isHovered state and gives it null as a default. Then made handleHoverMarker(id) function with id which will get it from specific hovered item's id. In function I changed setIsHovered's value to this sent id. So then I shared isHovered and handleHoverMarker with props.
Bikes.js
const [isHovered, setIsHovered] = useState(null)
const handleHoverMarker = (id) => {
setIsHovered(id)
}
<div>
<BikesList handleHoverMarker={handleHoverMarker} items={filteredDataState} />
</div>
<div className="bikes-map">
<MapContainer isHovered={isHovered} style={{ height: '50rem' }} coords={BIKES} mapZoom={9} />
</div>
Second, handleHoverMarker props sent to the BikeItem component which represents each of items in list.
BikesList.js
<ul className="bikes-list">
{props.items.map((bike) => (
<BikeItem
key={bike.id}
id={bike.id}
image={bike.images[0]}
title={bike.title}
city={bike.city}
size={bike.size}
price={bike.price.first}
creator={bike.creator}
maxLength={24}
handleHoverMarker={props.handleHoverMarker}
/>
))}
</ul>
In the BikeItem.js set mouseHover events and pass the id with handleHoverMarker(id) function. So we will know which item hovered with id.
Note: I didn't write all codes in BikeItem.js only took the necessary part
BikeItem.js
<li onMouseEnter={()=> props.handleHoverMarker(props.id):null} onMouseLeave={()=>props.handleHoverMarker(null):null} key={props.id}>
So here we come back to the MapContainer which will show hovered item's location
MapContainer.js
{props.coords ?
props.coords.map(mark => {
return <Marker
position={[mark.location.lat, mark.location.lng]}
icon={biker}
opacity={props.isHovered === mark.id ? .7 :1}
key={mark.id} >
<Popup className="popup">
<Link to={`/b/${mark.id}`} className="popup container">
<div className="popup-container__title">
<h3> {mark.title}</h3>
</div>
</Link>
</Popup>
</Marker>
}) : null}
Here I changed opacity value conditionally with props.isHovered which we sent from Bikes.js file.
Note: I couldn't changed marker's style because I didn't found a way from documentaton of leaflet map. So logic is the same, you can do it with Google Maps too. Enjoy good luck :)
I am trying to download a .pdf document from the external database Contentful using an HTML link on a user interface.
The problem I have is that not always some of the fields inside Contentful require a pdf document and when there is no document to download the filed remains empty and the developer-tools throws an error. Because of that, the compilation stops and I can't sudo npm start.
The problem: How can I write a loop that skips empty fields in a database, in this case a Contentful beckend?
The file path is contained in: ship.projectnotes.fields.file.url as shown below:
import Client from '../Contentful';
class Sidebar extends React.Component {
state = {
ships: []
};
async componentDidMount() {
let response = await Client.getEntries({
content_type: 'cards'
});
const ships = response.items.map((item) => {
const {
name,
slug,
projectnotes
} = item.fields;
return {
name,
slug,
projectnotes
};
});
this.setState({
ships
});
}
getFilteredShips = () => {
// operations .......
};
render() {
return (
<div className="map-sidebar">
{this.props.activeShipTypes}
<pre>
{this.getFilteredShips().map((ship) => {
console.log(ship);
return (
<Card className="mb-2">
<CardImg />
<CardBody>
<CardTitle>
<h3 className="thick">{ship.name}</h3>
</CardTitle>
<Row style={{ marginTop: '20px' }}>
<div className="buttoncontainer">
<div className="btn btn-cards">
<a className="buttonLink" ship.projectnotes.fields.file.url} download>
Project Notes
</a>
</div>
</div>
</Row>
</CardBody>
</Card>
);
})}
</pre>
</div>
);
}
}
export default Sidebar;
I can confirm that I am reading correctly the name of the field from Contentful:
What I have done so far:
1) I was able to implement the link to the document but after I started using the external container Contentful, the pdf is not downloadable, contrarily to what I was hoping. The problem is that there is an empty field as unhandled problem and don't know how to take care of that.
Thanks for pointing in the right direction.
You can use the .hasOwnProperty('fieldName') to safely check to see if an object has the property you require. So in your case you should be able to add a simple if statement to check to see if the field 'file' exits in your loop.
see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty
import Client from '../Contentful';
class Sidebar extends React.Component {
state = {
ships: []
};
async componentDidMount() {
let response = await Client.getEntries({
content_type: 'cards'
});
const ships = response.items.map((item) => {
const {
name,
slug,
projectnotes
} = item.fields;
return {
name,
slug,
projectnotes
};
});
this.setState({
ships
});
}
getFilteredShips = () => {
// operations .......
};
render() {
return (
<div className="map-sidebar">
{this.props.activeShipTypes}
<pre>
{this.getFilteredShips().map((ship) => {
console.log(ship);
// lets add a check here you can change it to suit
if(ship.projectnotes.fields.hasOwnProperty('file')) {
return (
<Card className="mb-2">
<CardImg />
<CardBody>
<CardTitle>
<h3 className="thick">{ship.name}</h3>
</CardTitle>
<Row style={{ marginTop: '20px' }}>
<div className="buttoncontainer">
<div className="btn btn-cards">
<a className="buttonLink" ship.projectnotes.fields.file.url} download>
Project Notes
</a>
</div>
</div>
</Row>
</CardBody>
</Card>
);
} else {
// return no render or what ever here
return null
}
})}
</pre>
</div>
);
}
}
export default Sidebar;
I'm a beginner developer and I work with Reactjs.
I'm doing a project where there will be a gallery of photos that I brought
from a flickr api service.
Each image will have two buttons:
1.Clone: clicking the clone button should duplicate the image.
2.Expand: clicking an image should display this image in a larger view
How do I clone the image in a different way than I did? (more effective)
How do I large the image without using the 'react-modal'?
I have two components- One of the gallery and the other of the pictures.
my Gallery.js:
handleClone = image => {
this.state.images.push(image);
this.setState({ images: this.state.images });
};
render() {
return (
<div className="gallery-root">
{this.state.images.map((dto, index) => {
return <Image key={'image-' + index} dto={dto} galleryWidth=
{this.state.galleryWidth}
handleClone={image => this.handleClone(image)}
/>;
})}
</div>
);
}
my Image.js:
handleClone() {
this.props.handleClone(this.props.dto); // send to the Gallery component
the image to clone.
}
render() {
return (
<div>
<FontAwesome className="image-icon" name="clone" title="clone"
onClick={()=> this.handleClone()}/>
<FontAwesome className="image-icon" name="filter" title="filter"
onClick={()=> this.filterChange()}/>
<FontAwesome className="image-icon" name="expand" title="expand" />
</div>
</div>
);
}
Thanks :)
For the clone purposes.
handleClone = image => {
const imagesCopy = [...this.state.images]; //creates a copy of the images array which is stored in your component.
imagesCopy.push(image);
//this.state.images.push(image); this way will mutate the state directly which is a mistake.
this.setState({ images: imagesCopy });
};
About the react-modal thing, I don't see anything related to that in the question post, can you please share out the related code?
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>
This is pretty complicated to explain.
I am getting a couple of Icons from a component library as follows:
import { Icons } frommy-component-library';`
Let say I've got 3 Icons in there called IconPlus, IconMinus and IconEquals.
I can easily display the IconEquals along with a description prop as follows:
const IconContainer = ({ description ) => (
<div>
{description}
<Icons.IconEquals />
</div>
)
This works nicely. Now I'm trying to implement a template where I could pass another prop icon to this container which would display the corresponding icon.
Eg. if icon is IconPlus
Then it should render the following:
<div>
{description}
<Icons.IconEquals />
</div>
How do I implement my JSX to do that?
This is basically what I've got:
import { Icons } from 'my-component-library'
const IconContainer = ({ description, icon }) => (
<div>
{description}
<Icons.{icon} /> // <---- Obviously that doesn't work
// ^^^^ But I need something like this
</div>
);
Is it possible to do this?
You can use like this :
<Icons[icon] />