I want to make a grey-colored background for my list in ReactJS.
The problem is that the background seems to have a fixed height which seems to be smaller than the inside's height...
I never met this problem before, and the only way I found to have the background size bigger than the element's is to put height: XXXpx, which is not suitable...
Can someone explain me what I did wrong ?
Here is my class file :
import React, { Component } from "react";
import { ListGroupItem } from "react-bootstrap";
import { LinkContainer } from "react-router-bootstrap";
import { API } from "aws-amplify";
import "./ProjectList.css";
export default class ProjectList extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
projects: [],
reducedView: true,
projectsNumber: 1000,
numberOfElementsToDisplay: 1000
};
}
async componentDidMount() {
try {
const projects = await this.projects();
console.log(projects)
this.setState({ projects });
} catch (e) {
alert(e);
}
this.setState({ isLoading: false });
}
projects() {
return API.get("economics-endpoint", "/list");
}
handleClick(e) {
this.setState({ reducedView: false });
e.preventDefault();
}
renderNotesList(projects) {
return [{}].concat(projects).map(
(note, i) => {
if(i !== 0){
if((this.state.reducedView && i <= this.state.numberOfElementsToDisplay) || !this.state.reducedView){
return(
<div className="element">
<ListGroupItem className="mainContainer">
<div>
ProjectName#{i}
</div>
</ListGroupItem>
</div>
);
}
}
else{
if(this.state.projectsNumber === 0){
return(
<div className="element">
<LinkContainer to={`/econx/new`}>
<ListGroupItem className="new">
<div>
+ Create New Project
</div>
</ListGroupItem>
</LinkContainer>
<div className="errorMessage">
You don't have any existing project yet.
</div>
</div>
);
}
else{
return(
<div className="element">
<LinkContainer to={`/econx/new`}>
<ListGroupItem className="new">
<div>
+ Create New Project
</div>
</ListGroupItem>
</LinkContainer>
</div>
);
}
}
}
);
}
render() {
return (
<div className="ProjectList">
<div className="projects">
{!this.state.isLoading &&
this.renderNotesList(this.state.projects)}
</div>
</div>
);
}
}
And my css file :
.ProjectList .notes h4 {
font-family: "Open Sans", sans-serif;
font-weight: 600;
overflow: hidden;
line-height: 1.5;
white-space: nowrap;
text-overflow: ellipsis;
}
.projects{
background-color: #E0E0E0;
border-radius: 10px;
padding: 1%;
}
.list-group-item{
margin-bottom: 3px;
padding: 0px;
line-height: 200px;
text-align: center;
vertical-align: middle;
border-radius: 6px;
padding-bottom: 50px;
}
.list-group-item:first-child{
padding: 0px;
border-radius: 6px;
}
.list-group-item:hover{
vertical-align: baseline;
}
.element{
width: 20%;
float: left;
padding: 0% 1% 1% 1%;
}
This doesn't answer your CSS question. I did have some thoughts on the JavaScript, though. I'll offer my refactor for your consideration. Hopefully I interpreted your original logic correctly:
import React, { Component } from "react";
import { ListGroupItem } from "react-bootstrap";
import { LinkContainer } from "react-router-bootstrap";
import { API } from "aws-amplify";
import "./ProjectList.css";
export default class ProjectList extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
projects: [],
reducedView: true,
projectsNumber: 1000,
numberOfElementsToDisplay: 1000
};
}
async componentDidMount() {
try {
const projects = await this.fetchProjects();
console.log(projects);
this.setState({ projects });
} catch (e) {
alert(e);
} finally {
this.setState({ isLoading: false });
}
}
fetchProjects = () => {
return API.get("economics-endpoint", "/list");
};
handleClick = e => {
e.preventDefault();
this.setState({ reducedView: false });
};
render() {
const {
isLoading,
numberOfElementsToDisplay,
projectsNumber,
reducedView
} = this.state;
const projects = reducedView
? this.state.projects.slice(0, numberOfElementsToDisplay)
: this.state.projects;
return (
<div className="ProjectList">
<div className="projects">
{!isLoading && (
<React.Fragment>
<div className="element">
<LinkContainer to={`/econx/new`}>
<ListGroupItem className="new">
<div>+ Create New Project</div>
</ListGroupItem>
</LinkContainer>
{projectsNumber === 0 && (
<div className="errorMessage">
You don't have any existing projects yet.
</div>
)}
</div>
{projects.map((project, index) => (
<div className="element">
<ListGroupItem className="mainContainer">
<div>ProjectName#{index}</div>
</ListGroupItem>
</div>;
))}
</React.Fragment>
)}
</div>
</div>
);
}
}
This fixes your off-by-one issue by hopefully capturing your intentions as I understand them:
If it's not loading...
Show a "Create New Project" item
If they don't have any projects yet, show them a message
If they do have projects, create a new element for each one
It's worth considering whether your projectsNumber could be replaced with projects.length. If so, you can probably combine (2) and (3) above to be an either-or scenario: If they don't have projects, show a message, if they do, show the projects.
Related
I want to make a photo slider like the following link by React.js.
https://youtu.be/Zv9KskTYTNQ
Each post contains a maximum of 5 photos When displaying, I want to display only one photo and switch photos with a slider instead of showing 5 photos.
Issue/error message
Currently, if there are two or more photos as shown below, they will be displayed vertically.
I tried the link below but I don't know how to apply it to my code. . https://www.npmjs.com/package/react-slideshow-image Or if there is another way that works, it will be great.
import React, { useState, useEffect, onClick } from "react";
import axios from "axios";
import Cookies from "universal-cookie";
import { apiURL } from "./Default";
import { useSelector } from "react-redux";
import { useParams, Link } from "react-router-dom";
import { useDispatch } from "react-redux";
import { setUserID, setUserName } from "../stores/user";
import { useForm } from "react-hook-form";
const cookies = new Cookies();
const Top = () => {
const { id } = useParams();
const [post, setPost] = useState();
const isLoggedIn = useSelector((state) => state.user.isLoggedIn);
const userID = useSelector((state) => state.user.userID);
const dispatch = useDispatch();
const {
register,
handleSubmit,
formState: { errors },
} = useForm();
const [len, setLen] = useState(0);
const [flug, setFlug] = useState(true);
const [initial_screen, setInitial] = useState(true);
const username = useSelector((state) => state.user.userName);
console.log(username);
let slideIndex = 1;
showSlides(slideIndex);
function plusSlides(n) {
showSlides((slideIndex += n));
}
function currentSlide(n) {
showSlides((slideIndex = n));
}
function showSlides(n) {
let i;
let slides = document.getElementsByClassName("mySlides");
let dots = document.getElementsByClassName("dot");
if (n > slides.length) {
slideIndex = 1;
}
if (n < 1) {
slideIndex = slides.length;
}
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
for (i = 0; i < dots.length; i++) {
dots[i].className = dots[i].className.replace(" active", "");
}
}
const getPosts = async (data) => {
await axios
.get(apiURL + "posts/", {
headers: {
"Content-Type": "application/json",
},
})
.then((result) => {
setPost(result.data);
setLen(result.data.length);
setInitial(true);
})
.catch((err) => {
console.log(err);
});
};
const getLoginID = async (data) => {
await axios
.get(apiURL + "mypage/", {
headers: {
"Content-Type": "application/json",
Authorization: `JWT ${cookies.get("accesstoken")}`,
},
})
.then((get_user) => {
dispatch(setUserID(get_user.data.id));
dispatch(setUserName(get_user.data.username));
})
.catch((err) => {
console.log(err);
});
};
useEffect(() => {
getPosts();
getLoginID();
}, [flug]);
const getSearchResult = async (data) => {
console.log(data.search);
console.log(apiURL + "posts/?search=" + data.search);
await axios
.get(apiURL + "posts/?search=" + data.search, {
headers: {
"Content-Type": "application/json",
},
})
.then((result) => {
setLen(result.data.length);
setPost(result.data);。
setInitial(false);
})
.catch((err) => {
console.log(err);
});
};
return (
<div className="container">
<div className="row text-center justify-content-center">
{isLoggedIn ? (
<p className="top_hello">Hello {username}!</p>
) : (
<p className="top_hello">Hello Guest!</p>
)}
<div className="top_search col-10 col-lg-12">
<form
className="top_search_input form-inline col-12 col-lg-4"
onSubmit={handleSubmit(getSearchResult)}
>
<input
placeholder="Search Title or Maker"
className="form-control"
{...register("search", { required: true })}
/>
<input className="btn btn-secondary" type="submit" value="Search" />
</form>
</div>
{len >= 1 ? (
initial_screen ? (
<>
{post.map((item, i) => (
<div key={i} className="top_post col-6 col-lg-3">
<div className="slideshow-container">
{item.photo && (
<div className="mySlides fade">
<img className="top_post_photo" src={item.photo} />
</div>
)}
{item.photo2 && (
<div className="mySlides fade">
<img className="top_post_photo" src={item.photo2} />
</div>
)}
{item.photo3 && (
<div className="mySlides fade">
<img className="top_post_photo" src={item.photo3} />
</div>
)}
{item.photo4 && (
<div className="mySlides fade">
<img className="top_post_photo" src={item.photo4} />
</div>
)}
{item.photo5 && (
<div className="mySlides fade">
<img className="top_post_photo" src={item.photo5} />
</div>
)}
<a className="prev" onclick="plusSlides(-1)">
❮
</a>
<a className="next" onclick="plusSlides(1)">
❯
</a>
</div>
<p>Title: {item.title}</p>
<p>Condition: {item.condition_name}</p>
<Link to={`/post/${item.id}`} className="btn btn-secondary">
Detail
</Link>
</div>
))}
</>
) : (
<>
{post.map((item, i) => (
<div key={i} className="top_post col-6 col-lg-3">
{item.photo && (
<img className="top_post_photo" src={item.photo} />
)}
{item.photo2 && (
<img className="top_post_photo" src={item.photo2} />
)}
{item.photo3 && (
<img className="top_post_photo" src={item.photo3} />
)}
{item.photo4 && (
<img className="top_post_photo" src={item.photo4} />
)}
{item.photo5 && (
<img className="top_post_photo" src={item.photo5} />
)}
<p>Title: {item.title}</p>
<p>Condition: {item.condition_name}</p>
<Link to={`/post/${item.id}`} className="btn btn-secondary">
Detail
</Link>
</div>
))}
<button
onClick={() => setFlug(!flug)}
className="btn btn-secondary"
>
Back
</button>
</>
)
) : (
<div>
<p>{len}</p>
<p>not found!</p>
<button
onClick={() => setFlug(!flug)}
className="btn btn-secondary"
>
Back
</button>
</div>
)}
</div>
</div>
);
};
export default Top;
CSS
* Top.js */
.top_hello {
text-align: right;
margin: 20px 0 0 0;
}
.top_search {
margin: 20px 0 20px 0;
justify-content: right;
}
.top_search_input {
display: flex;
margin-right: 0;
margin-left: auto;
}
.top_post {
/* position: relative; */
background:rgb(209, 255, 209);
padding:15px;
border-radius: 10px;
margin-bottom: 30px;
width: 250px;
height: 400px;
/* margin: 10px; */
}
.top_post_photo {
object-fit: cover;
width: 200px;
height: 200px;
}
/* Slideshow container */
.slideshow-container {
max-width: 200px;
position: relative;
margin: auto;
}
/* Hide the images by default */
.mySlides {
display: none;
}
/* Next & previous buttons */
.prev, .next {
cursor: pointer;
position: absolute;
top: 50%;
width: auto;
margin-top: -22px;
padding: 16px;
color: white;
font-weight: bold;
font-size: 18px;
transition: 0.6s ease;
border-radius: 0 3px 3px 0;
user-select: none;
}
/* Position the "next button" to the right */
.next {
right: 0;
border-radius: 3px 0 0 3px;
}
/* On hover, add a black background color with a little bit see-through */
.prev:hover, .next:hover {
background-color: rgba(0,0,0,0.8);
}
/* Fading animation */
.fade {
animation-name: fade;
animation-duration: 1.5s;
}
#keyframes fade {
from {opacity: .4}
to {opacity: 1}
}
I am new to coding with React.js and monday.com. I am trying to create a weather app that works with monday.com. I want the app to use the location column on the monday.com board to display the weather data for a specific city. My api seems to work just fine and gives the weather results when I enter a city into my app. The below error occurred once I started to try and get the app to work with the monday.com board.
I have an import/export error. I have checked all my opening and closing brackets but they all seem correct. Please advise how I can fix this problem. Thanks!
Error:
Error in ./src/reportWebVitals.js
Syntax error: C:/Users/E7470/weather-app/src/reportWebVitals.js: 'import' and 'export' may only appear at the top level (3:4)
1 |
const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
> 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
| ^
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
# ./src/index.js 19:23-51
App.js:
import React, { useState } from 'react';
import './App.css';
import mondaySdk from 'monday-sdk-js';
import 'monday-ui-react-core/dist/main.css';
//Explore more Monday React Components here: https://style.monday.com/
import AttentionBox from 'monday-ui-react-core/dist/AttentionBox.js';
const monday = mondaySdk();
function App() {
const apiKey = 'API KEY'; //I inserted my api key here
const [weatherData, setWeatherData] = useState([{}]);
const [city, setCity] = useState('');
const [context, setContext] = useState();
const [weatherArr, setWeatherArr] = useState();
useEffect(() => {
const getContext = async () => {
try {
monday.listen('context', (res) => {
console.log(res.data);
getBoards(res.data);
setContext(res.data);
});
monday.listen("settings", (res) => {
console.log(res.data);
setMeasurementUnit(res.data.dropdown)
})
//board id (Add board Id Here eg.328567743)
} catch (err) {
throw new Error(err);
}
};
getContext();
}, []);
const getBoards = async (context) => {
try {
var arr = [];
var boards = [];
for( const boardId of context.boardIds){
var res = await monday.api(`query { boards(limit:1, ids:[${boardId}]) {
name
items {
name
column_values {
id
value
text
}
}
}
}`);
boards.push(res.data.boards);
}
for (const board of boards ){
console.log(boards)
console.log(board)
for (const item of board[0].items){
var location = item.column_values[0].text;
var latLng = item.column_values[0].value
var itemObj = {
location,
latLng
}
const getWeather = (event) => {
if (event.key == 'Enter') {
fetch(
`https://api.openweathermap.org/data/2.5/weather?q=${city}&units=imperil&APPID=${apiKey}` //api given in video tutorial
)
.then((response) => response.json())
.then((data) => {
setWeatherData(data);
setCity('');
});
}
};
setWeatherArr(arr);
} catch (err) {
throw new Error(err);
}
};
return (
<div className="container">
<input
className="input"
placeholder="Enter City..."
onChange={(e) => setCity(e.target.value)}
value={city}
onKeyPress={getWeather}
/>
{typeof weatherData.main === 'undefined' ? (
<div>
<p>Welcome to weather app! Enter the city you want the weather of.</p>
</div>
) : (
<div className="weather-data">
<p className="city">{weatherData.name}</p>
<p className="temp">{Math.round(weatherData.main.temp)}℉</p>
<p className="weather">{weatherData.weather[0].main}</p>
</div>
)}
{weatherData.cod === '404' ? <p>City not found.</p> : <></>}
</div>
);
}
export default App;
App.css:
.container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 25px;
}
.input {
padding: 15px;
width: 80%;
margin: auto;
border: 1px solid lightgrey;
border-radius: 6px;
font-size: 16px;
}
.input:focus{
outline: none;
}
.weather-data{
margin-top: 30px;
display: flex;
flex-direction: column;
align-items: center;
}
.city{
font-size: 30px;
font-weight: 200;
}
.temp{
font-size: 90px;
padding: 10px;
border: 1px solid lightgray;
border-radius: 12px;
}
.weather{
font-size: 30px;
font-weight: 200;
}
I am using nextjs to compile my code and antd framework. I am unable to style the positioning of my button, also I want my start button to trigger a set of buttons but for some reason it does not work. Below is my code
import React, { Component } from "react";
import Layout from "./Layout";
import { Radio } from "antd";
export default class PositiveAffirmation extends Component {
state = {
changeButton: false
};
toggleChangeButton = e => {
this.setState({
changeButton: e.target.value
});
};
render() {
const { changeButton } = this.state;
return (
<Layout>
<Radio.Group
defaultValue="false"
buttonStyle="solid"
onChange={this.changeButton}
className="radio-buttons"
>
<Radio.Button value={true}>Start</Radio.Button>
<Radio.Button value={false}>Stop</Radio.Button>
</Radio.Group>
{changeButton && (
<Button.Group size={size}>
<Button type="primary">Happy</Button>
<Button type="primary">Sad</Button>
<Button type="primary">Fullfiled</Button>
</Button.Group>
)}
<style jsx>{`
Radio.Button {
font-size: 100px;
margin-left: 20px;
margin-top: 5px;
margin-bottom: 5px;
display: flex;
justify-content: center;
}
`}</style>
</Layout>
);
}
}
you are calling just wrong fn change onChange={this.changeButton} to onChange={this.toggleChangeButton}
I am trying to style the list and sublist menu. Some list items have name and some list items having sublist items having svg added infront of list item. in doing so, the list item without sublist item is not indented correctly. how can i achieve it. could somebody help me. Below is what i have tried.
return (
{this.props.expanded &&
<Drawer className="drawer">
<header>
<h4>List items</h4>
</header>
<ListItems listitemss={this.props.listitems} />
</Drawer>
}
</div>
);
};
}
class ListItemss extends React.PureComponent {
render() {
return <ul className="listitems_list">
<div className="lists">
{this.props.layers.map((list, index) => {
return <List key={index} list={list} />
})}
</div>
</ul>
}
}
class List extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
expanded: false,
hidden: false,
};
}
expand = () => {
this.setState({expanded: true});
};
collapse = () => {
this.setState({expanded: false});
};
hide_layer = () => {
this.setState({hidden: true});
};
show_layer = () => {
this.setState({hidden: false});
};
render() {
return <li>
<div className="list">
{this.props.list.children && !this.state.expanded &&
<SvgAccDown width="14" height="8" onClick={this.expand} />
}
{this.props.list.children && this.state.expanded &&
<SvgAccUp width="20" height="18" onClick={this.collapse} />
}
<span>{this.props.list.name}</span>
</div>
{this.props.list.children && this.state.expanded &&
<ListItems lists={this.props.list.children}/>
}
</li>;
}
}
.listitems_list {
height: 100%;
overflow: auto;
.lists {
height: 100%;
margin-left: 12px;
overflow: auto;
.list {
background-color: #fff;
display: flex;
flex-direction: row;
align-items: center;
cursor: pointer;
span {
padding-right: 12px;
padding-top: 12px;
padding-bottom: 12px;
padding-left: 2px;
font-size: 16px;
font-weight: bold;
}
}
}
}
If it is an external CSS file, and you are using something like Create React App, you can just import 'mystyle.css;`
Supposed to look like the below (does in Edge & Chrome):
But looks like this in Safari 10:
I've read a few SO questions that have not help resolve the issue. Most recently this one:
Flexbox not working on button or fieldset elements
The answers are not resolving my issue.
How do I get a new button to wrap to a new line instead of overflowing the container?
Here is the Sass and ReactJS component I have. Also, I am using Bootstrap 4.
class BasicQueryCuts extends Component {
constructor(props) {
super(props);
this.state = {
cuts: {}
}
this.clearSelection = this.clearSelection.bind(this);
this.selectAll = this.selectAll.bind(this);
}
clearSelection() {
this.setState({
cuts: {}
})
this.props.clearCuts();
}
// pieces together the cuts that are selected
onCutSelect(cut, str) {
// want to make sure it stays a number
// so that it matches the server data
// tends to convert to string if not specific
cut = Number(cut);
this.setState(
({cuts: prevCuts}) => (
this.state.cuts[cut] && str !== 'all'
?
{cuts: {...prevCuts, [cut]: undefined }}
:
{cuts: {...prevCuts, [cut]: cut }}
),
() => this.props.basicQueryResults(this.state.cuts)
)
}
selectAll() {
const { country } = this.props;
let { query_data } = this.props;
if (query_data) {
if (query_data[0].Country && country) {
var data = _.filter(query_data, {'Country': country});
} else {
var data = query_data;
}
}
_.map(
data, c => {
this.onCutSelect(c.SortOrder, 'all');
}
)
}
// These buttons will allow selecting everything, or clearing the selection
renderAllNothingButtons() {
let { query_data } = this.props;
// generate the list of cuts
if (query_data) {
return (
<Row>
<Col>
<Button color='primary' key='all' className='cuts-btn' onClick={this.selectAll}>
Select All
</Button>
</Col>
<Col>
<Button color='danger' key='cancel' className='cuts-btn' onClick={this.clearSelection}>
Clear All
</Button>
</Col>
</Row>
)
}
}
// renders the cut multi-list, by first ordering what comes from
// the server and then depending on the survey
// setting up the option and value keys
renderCutsButtons() {
const { country } = this.props;
let { query_data } = this.props;
if (query_data) {
if (query_data[0].Country && country) {
var data = _.filter(query_data, {'Country': country});
} else {
var data = query_data;
}
}
// generate the list of cuts
return (
<Row>
{_.map(data, c => {
var cut = c.RptCutCat + ': ' + c.RptCut
return (
<Col key={c.SortOrder}>
<Button
className={this.state.cuts[c.SortOrder] ? 'cuts-btn-active' : 'cuts-btn'}
key={c.SortOrder}
value={c.SortOrder}
onClick={event => this.onCutSelect(event.target.value, 'single')}
>
<span>{cut}</span>
</Button>
</Col>
)}
)}
</Row>
)
}
render() {
const { query_data } = this.props;
return (
<div className='results-bq-cuts'>
{this.renderCutsButtons()}
{query_data
?
<hr />
:
null
}
{this.renderAllNothingButtons()}
{query_data
?
<hr />
:
null
}
</div>
)
}
}
.results-modal {
#media all and (max-width: 1250px) {
max-width: 95%;
}
max-width: 1200px;
.modal-content {
.modal-body {
// padding: 0;
margin-left: 13px;
margin-right: 13px;
.results-bq-cuts {
.col {
padding:2px;
}
.cuts-btn {
font-size: 11px;
padding: 3px;
width: 100%;
box-shadow: none;
}
.cuts-btn-active {
font-size: 11px;
padding: 3px;
width: 100%;
background-color: $croner-blue;
box-shadow: none;
}
h5 {
text-align: left;
}
hr {
margin-top: 5px;
margin-bottom: 5px;
}
}
}
}
}
Compiled HTML here:
Turns out it was an issue with Safari 10.0.0. Upgraded the VM I have macOS running in which upgraded Safari and now the issue is gone. Saw some responses that seemed to indicate the issue was addressed in Safari 10.1.