Dynamically create dropdown menu options from array with react-bootstrap - javascript

I'm building a drupal based e-commerce site right now and got stuck. Still new to react and coding in general, but trying to learn. So I've got all my data pulled in, using redux and rest api, and I'm getting my products, variations and attributes. The product page is setting a specific product based on url, and now I need to be able to select the different attributes via a dropdown menu. Currently I have a place holder dropdown that matches the one shown in react-bootstrap documentation. However, I need to be placing options in that dropdown based off of my array holding the attributes.
I'm sure it's simple but I've been searching around and haven't found an answer yet that works. Hopefully you guys can help.
As you look through the code, keep in mind that sizes = [] is the array I'm looking to place data from as the selectable options in the dropdown.
Here's the product page:
import React, { Component} from 'react';
import '../../css/Home.css';
import MenuBar from "../sub-components/MenuBar";
import LeftMenuBar from "../sub-components/LeftMenuBar";
import "../../css/ProductPage.css"
import WomensWear from "../../media/WomensWear.jpg"
import {
Dropdown,
DropdownToggle,
DropdownMenu,
DropdownItem } from 'reactstrap';
class ProductPage extends Component {
constructor(props) {
super(props);
this.toggle = this.toggle.bind(this);
this.state = {
dropdownOpen: false
};
}
toggle() {
this.setState(prevState => ({
dropdownOpen: !prevState.dropdownOpen
}));
}
getProduct() {
let product = null;
let sizes = [];
if (this.props.products && this.props.products.items.length) {
product = this.props.products.items.find(o => o.path[0].alias === this.props.router.match.url);
if (product && this.props.variations && this.props.attributes) {
product.something = [];
for (let i = 0; i < product.variations.length; i++) {
let varid = product.variations[i].target_id;
let variation = this.props.variations.items.find(o => o.variation_id[0].value === varid);
variation.size = this.props.attributes.items.find(o => o.attribute_value_id[0].value === variation.attribute_size[0].target_id);
sizes.push({value: variation.size.attribute_value_id[0].value, name: variation.size.name[0].value});
product.something.push(variation);
console.log(sizes);
}
}
}
return product;
}
render() {
let style = {
height: this.props.height - 56,
};
let product = this.getProduct();
let body = product && product.body.length ? product.body[0].value : null;
return (
<div className="App" id="default">
<div className='MenuBar'>
<MenuBar/>
</div>
<div>
<div style={style} className="ProductPage row no-gutters">
<div className="col-xs-3 col-md-3">
<LeftMenuBar/>
</div>
<div className="outer col-xs-4 col-md-4">
<div>
<div id="ProductPlacement">
<img src={WomensWear} alt=""/>
<div id="alternate-pics">
<div id="alt-pic">
</div>
<div id="alt-pic">
</div>
<div id="alt-pic">
</div>
</div>
</div>
</div>
</div>
<div className="col-xs-5 col-md-5">
<div id="ImagePlacement">
<div className="ProductTitle">
<h1>First Product</h1>
</div>
<hr/>
<div className="ProductDescription">
<div dangerouslySetInnerHTML={{__html: body}} />
</div>
<div id="options">
<div id="color">
</div>
<div id="color2">
</div>
<div id="color3">
</div>
</div>
<div id="options">
<div>
<Dropdown isOpen={this.state.dropdownOpen} toggle={this.toggle}>
<DropdownToggle caret id="size-dropdown">
Size
</DropdownToggle>
<DropdownMenu>
<DropdownItem>1</DropdownItem>
<DropdownItem>3</DropdownItem>
<DropdownItem>5</DropdownItem>
</DropdownMenu>
</Dropdown>
<div className="AddToCart">
<button className="AddToCart">Add To Cart</button>
<button className="Price">$34.99</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default ProductPage;

Neat thing about React is that you can use regular JS.
<Dropdown isOpen={this.state.dropdownOpen} toggle={this.toggle}>
<DropdownToggle caret id="size-dropdown">
Size
</DropdownToggle>
<DropdownMenu>
{sizes.map(size => (
<DropdownItem>{size}</DropdownItem>
))}
</DropdownMenu>
</Dropdown>
Sidenote: select seems to be more suitable element for this but that wasn't your question.

Related

Show post content in the same page ReactJS

i'm creating a blog. in my index.js i have a left sidebar that shows the article links.
What I'm trying to do is when I click on the link the post content should be shown in the right sidebar of my index.js
At the moment it's been opened in a new page.
index.js
const IndexPage = ({
data: {
allMarkdownRemark: { edges },
},
}) => {
const PostData = edges[0]
const Posts = edges
.filter(edge => !!edge.node.frontmatter.date) // You can filter your posts based on some criteria
.map(edge => <PostLink key={edge.node.id} post={edge.node} />)
return (
<div className='html-container'>
<div className='main-container'>
<div className='row'>
<div className='left-sidebar'>
<div className='logo'>
<p>logo</p>
</div>
<div className='menu'>
{Posts}
</div>
<div className='social'>
<img src={twitch} />
<img src={discord} />
<img src={twitter} />
<img src={email} />
</div>
</div>
<div className='right-sidebar'>
</div>
</div>
</div>
</div>
)
}
post-link.js
import React from "react"
import { Link } from "gatsby"
const PostLink = ({ post }) => (
<div>
<Link to={"/blog"+post.frontmatter.slug}>
{post.frontmatter.title}
{/* {post.frontmatter.title} ({post.frontmatter.date}) */}
</Link>
</div>
)
export default PostLink
Check the API of the Link and if it has an equivalent of target attribute.

I don't want to create another db table to filter who is team and who is friend, please help me

I don't want to creater another table called friends at strapi and link it again to visual studio code, so I have a Characters table for all team and friends. So I want to input only new data at Characters , but filter it to know which one is friend or team. So I've tried to make a function for it to know's which is a friend, that I've determined with if you have only start date your a team if you have both start and end date you are friend. The source code at the file is this:
import Head from 'next/head'
import Layout from '../../components/Layout'
import styles from '../../styles/Home.module.css'
import fetchFromCMS from '../../lib/service';
import React, { Component } from 'react';
import "react-responsive-carousel/lib/styles/carousel.min.css"; // requires a loader
import { Carousel } from 'react-responsive-carousel';
export async function getStaticProps() {
const characters = await fetchFromCMS('characters');
return {
props: { characters},
revalidate: 1,
};
}
function sortByDate(a , b){
return new Date(a.StartDate) - new Date(b.StartDate);
}
function isFirend(a ){
var bool = true;
new Date(a.EndDate) != null? bool = true : bool= false;
return bool ;
}
const charactersItem = ({ characters }) => {
return (
<Layout>
<div className={styles.container}>
<Head>
<title>Characters</title>
</Head>
<main className={styles.main} id="page-top">
{/*///Team*/ }
<section className="bg-light page-section">
<div className="container">
<div className="row">
<div className="col-lg-12 text-center">
<h2 className="section-heading text-uppercase">Our Amazing Team</h2>
<h3 className="section-subheading text-muted">Check out our fantastic team.</h3>
</div>
</div>
<div className="row">
{characters.sort().map((character) => (
<div className="col-sm-4">
<a href={`/Team/${character.Slug}`}>
<div className="team-member">
<img className="mx-auto rounded-circle" src={character.Image.url} alt=""></img>
<h4 className="text-muted">{character.PaineapleName}</h4>
</div>
</a>
</div>
))
}
</div>
</div>
</section>
{/*//friends*/}
{ <section className="bg-light page-section">
<div className="container">
<div className="row">
<div className="col-lg-12 text-center">
<h2 className="section-heading text-uppercase">Our Amazing Friends</h2>
<h3 className="section-subheading text-muted">Check out our fantastic team.</h3>
</div>
</div>
<div className="row">
{characters.sort(character.EndDate).map((character) => (
<div className="col-sm-4">
<a href={`/Team/${character.Slug}`}>
<div className="team-member">
<img className="mx-auto rounded-circle" src={character.Image.url} alt=""></img>
<h4 className="text-muted">{character.PaineapleName}</h4>
</div>
</a>
</div>
))
}
</div>
</div>
</section> }
</main>
</div>
</Layout>
)
};
export default charactersItem;
The results aren't what I've expected because and the error it shows is this one:
I try other solutions and the only way I did something nearby the objective it duplicated, I mean with this, it duplicated the info instead of filter which one is friend.
character.endDate is not a compare function. It's possible Characters is the issue but you should isolate each issue one by one to troubleshoot.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

Having trouble rendering an array of images from an api (Django Rest Framework) response in React

Hi this is my first project in both React and Django Rest Framework and I need to figure this out to complete the project.
The issue I'm having (I believe it's a React one) is that my api is returning an json response which React receives using axios which works fine since when I do the console log all the data is there and Im also able to pass the data to a tag, etc. I would like to display the photos that are being sent to by the api. The link is not the problem as I am able to view the photo in the browser using the link provided by the api. The problem is that I have multiple images in the api response that are set up as an array.
As shown here:
postmanResponse
Response using console:
enter image description here
I guess essentially what I'm asking is there a way that I can make an array/object with the image array that my api is delivering so that I can then use it to show the picture in React?
Any help will be helpful. Thank you!
Here is my code for the React side:
// Import Files
import React, { Component } from 'react';
// Import Axios
import axios from "axios";
// Import Is Mobile
import { isMobile } from 'react-device-detect';
// Import Css
import "./projectDetail.css";
// Mobile Css
import "./projectDetailM.css"
// Lightbox
import { SRLWrapper } from "simple-react-lightbox";
// Import Footer
import Footer from "../Footer/footer"
// Project Detail Class
class ProjectDetail extends Component {
// States
state = {
data: [],
photoIndex: 0,
isOpen: false,
}
// Mount Data to the State
componentDidMount() {
this.handleFetchItem();
}
// Get the project via axios
handleFetchItem = () => {
// Variables
const {
match: { params }
} = this.props
// Set State
this.setState({ loading: true });
// Axios Setup
axios.get('http://127.0.0.1:8000/projects/' + params.ID)
.then(res => {
this.setState({ data: res.data, loading: false });
})
.catch(console.error());
}
// Render the page
render() {
// Const
const { data } = this.state;
const project = data;
// Print to console (Debugging)
//console.log(data);
// Return Page
return (
<div className="projectDetailMainContainer">
<div className="projectDetailGrid">
<div className="projectDetailArea">
<div className="projectNameArea">
<h1 className="projectNameStyling">
{project.title}
</h1>
</div>
<div className="projectAddress1Area">
<h2 className="projectAddress1Styling">
{project.address},
</h2>
</div>
<div className="projectAddress2Area">
<h2 className="projectAddress2Styling">
{project.address2}
</h2>
</div>
<div className="projectCityArea">
<h2 className="projectCityStyling">
{project.city} {project.zipcode}
</h2>
</div>
<div className="projectProgressArea">
<h3 className="projectProgressStyling">
{project.completed}
</h3>
</div>
<div className="projectReturnButton">
<button
className="btnStyleDetailPage"
type="button"
onClick={() => { this.props.history.replace('/projects') }}>
Return to Project List
</button>
</div>
</div>
<div className="projectDetailImageArea">
<SRLWrapper>
<img className="projectImageStyling"
src={require("./placeholders/city.jpg")} alt={project.title} />
</SRLWrapper>
</div>
</div>
<Footer />
</div>
);
}
}
// Export Compoenent
export default ProjectDetail;
You can solve this by implementing a image carousel or iterating over the images array.
First of all you must guarantee that the pictures are properly set on a state (does not matter what type of component). Then, here is one way to show all of the images and solve the problem:
function ImageList(props) {
return (
props.images.map((pic, index) => {
return (
<img key={index} src={pic.src} alt="image" />
);
})
);
}
use map like this
{ data.map(project => { <div className="projectDetailMainContainer">
<div className="projectDetailGrid">
<div className="projectDetailArea">
<div className="projectNameArea">
<h1 className="projectNameStyling">
{project.title}
</h1>
</div>
<div className="projectAddress1Area">
<h2 className="projectAddress1Styling">
{project.address},
</h2>
</div>
<div className="projectAddress2Area">
<h2 className="projectAddress2Styling">
{project.address2}
</h2>
</div>
<div className="projectCityArea">
<h2 className="projectCityStyling">
{project.city} {project.zipcode}
</h2>
</div>
<div className="projectProgressArea">
<h3 className="projectProgressStyling">
{project.completed}
</h3>
</div>
<div className="projectReturnButton">
<button
className="btnStyleDetailPage"
type="button"
onClick={() => { this.props.history.replace('/projects') }}>
Return to Project List
</button>
</div>
</div>
<div className="projectDetailImageArea">
<SRLWrapper>
<img className="projectImageStyling"
src={require("./placeholders/city.jpg")}
alt={project.title} />
</SRLWrapper>
</div>
</div>
<Footer />
</div>
})}
for the images you can access them by index like this
{project.images[0].src}
{project.images[1].src}
{project.images[2].src}
example:
<img src={project.images[0].src} alt="image" />

How to properly search in a list in ReactJS

I am trying to set a simple search operation in a user interface as shown below:
I have a total of 70 react-strap cards and each card contain a vessel with name, type and an image. I would like to search the name of the vessel and have the card related to that vessel to pop-up. All my images are currently contained inside the external database Contentful. Below the fields of interests:
The problem is that I don't know how to write a search function that locate a specific value of a list.
Below the code:
SideBar.js
import React from 'react';
import Client from '../Contentful';
import SearchVessel from '../components/SearchVessel';
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,
type
} = item.fields;
return {
name,
slug,
type
};
});
this.setState({
ships
});
}
getFilteredShips = () => {
if (!this.props.activeShip) {
return this.state.ships;
}
let targetShip = this.state.ships.filter(
(ship) => this.props.activeShip.name === ship.name
);
let otherShipsArray = this.state.ships.filter((ship) => this.props.activeShip.name !== ship.name);
return targetShip.concat(otherShipsArray);
};
render() {
return (
<div className="map-sidebar">
{this.props.activeShipTypes}
<SearchVessel />
<pre>
{this.getFilteredShips().map((ship) => {
console.log(ship);
return (
<Card className="mb-2">
<CardImg />
<CardBody>
<div className="row">
<img
className="image-sizing-primary"
src={ship.companylogo.fields.file.url}
alt="shipImage"
/>
</div>
<div>
<img
className="image-sizing-secondary"
src={ship.images.fields.file.url}
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>
<Row style={{ marginTop: '20px' }}>
<div className="buttoncontainer">
<div className="btn btn-cards">
<a
className="buttonLink"
download
href={ship.projectnotes.fields.file.url}
>
Project Notes
</a>
</div>
<div className="btn btn-cards">
<a className="buttonLink" href={ship.abstract.fields.file.url}>
Abstract
</a>
</div>
</div>
</Row>
</CardBody>
</Card>
);
})}
</pre>
</div>
);
}
}
export default Sidebar;
VesselSearch.js
import React, { Component } from 'react';
export default class SearchVessel extends Component {
render() {
const { value, handleSubmit, handleChange } = this.props;
return (
<React.Fragment>
<div className="container">
<div className="row">
<div className="col-10 mx-auto col-md-8 mt-5 text-center">
<h4 className="text-slanted text-capitalize">Search for Vessel</h4>
<form className="mt-4" onSubmit={handleSubmit}>
<label htmlFor="search" className="text-capitalize">
type vessel separated by comma
</label>
<div className="input-group">
<input
type="text"
name="search"
placeholder="Type name of vessel here"
className="form-control"
value={value}
onChange={handleChange}
/>
<div className="input-group-append">
<button type="submit" className="input-group-text bg-primary text-white">
<i className="fas fa-search" />
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</React.Fragment>
);
}
}
What I have done so far:
1) I tried different combination with the filter function and I think I am close. The problem is that when I operate the search nothing happens and in order to find the card of the vessel I want, I have to scroll down until I find it.
I am running out of ideas and if you see something I didn't catch point me in the right direction for solving this issue.
You're close! I would add a field to your state called 'searchText' and then create a method to filter based on that searchText state item.
getFilteredShips = () => this.state.ships.filter(s => s.name.includes(this.state.searchText)
Then just map over those values to render the cards that match the search text. The cards will update each time the searchText value updates.
this.getFilteredShips().map(ship => ..........
React is famous for re-usable component. You will have all the data of these vessels in an array. You will loop through the array and render the items with card component.And when you search for the specific card you want that vessel to pop out on top.
There are two ways to do it:
You have to run through the array, find the index of that vessel and do whatever it takes to manipulate your array and to make that item at top and re-render your list.
Alternatively render one more component on top of your vessel list as user clicks the search button. You just have to find the item index and render it. This way you don't have to deal with array manipulation. It doesn't matter if you have 80 or 1000 cards.
Please checkout official documentation for array methods, for array slicing and splice.
Hope this is what you are looking for. If you need further help, comment please.

How to add custom clickHandler for a specifc row

To set the context, I am new to REACT. I am working on a sample app where I need to display the trade data in tabular format. If you select the row, delete button on the extreme right should be displayed. Otherwise it should be hidden.
Instead of toggling with the display button, I am just trying to show and hide a text first. I was able to do that. Only thing which happens is that the text gets toggled for all the rows.
I was trying number of things to get this working. The code below is work in progress and I am not sure what to do next,
import React from 'react';
class TradeTableView extends React.Component {
constructor(){
super()
this.state = {
data: []
}
this.handleClickEvent = this.handleClickEvent.bind(this);
}
handleClickEvent(event) {
const name = event.target.name;
console.log('Name in handleClickEvent is ' + name);
}
componentDidMount() {
console.log('inside component did mount..');
fetch('http://localhost:3004/row')
.then(response => {
return response.json();})
.then(responseData => {console.log(responseData); return responseData;})
.then((data) => {
// jsonItems = JSON.parse(items);
this.setState({data: data});
});
}
render() {
return(
<div className="Table">
<div className="Heading">
<div className="Cell">
<p>Trade Date</p>
</div>
<div className="Cell">
<p>Commodity</p>
</div>
<div className="Cell">
<p>Side</p>
</div>
<div className="Cell">
<p>Quanity</p>
</div>
<div className="Cell">
<p>Price</p>
</div>
<div className="Cell">
<p>Counterparty</p>
</div>
<div className="Cell">
<p>Location</p>
</div>
<div className="Cell">
<p></p>
</div>
</div>
{this.state.data.map((item, key) => {
let prop1 = 'shouldHide'+key;
console.log('The prop is ' + prop1);
return (
<div ref={prop1} key={key} className="Row" onClick={this.handleClickEvent}>
<div className="Cell">
<p>{item.a}</p>
</div>
<div className="Cell">
<p>{item.b}</p>
</div>
<div className="Cell">
<p>{item.c}</p>
</div>
<div className="Cell">
<p>{item.d}</p>
</div>
<div className="Cell">
<p>{item.e}</p>
</div>
<div className="Cell">
<p>{item.f}</p>
</div>
<div className="Cell">
<p>{item.f}</p>
</div>
<div className="Cell">
<p onClick={this.handleClickEvent}>{this.state.prop1 ? 'Sample Text':'Some Text'}</p>
</div>
</div>
)
})}
</div>
);
}
}
export default TradeTableView;
This is my component. If you can let me know how to toggle the text only for a particular row, I can most probably use that know how to toggle the button(my original use case) and then delete the row on click of the button. I will really appreciate your help.
P.S I was able to toggle the text.You may not find logic on thi.state.prop1 in my code above because I was trying to modify the code to make it work for a single row. And finally I got in a state where it is not working for all the rows and obviously not for a single row. To sum up, my problem is to identify the unique row and dislay a section only for that row.
I've added a currentSelectedRow property to state to keep track of the selected row. Below is the code with minimal configuration.
import React from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
class TradeTableView extends React.Component {
constructor() {
super()
this.state = {
data: [{id:1,val:11},{id:2,val:22},{id:3,val:33}],
currentSelectedRow : -1
}
}
handleClickEvent = (event, key) =>{
this.setState({ currentSelectedRow: key})
}
render() {
return (
<div className="Table">
{this.state.data.map((item, key) => {
return (
<div key={key} className="Row" onClick={(e) => this.handleClickEvent(e, key)}>
<div className="Cell">
<p>{item.id}</p>
</div>
<div className="Cell">
<p>{item.val}</p>
</div>
<div className="Cell">
<p onClick={(e) => this.handleClickEvent(e, key)}>{this.state.currentSelectedRow === key ? 'Row Selected' : 'Row Not Selected'}</p>
</div>
</div>
)
})}
</div>
);
}
}
render(<TradeTableView />, document.getElementById('root'));
Here is the working example
Change your handleClickevent like this:
handleClickEvent(event, index) {
const name = event.target.name;
console.log("index is", index);
const stateData = [...this.state.data];
stateData[index]= "some new value"
this.setState({
data: stateData,
})
console.log('Name in handleClickEvent is ' + name);
}
change how you are attaching click handler to
onClick={(event) => this.handleClickEvent(event, key)}
Something along these lines is needed as per my understanding of the question.

Categories

Resources