How to display html content dynamically when clicking a button in ReactJS? - javascript

I have made 2 buttons and 1 input box which displays date from JSON data. When I click on increment or decrement buttons it should display the data.available_slots[0].data_slots
If data.available_slots[this.state.counter].data_slots === 0 then it should display "No slot available today" besides input box.
data.js:
const data = {
"template_type": "slot_picker",
"selection_color": "#000000",
"secondary_color": "#808080",
"title": "Available Slots for Dr. Sumit",
"available_slots": [
{
"date": "Wed, Dec 06",
"date_slots": [
]
},
{
"date": "Thu, Dec 07",
"date_slots": [
]
},
{
"date": "Fri, Dec 08",
"date_slots": [
]
},
{
"date": "Sat, Dec 09",
"date_slots": [
]
},
{
"date": "Today",
"date_slots": [
{
"hour": "8",
"hour_slots": [
{
"08:10 AM": "slotId001"
},
{
"08:50 AM": "slotId005"
}
]
},
{
"hour": "3",
"hour_slots": [
{
"03:00 PM": "slotId005"
},
{
"03:30 PM": "slotId007"
}
]
}
]
},
{
"date": "Tomorrow",
"date_slots": [
]
},
{
"date": "Wed, Dec 13",
"date_slots": [
{
"hour": "4",
"hour_slots": [
{
"04:30 PM": "slotId105"
},
{
"04:50 PM": "slotId106"
}
]
},
{
"hour": "5",
"hour_slots": [
{
"05:30 PM": "slotId202"
},
{
"05:45 PM": "slotId208"
}
]
}
]
}
]
};
export default data;
datepicker.js:
import React, { Component } from 'react';
import data from './data';
import './datepicker.css';
class DatePicker extends Component {
constructor(props){
super(props);
this.state = {
counter:0
};
}
increment(){
if(this.state.counter < 6){
this.setState(prevState => ({counter: prevState.counter + 1}))
}
if(data.available_slots[this.state.counter].data_slots === 0){
return(
<p>No slots available for today</p>
)
}else{
return(
<p>Slots available for today</p>
)
}
}
decrement(){
if(this.state.counter > 0){
this.setState(prevState => ({counter: prevState.counter-1}))
}
if(data.available_slots[this.state.counter].data_slots === 0){
return(
<p>No slots available for today</p>
)
}else{
return(
<p>Slots available for today</p>
)
}
}
render() {
return (
<div>
<div id="center">
<div className="title">
<p>Pick a Date</p>
</div>
<div className="increment">
<button type="button" className="btn btn-success" id="plus" onClick={this.increment.bind(this)}>+</button>
</div>
<div className="display">
<input type="text" id="date" value={data.available_slots[this.state.counter].date}/>
</div>
<div className="decrement">
<button type="button" className="btn btn-danger" id="minus" onClick={this.decrement.bind(this)}>-</button>
</div>
<div className="submit">
<button type="button" class="btn btn-primary" id="submit">Set Date</button>
</div>
</div>
<div id="slotinfo">
</div>
</div>
);
}
}
export default DatePicker;
When I click on plus/minus buttons for that day it should display if the slot is available for that day or not. So the increment() and decrement() functions are not returning the <p> elements besides input box.
Screenshot:

increment and decrement functions are just returning the <p> elements and doesn't know where to display them.
Move the logic to render "No slots available for today" or "Slots available for today" inside the render function based on the state variable this.state.counter. The logic inside increment and decrement methods can be removed.
increment(){
if(this.state.counter < 6){
this.setState(prevState => ({counter: prevState.counter + 1}))
}
}
decrement(){
if(this.state.counter > 0){
this.setState(prevState => ({counter: prevState.counter - 1}))
}
}
And in the render function,
<div id="slotinfo">
{ data.available_slots[this.state.counter].date_slots.length === 0 ?
<p>No slots available for today</p> : <p>Slots available for today</p> }
</div>

Related

Order by nested field using Astro

Given the following JSON response, how would I group them according to team first, then by year, using javascript and/or jsx to map the response? I'm using Astro.
{
"data": [
{
"id": 1,
"team_name": "Team One",
"players": [
{
"player_name": "Mickey Mantle",
"players_year": {
"year": 2024
}
},
{
"player_name": "Larry Smalls",
"players_year": {
"year": 2022
}
},
{
"player_name": "Ron Davis",
"players_year": {
"year": 2024
}
}
]
},
{
"id": 2,
"team_name": "Team Two",
"players": [
{
"player_name": "Jim Abbot",
"players_year": {
"year": 2022
}
}
]
}
]
}
End Result – The HTML output should match this:
<div class="group">
<h2>Team One</h2>
<h3>2022</h3>
<ul>
<li>Larry Smalls</li>
</ul>
<h3>2024</h3>
<ul>
<li>Mickey Mantle</li>
<li>Ron Davis</li>
</ul>
</div>
<div class="group">
<h2>Team Two</h2>
<h3>2022</h3>
<ul>
<li>Jim Abbot</li>
</ul>
</div>
Currently, here is my file which works, but without the grouping as seen directly above. What additional javascript is needed in Astro's frontmatter and markup required in the body of the page?
teams.astro
---
const directus = await getDirectusClient()
const response = await directus.items("teams").readByQuery({
fields: [
"id",
"team_name",
"players.player_name",
"players.players_year.year",
],
})
const formattedResponse = response.data.map((team) => {
return {
...team,
yearsArr: team.players.map(player => player.players_year.year)
}
})
const [...teams] = formattedResponse
---
<h1>Teams Page</h1>
{
teams.map((team) => {
return (
<div class='group'>
<h2>{team.team_name}</h2>
<ul>
{team.players.map((player) => (
<li>
{player.player_name} ({player.players_year.year})
</li>
))}
</ul>
</div>
)
})
}
This have been asked many times before. But not exactly like this.
Update: added the html markup (for Astro).
var obj = {data:[{id:1,team_name:"Team One",players:[{player_name:"Mickey Mantle",players_year:{year:2024}},{player_name:"Larry Smalls",players_year:{year:2022}},{player_name:"Ron Davis",players_year:{year:2024}}]},{id:2,team_name:"Team Two",players:[{player_name:"Jim Abbot",players_year:{year:2022}}]}]};
var result = {};
obj.data.forEach(function(item) {
result[item.team_name] = result[item.team_name] || {}
item.players.forEach(function(player) {
result[item.team_name][player.players_year.year] = result[item.team_name][player.players_year.year] || [];
result[item.team_name][player.players_year.year].push(player.player_name);
})
})
console.log(result)
.as-console-wrapper {
max-height: 100% !important
}
<h1>Teams Page</h1>
{Object.entries(result).map(([team_name, team]) => { return (
<div class='group'>
<h2>{team_name}</h2>
{Object.entries(team).map(([year, players]) => (
<h3>{year}</h3>
<ul>
{players.map(player_name) => (
<li>
{player_name}
</li>
)}
</ul>
))}
</div>
) }) }

How to return all elements from an Object?

There is a page where you can see the details of a user's loan. There is a decorator where I return values ​​using the get () method. In general, there is a partial refund, which returns items of partial payments as shown in the photo. My problem is that I cannot specify all partial payments, only receive one by one.
Loan Details component:
<div className="ClientLoanDetails__card__content__inner__wrapper">
{Object.keys(payments[0]).map(val => {
{
[payments[0][val]].map((payment: any, index: number) => (
<div className="ClientLoanDetails__card__content-inner" key={index}>
{paymentsFields.map((item, indexInner) => (
<div className="ClientLoanDetails__card__content-item" key={indexInner}>
<div className="ClientLoanDetails__card__content-item__title">
{item.title}
</div>
<div className="ClientLoanDetails__card__content-item__value">
{payment[item.key]}
</div>
</div>
))}
</div>
));
}}
)
}}
</div>
This is code snippet for key & titles from loan.ts:
export const repaymentsFields = [
{
key: 'issuedDate',
title: lang.CLIENTS.REPAYMENTS.ISSUED_DATE,
},
{
key: 'period',
title: lang.CLIENTS.REPAYMENTS.PERIOD_IN_DAYS,
},
]
JSON of repayments:
"partialRepayments": [
{
"orderId": "A11Fz090VT1BmObJ0S-0",
"repaidPrincipalAmount": {
"amount": 250000.0
},
"repaidInterestAmount": {
"amount": 0
},
"repaidOverdueAmount": {
"amount": 0
},
"repaidProlongationAmount": {
"amount": 0
},
"started": "2020-11-09T16:52:08.981+0600",
"completed": "2020-11-09T16:52:21.170+0600",
"period": 25,
"timestamp": "2020-11-09T16:52:21.174+0600"
},
{
"orderId": "A11Fz090VT1BmObJ0S-1",
"repaidPrincipalAmount": {
"amount": 300000.0
},
"repaidInterestAmount": {
"amount": 0
},
"repaidOverdueAmount": {
"amount": 0
},
"repaidProlongationAmount": {
"amount": 0
},
"started": "2020-11-09T16:54:31.923+0600",
"completed": "2020-11-09T16:54:46.313+0600",
"period": 25,
"timestamp": "2020-11-09T16:54:46.317+0600"
}
],
the problem is that it is impossible to display the values ​​that come as in the photo (one loan may have several repayments)
I have to return all values from an Object
IMAGE of console
Why don't you loop through the partialPayementResponse and access each field through the dot . notation ? Such as follows:
<div>
{partialRepayments.map((item, index) => {
return (
<div key={index}>
<div>Completed: <span>{item.completed}</span></div>
<div>orderId: <span>{item.orderId}</span></div>
<div>period: <span>{item.orderId}</span></div>
<div>repaidInterestAmount: <span>{item.repaidInterestAmount.amount}</span></div>
<div>repaidOverdueAmount: <span>{item.repaidOverdueAmount.amount}</span></div>
<div>repaidPrincipalAmount: <span>{item.repaidPrincipalAmount.amount}</span></div>
<div>repaidProlongationAmount: <span>{item.repaidProlongationAmount.amount}</span></div>
<div>started: <span>{item.started}</span></div>
<div>timestamp: <span>{item.timestamp}</span></div>
</div>)
})}
</div>
I wrote it without using your classNames but I think you get the idea
Not sure what's the problem here.
Can't u just iterate over these things?
Or create function and then display the thing that function returns...
for example:
displayAppropriateFields = () => {
let returnedArray = [];
returnedArray.push(<div> Some text in the div </div>);
for(let i=0; i<someArray.length; i++) {
returnedArray.push(<span> someArray[i] </span>)
}
return returnedArray;
}
And then display it in render method like so:
this.displayAppropriateFields();

how to use filter effect on checkbox in ReactJS?

how to use filter-effect whenever user click on checkbox?
As per below image, there is filter page. what i am trying to do is whenever user will click on checkbox the value should be return as output as per below filtering api data, But i am getting a null value instead.
image:
end-point url : http://localhost:8000/api/filter/
filter category api-data:
{
"product_categoryData": [
{
"id": 1,
"category_title": "category01"
},
{
"id": 2,
"category_title": "category02"
},
],
"filter_colorData": [
{
"id": 1,
"color_title": "black",
"color_hex_code": "#000000"
},
{
"id": 2,
"color_title": "red",
"color_hex_code": "#43243dsf"
},
],
//(so on...)
}
After filtering product filter api-data,
end point-url: http://localhost:8000/api/p_list?product_category=1&min_price=&max_price=&color=&size=
[
{
"url": "http://localhost:8000/api/p/product01",
"id": 1,
"title": "product01",
"slug": "product01",
"image": "http://localhost:8000/media/product2_EMWEgQI.png",
"price": 5,
"status": true,
"created_on": "2020-04-19T18:44:03Z"
},
{
"url": "http://localhost:8000/api/p/product07",
"id": 8,
"title": "product07",
"slug": "product07",
"image": "http://localhost:8000/media/product4_CKX7xsA.png",
"price": 8,
"status": true,
"created_on": "2020-04-19T18:44:03Z"
}
]
./src/Filter.js
import React, { Component } from "react";
class App extends Component {
constructor(props) {
super(props);
this.state = {
response: "",
filter_response: "",
category_value : "",
min_price: "",
max_price: "",
color_value: "",
size_value: "",
};
}
componentDidMount() {
this.fetchData();
}
filterClick = (value) => {
this.setState({category_value: value, min_price: value, max_price: value, color_value: value,
size_value: value}, this.fetchFilterEffectData);
};
fetchData = async () => {
try {
const response = await fetch(
`http://localhost:8000/api/filter/`
);
const JsonResponse = await response.json();
this.setState({ response: JsonResponse });
}
catch (error) {
console.log(error);
}
};
fetchFilterEffectData = async () => {
try {
const filter_response = await fetch(
`http://localhost:8000/api/p_list?product_category=${this.state.category_value}&min_price=${this.state.min_price}&max_price=${this.state.max_price}&color=${this.state.color_value}&size=${this.state.size_value}`
);
const JsonFilterResponse = await filter_response.json();
this.setState({ filter_response: JsonFilterResponse });
}
catch (error) {
console.log(error);
}
};
render() {
const { response } = this.state;
if (!response) {
return "Loading...";
}
return (
<div>
//Before Effect
<div class="select_option_list">Category <i class="right fas fa-caret-down"></i> </div>
<div class="select_option_dropdown">
{response.product_categoryData.map((response) =>(
<div class="form-check form-check-outline">
<input class="form-check-input" type="checkbox" id="inlineCheckbox1" value="option1"/>
<label class="form-check-label" for="inlineCheckbox1"><a href="#" onClick={() => this.filterClick(response.id)}>{response.category_title}</a></label>
</div>
))}
</div>
</div>
//After Effect
{filter_response.map((response) =>(
<div class="col-md-12">
<div class="blog-entry animate d-md-flex">
<img src={response.image} className="App-logo"/>
<div class="text text-2 pl-md-4">
<h3 class="mb-2">{response.title}</h3>
</div>
</div>
</div>
))}
</div>
);
}
}
export default App;

Try to map over an array of url images to render to cards using map

As the title says I am trying to map over an array of objects to get the photo urls to render in the cards. The cards only populate when you fill out a review form. I tried faker js but it would render a blank image so I thought that an array of objects would do the trick but I keep getting the error "Objects are not valid as a React child (found: object with keys {id, img}). If you meant to render a collection of children, use an array instead." Not really sure I know what I am doing wrong. Please assistance would be appreciated.
import { Card, Image } from 'semantic-ui-react'
import { Link } from 'react-router-dom';
import { axiosWithAuth } from '../utils/auth'
import "./userInfo.css"
function UserCard(props) {
// console.log("cardprops", props)
const { setReviews } = props;
// const deleteReview = data => {
// console.log(data.id);
// setReviews(reviews => [...reviews.filter(review => review.id !== data.id)]);
// };
const deleteReview = restaurant => {
axiosWithAuth().delete(`https://foodiefun-api.herokuapp.com/api/reviews/${restaurant.id}`, restaurant)
.then(res => {
setReviews(reviews => [...reviews.filter(review => review.id !== restaurant.id)]);
})
.catch(err => {
console.log('can not delete message', err)
})
}
let postsdata = [
{
"id": 1,
"img": "https://www.thegrilledcheesetruck.com/wp-content/uploads/2017/03/gct-menu21-800x600.jpg"
},
{
"id": 2,
"img": "https://blueprint-api-production.s3.amazonaws.com/uploads/card/image/917437/3261d336-f53b-44a0-abdb-69792f60af66.jpg"
},
{
"id": 3,
"img": "https://tastychomps.com/wp-content/uploads/2019/06/P6150451-800x600.jpg"
},
{
"id": 4,
"img": "https://cdn.styleblueprint.com/wp-content/uploads/2019/07/SB-BHM-Food-Truck-Mustard-Seed-Food-Co-hot-mess-fries.jpg"
},
{
"id": 5,
"img": "https://snworksceo.imgix.net/cav/8ed1b226-a90d-4c2d-9216-99689efa4334.sized-1000x1000.jpg?w=800"
},
{
"id": 6,
"img": "https://www.whatsonnetwork.co.uk/uploads/800x600/e6e34f13ec62f43638b808feb55fab9e.jpg"
},
{
"id": 7,
"img": "https://news.wbfo.org/sites/wbfo/files/styles/medium/public/201907/table_food.jpg"
},
{
"id": 8,
"img": "https://craftcleaver.co.uk/wp-content/uploads/2017/10/sharing-platter-on-blue-square-angle-800x600.jpg"
},
{
"id": 9,
"img": "https://theculturetrip.com/wp-content/uploads/2015/12/800px-Hoppers_at_house_of_dosas.jpg"
},
{
"id": 10,
"img": "https://s3-prod.adage.com/s3fs-public/styles/800x600/public/80_ChickenMcNuggetHappyMeal.jpg"
},
{
"id": 11,
"img": "https://porteliotfestival.com/wp-content/uploads/2017/04/Port-Eliot-Festival-2017-294A3665-800x600.jpg"
},
{
"id": 12,
"img": "https://www.mykadhai.com/assets/images/img-4142-2000x1500-800x600.jpg"
},
{
"id": 13,
"img": "https://nwatravelguide.com/wp-content/uploads/2018/05/The-Hive-800x600.jpg"
},
{
"id": 14,
"img": "https://www.mjseatery.com/images/buritto.jpg"
},
{
"id": 15,
"img": "https://imagevars.gulfnews.com/2019/07/18/Deccan-Delight-biryani_16c043a76bd_original-ratio.jpg"
}
]
return (
<Card>
<div className="rating">
<span>☆</span><span>☆</span><span>☆</span><span>☆</span><span>☆</span>
</div>
const Photo = ({postsdata}) => (
<div>
{postsdata.map(postdata => (
<Image className='photoOfOrder' key={postdata.img} src={postdata.img} wrapped ui={false} />
))}
</div>
)
<Card.Content>
<Card.Header
className='restaurantName'>{props.tileData.restaurantName}
</Card.Header>
<Card.Meta>
<span className='dateOfVisit'><b>Date Visited: </b> {props.tileData.dateOfVisit}</span>
</Card.Meta>
<Card.Meta>
<span className='restaurantType'><b>Type of Food: </b>{props.tileData.restaurantType}</span>
</Card.Meta>
<Card.Meta>
<span className='waitTime'><b>Wait Time: </b>{props.tileData.waitTime} minutes</span>
</Card.Meta>
<Card.Meta>
<span className='menuItem'><b>Item Ordered: </b>{props.tileData.menuItem}</span>
</Card.Meta>
<Card.Meta>
<span className='price'><b>Price: $</b>{props.tileData.price}</span>
</Card.Meta>
<Card.Meta>
<span className='foodRating'><b>Food rating: </b>{props.tileData.foodRating} Stars</span>
</Card.Meta>
<Card.Meta>
<span className='comments'><b>Comments: </b>{props.tileData.comments}</span>
</Card.Meta>
</Card.Content>
<Link to={`/edit/${props.tileData.id}`}>
<button className='edit-btn btn btn-bubble'>
Edit
</button></Link>
<button className='delete-btn btn2 btn-bubble2'
onClick={() => deleteReview(props.tileData)}>
Delete
</button>
</Card >
)
}
export default UserCard;```
UderInfo.js
The only other file for the cards
```import React, { Component } from 'react';
import UserCard from './userCard';
import SearchSelect from './SearchSelect'
import "./userInfo.css";
export default class userInfo extends Component {
constructor(props) {
super(props);
this.state = { selectedFilterThingies: [] }
this.searchSelectHandler = this.searchSelectHandler.bind(this);
}
searchSelectHandler(value) {
this.setState({ selectedFilterThingies: value });
console.log("searched array", value)
}
// ["Fast Food", "Japanese", "Mexican" ]
render() {
//console.log("updatehandler", {this.searchSelectHandler})
if (!this.props.data) {
return <div>Loading Foodie Cards...</div>
}
else {
if (this.state.selectedFilterThingies.length < 1) {
return <section className='userCard '>
<div>
<div>
<SearchSelect updateHandler={this.searchSelectHandler} data={this.props.data} />
</div>
<div className='gridview' >
{this.props.data.map(oneRest => (
<UserCard className='onecard' tileData={oneRest} setReviews={this.props.setReviews} />
))}
</div>
</div>
</section>
}
else {
let newarray = []
//check for restuarant type and render from newarray
newarray = (this.props.data.filter(item =>
this.state.selectedFilterThingies.some(filter => filter === item.restaurantType)))
console.log("newarray", newarray)
return <section className='userCard '>
<div>
<div>
<SearchSelect updateHandler={this.searchSelectHandler} data={this.props.data} />
</div>
<div className='gridview'>
{newarray.map(oneRest => (
<UserCard className='onecard' tileData={oneRest} setReviews={this.props.setReviews} />
))}
</div>
</div>
</section>
}
}
}
}
```
you need to take Photo out of return statement and format map properly
import { Card, Image } from 'semantic-ui-react'
import { Link } from 'react-router-dom';
import { axiosWithAuth } from '../utils/auth'
import "./userInfo.css"
function UserCard(props) {
// console.log("cardprops", props)
const { setReviews } = props;
// const deleteReview = data => {
// console.log(data.id);
// setReviews(reviews => [...reviews.filter(review => review.id !== data.id)]);
// };
const deleteReview = restaurant => {
axiosWithAuth().delete(`https://foodiefun-api.herokuapp.com/api/reviews/${restaurant.id}`, restaurant)
.then(res => {
setReviews(reviews => [...reviews.filter(review => review.id !== restaurant.id)]);
})
.catch(err => {
console.log('can not delete message', err)
})
}
let postsdata = [
{
"id": 1,
"img": "https://www.thegrilledcheesetruck.com/wp-content/uploads/2017/03/gct-menu21-800x600.jpg"
},
{
"id": 2,
"img": "https://blueprint-api-production.s3.amazonaws.com/uploads/card/image/917437/3261d336-f53b-44a0-abdb-69792f60af66.jpg"
},
{
"id": 3,
"img": "https://tastychomps.com/wp-content/uploads/2019/06/P6150451-800x600.jpg"
},
{
"id": 4,
"img": "https://cdn.styleblueprint.com/wp-content/uploads/2019/07/SB-BHM-Food-Truck-Mustard-Seed-Food-Co-hot-mess-fries.jpg"
},
{
"id": 5,
"img": "https://snworksceo.imgix.net/cav/8ed1b226-a90d-4c2d-9216-99689efa4334.sized-1000x1000.jpg?w=800"
},
{
"id": 6,
"img": "https://www.whatsonnetwork.co.uk/uploads/800x600/e6e34f13ec62f43638b808feb55fab9e.jpg"
},
{
"id": 7,
"img": "https://news.wbfo.org/sites/wbfo/files/styles/medium/public/201907/table_food.jpg"
},
{
"id": 8,
"img": "https://craftcleaver.co.uk/wp-content/uploads/2017/10/sharing-platter-on-blue-square-angle-800x600.jpg"
},
{
"id": 9,
"img": "https://theculturetrip.com/wp-content/uploads/2015/12/800px-Hoppers_at_house_of_dosas.jpg"
},
{
"id": 10,
"img": "https://s3-prod.adage.com/s3fs-public/styles/800x600/public/80_ChickenMcNuggetHappyMeal.jpg"
},
{
"id": 11,
"img": "https://porteliotfestival.com/wp-content/uploads/2017/04/Port-Eliot-Festival-2017-294A3665-800x600.jpg"
},
{
"id": 12,
"img": "https://www.mykadhai.com/assets/images/img-4142-2000x1500-800x600.jpg"
},
{
"id": 13,
"img": "https://nwatravelguide.com/wp-content/uploads/2018/05/The-Hive-800x600.jpg"
},
{
"id": 14,
"img": "https://www.mjseatery.com/images/buritto.jpg"
},
{
"id": 15,
"img": "https://imagevars.gulfnews.com/2019/07/18/Deccan-Delight-biryani_16c043a76bd_original-ratio.jpg"
}
]
const Photo = postsdata.map(postdata => (
<Image className='photoOfOrder' key={postdata.img} src={postdata.img} wrapped ui={false} />
);
return (
<Card>
<div className="rating">
<span>☆</span><span>☆</span><span>☆</span><span>☆</span><span>☆</span>
</div>
<div>
{Photo}
</div>
<Card.Content>
<Card.Header
className='restaurantName'>{props.tileData.restaurantName}
</Card.Header>
<Card.Meta>
<span className='dateOfVisit'><b>Date Visited: </b> {props.tileData.dateOfVisit}</span>
</Card.Meta>
<Card.Meta>
<span className='restaurantType'><b>Type of Food: </b>{props.tileData.restaurantType}</span>
</Card.Meta>
<Card.Meta>
<span className='waitTime'><b>Wait Time: </b>{props.tileData.waitTime} minutes</span>
</Card.Meta>
<Card.Meta>
<span className='menuItem'><b>Item Ordered: </b>{props.tileData.menuItem}</span>
</Card.Meta>
<Card.Meta>
<span className='price'><b>Price: $</b>{props.tileData.price}</span>
</Card.Meta>
<Card.Meta>
<span className='foodRating'><b>Food rating: </b>{props.tileData.foodRating} Stars</span>
</Card.Meta>
<Card.Meta>
<span className='comments'><b>Comments: </b>{props.tileData.comments}</span>
</Card.Meta>
</Card.Content>
<Link to={`/edit/${props.tileData.id}`}>
<button className='edit-btn btn btn-bubble'>
Edit
</button></Link>
<button className='delete-btn btn2 btn-bubble2'
onClick={() => deleteReview(props.tileData)}>
Delete
</button>
</Card >
)
}
export default UserCard;```
Your problem is this,
const Photo = ({postsdata}) => (
<div>
{postsdata.map(postdata => (
<Image className='photoOfOrder' key={postdata.img} src={postdata.img} wrapped ui={false} />
))}
</div>
)
We never write functions inside of return, you just need to do this,
<div>
{postsdata.map(postdata => (
<Image className='photoOfOrder' key={postdata.id} src={postdata.img} wrapped ui={false} />
))}
</div>
Note: You have provided key={postdata.img}, when you have id then you should provide id as key which is more useful.
Update
To match any image randomly you can do this,
{postsdata.filter(postdata => postdata.id === props.index).map(data=> <Image className='photoOfOrder' key={data.id} src={data.img} wrapped ui={false} />)}
You need to pass index from parent component as,
<UserCard className='onecard' tileData={oneRest} setReviews={this.props.setReviews} index={Math.floor(Math.random()*15)+1} />
Here Math.floor(Math.random()*15)+1 will give you random number between 1 to 15.

React, show quantity of how many elements match after filtering

I have this input that filters through a state and shows only the elements that match after typing something, as an extra bonus I need to show the quantity of how many items match.
For example:
If I type "react" only the elements with the react word in it will be shown so the render should show something like this.
There are 2 enterprises that have what you need
My code:
const searchingFor = (term) => {
return (x) => {
return x.tecnologia.toLowerCase().includes(term.toLowerCase()) || !term;
}
}
class FilterClass extends React.Component {
constructor(props) {
super(props);
this.state = {
empresas: [
{
empresa: "Daniel",
tecnologia: "React",
clientes: ["sodimac", "ripley", "paris"],
experiencia: "5 años",
id: 1
},
{
empresa: "Juan",
tecnologia: "React",
clientes: ["Falabella", "ripley", "ikea"],
experiencia: "3 años",
id: 2
},
{
empresa: "David",
tecnologia: "Angular",
clientes: ["Falabella", "ripley", "ikea"],
experiencia: "3 años",
id: 2
},
{
empresa: "Carlos",
tecnologia: "Vue",
clientes: ["Copec", "Wallmark", "Unimark"],
experiencia: "6 años",
id: 3
}
],
term: ''
}
this.searchHandler = this.searchHandler.bind(this);
}
searchHandler(event) {
this.setState({ term: event.target.value })
}
render() {
const {term, empresas} = this.state;
return (
<div>
<form className="container--flex-center">
<input type="text" onChange={this.searchHandler} value={term} />
</form>
{empresas.filter(searchingFor(term)).map(item =>
<FilterComponent
empresa={item.empresa}
tecnologia={item.tecnologia}
clientes={item.clientes}
experiencia={item.experiencia}
key={item.id}
/>
)}
</div>
)
}
}
export default FilterClass;
Well, I do not know where this bonus message should appear, so excuse me if it is not the correct answer.
Well I inserted the message just below the map and then put a filter in the matrix that returns the size as a condition to render the bonus message.
{empresas.filter(element => element.tecnologia === term).length > 0 &&
<div>
here are {empresas.filter(element => element.tecnologia === term).length} enterprises that have what you need
</div>
}
Result
render() {
const {term, empresas} = this.state;
return (
<div>
<form className="container--flex-center">
<input type="text" onChange={this.searchHandler} value={term} />
</form>
{empresas.filter(element => element.tecnologia === term).map(item =>
<FilterComponent
empresa={item.empresa}
tecnologia={item.tecnologia}
clientes={item.clientes}
experiencia={item.experiencia}
key={item.id}
/>
)}
{empresas.filter(element => element.tecnologia === term).length > 0 &&
<div>There are {empresas.filter(element => element.tecnologia === term).length} enterprises that have what you need</div>
}
</div>
)
}
If you want to pass the count of the matched results you can do a trick like this. First Filter you empresas array with your condition then map it.
import React, { Component } from "react";
const searchingFor = term => {
return x => {
return x.tecnologia.toLowerCase().includes(term.toLowerCase()) || !term;
};
};
class FilterClass extends React.Component {
constructor(props) {
super(props);
this.state = {
empresas: [
{
empresa: "Daniel",
tecnologia: "React",
clientes: ["sodimac", "ripley", "paris"],
experiencia: "5 años",
id: 1
},
{
empresa: "Juan",
tecnologia: "React",
clientes: ["Falabella", "ripley", "ikea"],
experiencia: "3 años",
id: 2
},
{
empresa: "David",
tecnologia: "Angular",
clientes: ["Falabella", "ripley", "ikea"],
experiencia: "3 años",
id: 3
},
{
empresa: "Carlos",
tecnologia: "Vue",
clientes: ["Copec", "Wallmark", "Unimark"],
experiencia: "6 años",
id: 4
}
],
term: "",
matchedcount: 0
};
this.searchHandler = this.searchHandler.bind(this);
this.contnmap = this.contnmap.bind(this);
}
searchHandler(event) {
this.setState({ term: event.target.value });
}
contnmap(term, empresas) {
let matchedcount = empresas.filter(searchingFor(term));
let count = Object.keys(matchedcount).length;
return [
matchedcount.map(item => (
<FilterComponent
empresa={item.empresa}
tecnologia={item.tecnologia}
clientes={item.clientes}
experiencia={item.experiencia}
key={item.id}
/>
)),
count
];
}
render() {
const { term, empresas } = this.state;
return (
<div>
<input type="text" onChange={this.searchHandler} value={term} />
{this.contnmap(term, empresas)[0]}
<div>count:{this.contnmap(term, empresas)[1]}</div>
</div>
);
}
}
export default FilterClass;
Here the contnmap() function returns an array where the 1st element will be the set of react elements and the next is the count.
You can just save the result of the filter (and render them later) and use .length to get the count:
render() {
const {term, empresas} = this.state;
const termItems = empresas.filter(searchingFor(term))
return (
<div>
<form className="container--flex-center">
<input type="text" onChange={this.searchHandler} value={term} />
</form>
<p>There are {termItems.length} enterprises that have what you need</p>
{termItems.map(item =>
<FilterComponent
empresa={item.empresa}
tecnologia={item.tecnologia}
clientes={item.clientes}
experiencia={item.experiencia}
key={item.id}
/>
)}
</div>
)
}
This way, you don't have to filter twice and just use a variable. Simple, clean, and reusable.

Categories