So I'm having an issue dynamically passing the background colour of a button to an styled component I have defined. If I import the styled component as follows:
import styled from 'styled-components';
const CartQuantityButton = styled.button`
background: ${props => props.background};
...
`;
export default CartQuantityButton;
Mycomponent .js
import CartQuantityButton from './styles/CartQuantityButton';
return (
<CartItemStyles>
<Mutation
mutation={UPDATE_CART_ITEM_MUTATION}
variables={this.state}
>
{(updateCartItem, { loading, error }) => {
return (
<Form2>
<table width="100%" border="0" cellPadding="0">
<tr>
<td><CartQuantityButton background={loading ? 'grey' : 'red'} type="submit">Updat{loading ? 'ing' : 'e'}</CartQuantityButton></td>
</tr>
</table>
</Form2>
)
}}
</Mutation>
</CartItemStyles>
)
everything works as expected, the background colour switches from red to grey. But if I define the styled component as part of MyComponent.js, as follows:
const Form2 = styled.form`
...
button,
input[type='submit'] {
background: ${props => props.background};
}
`;
return (
<CartItemStyles>
<Mutation
mutation={UPDATE_CART_ITEM_MUTATION}
variables={this.state}
>
{(updateCartItem, { loading, error }) => {
return (
<Form2>
<table width="100%" border="0" cellPadding="0">
<tr>
<td><button background={loading ? 'grey' : 'red'} type="submit">Updat{loading ? 'ing' : 'e'}</button></td>
</tr>
</table>
</Form2>
)
}}
</Mutation>
</CartItemStyles>
)
the background colour of the <button/> isn't picked up. What am I overlooking here?
Related
I am using react bootstrap table to show my data. The table is not responsive and has a over-proportioned size on the right side.
Look also at the picture showing that the table is much larger than the other components.
I have tried to include a few css elements such as container, width, max-width, among others however nothing worked.
I am importing the Bootstrap CSS using this: import 'bootstrap/dist/css/bootstrap.min.css';
Thanks in advance.
index.jsx
import React from 'react'
import '../../../../src/styles.css'
export default function Datatable({ data }) {
const columns = data[0] && Object.keys(data[0]);
return (
<table class="table" >
<thead class=" table-striped table-bordered table-sm ">
<tr >{data[0] && columns.map((heading) => <th>{heading}</th>)}</tr>
</thead>
<tbody class=" table-striped table-bordered table-sm " >
{data.map((row) => (
<tr>
{ columns.map((column) => (
<td>{row[column]}</td>
))}
</tr>
))}
</tbody>
</table>
);
}
styles.css
body {
background: #fafafa;
}
table {
background: #f89c9c;
font-size: 14px;
text-align: center;
}
thead {
font-size: 20px;
}
Base.js
import React from 'react';
import Menu from "./Menu"
import Button from "react-bootstrap/Button";
import Container from "react-bootstrap/container";
import Row from "react-bootstrap/row";
const Base = ({
title = "My Title",
description = "My description",
className = "",
children
}) => {
return (
<div>
<Menu />
<Container fluid className="bg-light" >
<Container fluid >
<div className="col bg-light text-dark text-left pt-5" >
<Row >
<h2 className="col-9 display-4 ml-0 font-weight-bold">{title}</h2>
<Button variant="link" className=" btn bg-light text-dark font-weight-bold">Investor</Button>
<Button variant="link" className="btn bg-light text-dark font-weight-bold">Borrower</Button>
<Button variant="link" className=" btn bg-light text-dark font-weight-bold">Charity</Button>
</Row>
<p className=" lead ml-0 font-weight-bold">{description}</p>
</div>
</Container>
<div className={className}>{children}</div>
</Container >
<footer className="footer bg-dark mt-auto py-3">
UserDashboard.js
import React, {useState, useEffect} from 'react';
import Base from '../core/Base'
import './helper/EnhancedTable';
import { Dash } from './helper/EnhancedTable'
const UserDashboard = () => {
return (
<Base title="User dashboard">
<Dash ></Dash>
</Base>
)
}
export default UserDashboard;
Table.js
import {API} from "../../backend"
import React, {useState, useEffect} from 'react';
import Datatable from './datatable';
require("es6-promise").polyfill();
require("isomorphic-fetch");
export default function Dash() {
const [data, setData] = useState([]);
//now we create the quesry state
const [q, setQ] = useState("");
const [searchColumns, setSearchColumns] = useState(["description", "borrower_name"]);
//this is the function that we want tpo fire when the dependencies are triggered
useEffect(() => {
//fetch will make the call to the server
fetch(`${API}project/`, {method: "GET"})
//then response will handle answer from server transforming the HTTP data into JSON data
.then((response) => response.json())
//now that we access to the JSON data from server we will get if from the local storage
.then((json) => setData(json))
}, []);
function search(rows) {
return rows.filter(
(row ) =>
searchColumns.some(column => row[column].toString().toLowerCase().indexOf(q.toLowerCase()) > -1
)
);
}
const columns = data[0] && Object.keys(data[0])
return (
<div>
<input type="text" value={q} onChange={(e) => setQ(e.target.value) }/>
{
columns && columns.map(column =>
<label>
<input
type="checkbox"
checked={searchColumns.includes(column)}
onChange={(e) => {
const checked = searchColumns.includes(column);
setSearchColumns((prev) => checked
? prev.filter((sc) => sc !== column)
: [...prev, column]
);
}}
/>
{column}
</label>)
}
<Datatable data={search(data)} />
</div>
)
}
export {Dash};
I am attempting to create a Gutenberg block to track exercise sets. I'm using a RichText component to allow users to edit default values in a table I pre-populate for them.
The block works well on the editor and, after saving, renders correctly in the post. However, when I reload the editor, I receive this error message: Block validation: Expected tag name 'thead', instead saw 'table'. It's almost like Gutenberg is stripping the table tag but leaving everything else.
Of course, that doesn't make sense, but I'm not sure what else it could be.
Here's my code, heavily edited for readability:
const { registerBlockType } = wp.blocks;
const { AlignmentToolbar, BlockAlignmentToolbar, BlockControls, RichText, useInnerBlockProps } = wp.blockEditor;
const { Component } = wp.element;
registerBlockType('bsd-strong-post/training-session', {
title: __('Strong Post', 'bsd-strong-post'),
description: __('Provides a short summary of a training session', 'bsd-strong-post'),
category: 'common',
icon: blockIcons.weight_lifting,
keywords: [
__('strength workout', 'bsd-strong-post'),
__('strong', 'bsd-strong-post'),
__('training', 'bsd-strong-post')
],
supports: {
html: true
},
attributes: {
/* ... */,
dayTemplateContent: {
type: 'string',
source: 'html',
selector: '.bsd-strong-post-training-template'
},
/* ... */
},
/* ... */
edit: class extends Component {
constructor(props) {
super(...arguments);
this.props = props;
/* ... */
this.dayTemplateHandler = this.dayTemplateHandler.bind(this);
this.onChangeBlockTemplate = this.onChangeBlockTemplate.bind(this);
}
/* ... */
dayTemplateHandler(new_val) {
const dayTemplateList = this.state.dayTemplateList;
let selectedDayTemplate = dayTemplateList.filter(item => {
return item.value == new_val;
})
if (selectedDayTemplate[0]['label']) {
this.props.setAttributes({
dayTemplateId: new_val,
dayTemplateName: selectedDayTemplate[0]['label']
});
}
this.getTemplate(new_val);
}
getTemplate(templateId) {
api.getDayTemplate(templateId)
.then((data) => {
if (!data.status || data.status == 0) {
return false;
};
if (!data.day_template) {
return false;
};
this.props.setAttributes({
dayTemplateContent: data.day_template.template_content
});
return data.day_template;
}).catch((err) => {
console.log('getTemplate caught error')
return false;
});
}
onChangeBlockTemplate(value) {
this.props.setAttributes({
dayTemplateContent: value
});
}
/* ... */
render() {
const { dayTemplateHandler, onChangeBlockTemplate, phaseControlHandler, programControlHandler, updateBlockAlignment, updateTextAlignment } = this;
const { block_alignment, dayTemplateId, dayTemplateName, dayTemplateContent, phaseId, phaseName, programAuthor, programId, programName, programPhases, text_alignment } = this.props.attributes;
/* ... */
return [
<InspectorControls>
<PanelBody title={ __('Basics', 'bsd-strong-post') }>
<SelectControl
label={ __('Day', 'bsd-strong-post') }
help={ __('The training session (e.g., Day One)', 'bsd-strong-post') }
value={ dayTemplateId }
options={ this.state.phaseTemplates }
onChange={ dayTemplateHandler }
/>
}
</PanelBody>
</InspectorControls>,
<div className='bsd-strong-post-block-editor'>
<div className={ this.props.className }>
<RichText
placeholder={ __('Log your lifts here') }
value={ dayTemplateContent }
multiline={ false }
onChange={ onChangeBlockTemplate }
className='bsd-strong-post-training-log'
/>
</div>
</div>
];
}
},
save: (props) => {
return (
<div className={ `align${props.attributes.block_alignment}` }>
<ul className='list-unstyled'style={{ textAlign: props.attributes.text_alignment }}>
<li>
<strong>{ __('Program', 'bsd-strong-post') }: </strong>
<span className='bsd-strong-post-program'>{ props.attributes.programName }</span>
</li>
<li>
<strong>{ __('Phase', 'bsd-strong-post') }: </strong>
<span className='bsd-strong-post-phase-ph'>{ props.attributes.phaseName }</span>
</li>
<li>
<strong>{ __('Day', 'bsd-strong-post') }: </strong>
<span className='bsd-strong-post-day-ph'>{ props.attributes.dayTemplateName }</span>
</li>
<li>
<strong>{ __('Author', 'bsd-strong-post') }: </strong>
<span className='bsd-strong-post-author-ph'>{ props.attributes.programAuthor }</span>
</li>
</ul>
<RichText.Content
value={ props.attributes.dayTemplateContent }
className='bsd-strong-post-training-log'
/>
</div>
)
}
});
Here's the console output on reload:
Content generated by 'save' function:
<div class="wp-block-bsd-strong-post-training-session alignwide"><ul class="list-unstyled"><li><strong>Program: </strong><span class="bsd-strong-post-program">Madcow</span></li><li><strong>Phase: </strong><span class="bsd-strong-post-phase-ph">Intermediate</span></li><li><strong>Day: </strong><span class="bsd-strong-post-day-ph">Day 1</span></li><li><strong>Author: </strong><span class="bsd-strong-post-author-ph">Madcow</span></li></ul>
<thead>
<tr>
<th scope="col">Exercise</th>
<th scope="col">Set 1</th>
<th scope="col">Set 2</th>
</tr>
</thead>
<tbody>
<tr class="bsd-strong-post-exercise-one">
<td class="bsd-strong-post-exercise-name">Squat</td>
<td class="bsd-strong-post-set-1">95 x 5</td>
<td class="bsd-strong-post-set-2">135 x 5</td>
</tr>
</tbody>
</div>
Content retrieved from post body:
<div class="wp-block-bsd-strong-post-training-session alignwide"><ul class="list-unstyled"><li><strong>Program: </strong><span class="bsd-strong-post-program">Madcow</span></li><li><strong>Phase: </strong><span class="bsd-strong-post-phase-ph">Intermediate</span></li><li><strong>Day: </strong><span class="bsd-strong-post-day-ph">Day 1</span></li><li><strong>Author: </strong><span class="bsd-strong-post-author-ph">Madcow</span></li></ul><table class='bsd-strong-post-training-template'>
<thead>
<tr>
<th scope='col'>Exercise</th>
<th scope='col'>Set 1</th>
<th scope='col'>Set 2</th>
</tr>
</thead>
<tbody>
<tr class='bsd-strong-post-exercise-one'>
<td class='bsd-strong-post-exercise-name'>Squat</td>
<td class='bsd-strong-post-set-1'>95 x 5</td>
<td class='bsd-strong-post-set-2'>135 x 5</td>
</tr>
</tbody>
</table></div>
I can see that the content displayed below Content generated by 'save' function: is missing the <table> and </table> tags. I've tried to work around this by adding tagName='table' in the RichText.Content properties inside the save function, but then the console shows duplicate <table> and </table> tags.
EDIT: The table is populated when a user makes a change to the Select control in InspectorControls. This action calls dayTemplateHandler, which among other things, calls getTemplate, a function that gets the content of the table from the database. Here's an example of that output (data.day_template.template_content):
<table class='bsd-strong-post-training-template'>
<thead>
<tr>
<th scope='col'>Exercise</th>
<th scope='col'>Set 1</th>
<th scope='col'>Set 2</th>
</tr>
</thead>
<tbody>
<tr class='bsd-strong-post-exercise-one'>
<td class='bsd-strong-post-exercise-name'>Squat</td>
<td class='bsd-strong-post-set-1'>95 x 5</td>
<td class='bsd-strong-post-set-2'>135 x 5</td>
</tr>
</tbody>
</table>
On reviewing the table template and considering the error, I suspect the issue is the selector of the dayTemplateContent attribute, .bsd-strong-post-training-template
The first time the content is saved, it successfully loads the template data from database and saves the complete table structure. When the content is reloaded, the block validator fails as the selector of dayTemplateContent reads in the child nodes of the table's css selector (which is thead) and doesn't match expected content. Ref: HTML example of blockquote/paragraphs
Try wrapping the <table> template with a <div class="bsd-strong-post-training-template"> or changing the selector.
I have a material ui table and I would like to colour the different cells according to what value is displayed in them. The cells are populated with json data using map. For example if a cell has the value 1, I would like the colour to be yellow.
{
Name: "A Person",
Attendence: [
{
date: "2019/12/01",
attendence: 1
},
{
date: "2019/12/02",
attendence: 1
},
{
date: "2019/12/03",
attendence: 0
}
]
}
];
return (
<Fragment>
{attendence.map(person => {
return (
<Table>
<thead>
<tr>
<th>Name</th>
{person.Attendence.map(personAttendendance => {
return <th>{personAttendendance.date}</th>;
})}
</tr>
</thead>
<tbody>
<tr>
<td>{person.Name}</td>
{person.Attendence.map(personAttendendance => {
return <td>{personAttendendance.attendence}</td>;
})}
</tr>
</tbody>
</Table>
);
})}
</Fragment>
);
}
export default Test;
That is what the table looks like. I tried
if(value === 1){
return(
<TableCell style={{ background: "red" }}>{value}</TableCell>
)
} else {
return(
<TableCell style={{ background: "red" }}>{value}</TableCell>
)
}
}
But that did not work . It just read the else and made everything red.
Change your tbody in test.js to:
<tbody>
<tr>
<td>{person.Name}</td>
{person.Attendence.map(personAttendendance => {
if(personAttendendance.attendence === 1){
return <td style={{background: "red" }}>{personAttendendance.attendence}</td>;
} else {
return <td style={{background: "blue" }}>{personAttendendance.attendence}</td>;
}
})}
</tr>
</tbody>
or
<tbody>
<tr>
<td>{person.Name}</td>
{person.Attendence.map(personAttendendance => {
return <td style={{background: personAttendendance.attendence === 1 ? "red" : "blue"}}>{personAttendendance.attendence}</td>;
})}
</tr>
</tbody>
Which ever suits you best.
Link to fork here. (using the second example)
I would like to have a modal that will pop up when a table row is clicked. The modal is opening when I click a row in my table component. However I'm not getting the desired result with the css. I want it to overlap everything that is on the page when a row is clicked. Right now it's showing on top of the page and I cant see the content in it.
//Modal.js
import React from "react";
import Table from "react-bootstrap/Table";
export default function Modal() {
return (
<div className="modalContainer">
<Table responsive="true" size="sm" striped bordered hover>
<thead>
<tr>
<th>Own Product</th>
<th>Competitors Products</th>
</tr>
</thead>
<p>Brand</p>
<p>Category</p>
<p>In Stock</p>
<p>Name</p>
<p>Price</p>
<p>Product Code</p>
<p>Product Link</p>
</Table>
</div>
);
}
//Code from Table.js
render() {
let { isLoaded, products } = this.state; //instead of typing
this.state all the time
if (!isLoaded) {
return <Loading />;
} else {
return (
<div className="tableContainer">
{this.props.rows}
<Table responsive="true" size="sm" striped bordered hover>
<thead>
<tr>
<th>Product ID</th>
<th>Product Name</th>
<th>Match ID</th>
<th>Match Score</th>
<th>Match Name</th>
<th>Match Price</th>
<th>Match State</th>
</tr>
</thead>
<tbody>
{products.map(product => (
//use filter instead to show only the matched ones
<tr key={product.id} onClick={() => this.toggleModal()}>
<td>{product.id}</td>
<td>{product.name}</td>
<td>{product.matches[0].id}</td>
<td>{Math.round(product.matches[0].score)}</td>
<td>{product.matches[0].name}</td>
<td>{product.matches[0].price}</td>
<td>{product.matches[0].matchLabel}</td>
</tr>
))}
{this.state.modalOpen ? <Modal /> : null}
</tbody>
</Table>
</div>
);
}
}
//CSS
.tableContainer {
position: relative;
width: 100%;
height: 100%;
}
.modalContainer {
margin: -30% auto;
position: absolute;
width: 100%;
height: 100%;
justify-content: center;
border: 1px solid black;
z-index: 1;
left: 0;
top: 0;
overflow: auto;
background-color: rgba(219, 239, 250);
}
The issue is that your tableContainer is position:relative, which re-sets the positioning context for its children. So, your <Modal> is absolutely positioned with respect to the tableContainer instead of the browser window.
You can either change your css to so your Modal is e.g. position:fixed or move your modal out of your tableContainer like this:
return (
<>
{this.state.modalOpen ? <Modal /> : null}
<div className="tableContainer">
{this.props.rows}
<Table responsive="true" size="sm" striped bordered hover>
//....//
</Table>
</div>
</>
State for modal
state = {
axiosStatus: {
status: '',
title: '',
details: '',
},
modal: false,
}
modal handler
modalHandler = ()=> {
this.setState({modal: !this.state.modal});
};
modal content hander
axiosStatusHandler = (status, title, details)=>{
let oldState = this.state.axiosStatus;
oldState.status = status;
oldState.title = title;
oldState.details = details;
this.setState({axiosStatus: oldState});
};
Jsx for modal
<Modal show={this.state.modal} modalClosed={this.modalHandler}>
<ModalContent
status = {this.state.axiosStatus.status}
title = {this.state.axiosStatus.title}
details = {this.state.axiosStatus.details}
/>
</Modal>
Modal Component
import React from 'react';
import './Modal.css';
import Aux from '../../../hoc/Auxi';
import Backdrop from '../Backdrop/Backdrop';
const Modal = ( props ) => (
<Aux>
<Backdrop show={props.show} clicked={props.modalClosed} />
<div
className={"Modal"}
style={{
transform: props.show ? 'translateY(0)' : 'translateY(-100vh)',
opacity: props.show ? '1' : '0'
}}>
{props.children}
</div>
</Aux>
);
export default Modal;
Backdrop Component
import React from 'react';
import './Backdrop.css';
const backdrop = (props) => (
props.show ? <div className={"Backdrop"} onClick={props.clicked}></div> : null
);
export default backdrop;
Backdrop css
.Backdrop {
width: 100%;
height: 100%;
position: fixed;
z-index: 100;
left: 0;
top: 0;
background-color: rgba(0, 0, 0, 0.5);
}
ModalContenet Component
import React from 'react';
const ModalContent = (props)=>{
return (
<div style={{textAlign: 'center'}}>
{/* <h3 style={{color: '#FF0000'}}>Failed</h3>*/}
<b><h2 style={{color: '#FF0000'}}>{props.title}</h2></b>
<h2 style={{color: '#FF0000'}}>{props.details}</h2>
</div>
)
};
export default ModalContent;
I have 2 different pages and 2 different css (one for each html page) and if i modify .table{} in one of them, the css is applied on all pages. I use react bootstrap
I expect to have one table from page1 at 100% width and the table from page2 at 33.3% width.
page2:
import React from 'react';
import Container from "react-bootstrap/Container";
import {Jumbotron} from "react-bootstrap";
import Row from "react-bootstrap/Row";
import Col from "react-bootstrap/Col";
import Image from "react-bootstrap/Image"
import ProgressBar from "react-bootstrap/ProgressBar"
import Table from "react-bootstrap/Table"
import './Doctor.css'
export default class Doctor extends React.Component {
constructor(props){
super(props);
this.state = {
items: [],
isLoaded: false,
}
}
componentDidMount() {
fetch('http://localhost:8000/api/doctorsList')
.then(res => res.json())
.then(json => {
this.setState({
isLoaded: true,
items: json,
})
});
}
render() {
var { isLoaded, items} = this.state;
if (!isLoaded){
return <div>Loading...</div>
}else {
return (
<Container>
<Jumbotron>
<h1 align="center">The Clinicum</h1>
</Jumbotron>
<Row>
{items.map(row =>(
<Col className={".column"} key={row.iddoctor}>
<Image src={require('./photos/dr1.jpg')} roundedCircle />
<p>Raiting:</p>
<ProgressBar>
<ProgressBar striped variant="success" now={70} key={1} label={"70%"} />
<ProgressBar striped variant="danger" now={30} key={2} label={"30%"} />
</ProgressBar>
<br/>
<Table striped bordered hover >
<tbody>
<tr>
<td>Name</td>
<td>{row.nume}</td>
</tr>
<tr>
<td>An absolvire</td>
<td>{row.anAbsolvire}</td>
</tr>
<tr>
<td>Specializare</td>
<td>{row.specializare}</td>
</tr>
<tr>
<td>Telefon</td>
<td>{row.photoLink}</td>
</tr>
</tbody>
</Table>
</Col>
))}
</Row>
</Container>
)};
}
}
page1:
import React, {Component} from 'react';
import { Link} from 'react-router-dom';
import {Jumbotron} from 'react-bootstrap';
import './Home.css';
import Container from "react-bootstrap/Container";
import Table from "react-bootstrap/Table";
import {Image} from "react-bootstrap";
class Home extends Component {
constructor(props){
super(props);
this.state = {
items: [],
isLoaded: false,
}
}
componentDidMount() {
fetch('http://localhost:8000/api/clinicList')
.then(res => res.json())
.then(json => {
this.setState({
isLoaded: true,
items: json,
})
});
}
render() {
var { isLoaded, items} = this.state;
if (!isLoaded){
return <div>Loading...</div>
}else {
return (
<Container>
<Jumbotron>
<h1 align="center">The Clinicum</h1>
</Jumbotron>
<Table className="table">
<thead>
<tr>
<th>Name</th>
<th>Locatie</th>
<th>Tip Unitate</th>
</tr>
</thead>
<tbody>
{items.map(row =>(
<tr key={row.idclinic}>
<td>
<Link to="/doctor">
<Image
src= {require(`./photos/${row.photoLink}.jpg`)}//{row.photoLink}
width="30"
height="30"
className="d-inline-block align-top"
alt={"aa"}
/>{row.name}
</Link>
</td>
<td>{row.locatie}</td>
<td>{row.tipUnitate}</td>
</tr>
))}
</tbody>
</Table>
</Container>
);
}
}
}
export default Home;
at Home.css i have
.table{
width: 100%;
}
at Doctor.css i have
.table{
width: 33.3%;
}
but in Home page the table is 33.3%
React doesn't compartmentalize CSS like Angular does. Once it's loaded in the browser it applies everywhere in the current page. Use additional classes on your tables to specify width.
Better yet, use the grid that Bootstrap provides (.col-xs-4 for 33%).
The order of your import statements will decide on which css file will be used last. However, in your case you should just simply add another marker that points to the change. For instance, in this you have a table className. Add another piece to it like so.
.table{
width: 100%;
border: 1px solid black
}
.home{
width: 33.3%
}
Then, in your JSX you can do this.
<Table className='table home' />
Now your table will have the border, and also the home width. This is the easiest way to modify existing css.
That is the normal behaviour. You have two classes with the same name, which means after React is finished building your dev, or prod environment the second class will overwrite the first one, because that is what CSS does.
There is a view different options for you to make sure that doesn't happen:
define inline styles
use CSS-in-js like this or with libraries like styled-components
define separate css class names (for this i would recommend a naming convention, this can be your own, your companies naming convention, or something like BEM)
Personally i would go for the naming convention BEM. This could look like the following:
.home__table {
width: 100%;
}
.doctor__table {
width: 33%;
}
But since you are using Bootstrap, you might want to use the inline-style option and use the bootstrap provided col sizes like #isherwood suggested.