Unable to change label on input:checked - styled-components

I'm attempting to follow this example (https://codesandbox.io/s/oYQ21A4wz) in a larger form and am really struggling to figure out how to change the label of the input on a :checked state for a styled-component in React. I'm using the 4.2 of styled-components. Any help would be GREATLY appreciated as I've been staring at this for a couple days.
I'm able to get the parent selectors working in other cases (eg: hover) but for some reason I cannot seem to target the Label from its child.
const CheckBoxDoors = props => {
const Label = styled.label`
display: inline-block;
background: rgba(255, 255, 255, 0.9);
border: 2px solid rgba(139, 139, 139, 0.3);
color: #adadad;
border-radius: 25px;
padding: 1px 4px;
margin: 1px;
white-space: nowrap;
`;
const Input = styled.input`
&:checked + ${Label} {
background: blue;
}
`;
return (
<div className="form-group, checkbox">
<CheckboxContainer>
<CheckboxTitle>{props.title}</CheckboxTitle>
<CheckboxGroup>
{props.options.map(option => {
return (
<Label key={option} className="checkbox-inline">
<Input
id={props.value}
name={props.name}
onChange={props.handleChange}
value={props.name + ' ' + option}
checked={
props.selectedOptions.indexOf(props.name + ' ' + option) >
-1
}
type="checkbox"
/>
{option}
</Label>
);
})}
</CheckboxGroup>
</CheckboxContainer>
</div>
);
};

Check this one out:
const Input = styled.input`
&:checked + ${Label} {
background: blue;
}
`;
This rule &:checked + ${Label} means 'when I am checked, the sibling Label component right below me will have these styles'; i.e
<>
<Input id={id}... />
<Label htmlFor={id}... />
</>
However, your component structure looks like this:
<Label>
<Input ... />
</Label>
You'd have to change it to the structure mentioned above.
Also note that you shouldn't declare your styled components inside another component, it'll hurt performance badly. Instead, you should do:
const Input = styled.input` ... `
const Label = styled.label` ... `
const CheckBoxDoors = props => ...

Related

what is difference between '.attrs()' and 'props' in styled-components?

const Input = styled.input.attrs(props => ({
// we can define static props
type: "text",
// or we can define dynamic ones
size: props.size || "1em",
}))`
color: palevioletred;
font-size: 1em;
border: 2px solid palevioletred;
border-radius: 3px;
/* here we use the dynamically computed prop */
margin: ${props => props.size};
padding: ${props => props.size};
`;
render(
<div>
<Input placeholder="A small text input" />
<br />
<Input placeholder="A bigger text input" size="2em" />
</div>
);
This example was taken from an official documentation
but, I think this code is same as follows:
const Input = styled.input`
color: palevioletred;
font-size: 1em;
border: 2px solid palevioletred;
border-radius: 3px;
margin: ${props => props.size};
padding: ${props => props.size};
`;
render(
<div>
<Input placeholder="A small text input" />
<br />
<Input placeholder="A bigger text input" size="2em" />
</div>
);
i don't understand to difference between '.attrs()' and 'props' in styled-components
Use inline styles (via attrs) if there are changes or something,like animation etc.
If styles dont change very often then use styled component with static and dynamic styles
Came across this already answered similar question. Kindly check it out

Axios POST request reloads page even after e.preventDefault() : React

So Im building a dummy social media application for my resume with NodeJS, MongoDB and React. As such, I have a NewPost form in which user can attach videos or images as files and enter their post captions. I have used Multer on Backend and I have tested my route on Postman and BackEnd is working fine. The only problem is that my form wont send the data at all. I have tried e.preventDefault() but as soon as I make POST axios request the page reloads and I get Request Aborted error in console and since the data is not sent to BackEnd, no posts are created.
One more odd thing I noticed is that when the content is image, posts are created- maybe because by the time it reloads, the images are uploaded already. In any case, my BackEnd is fine- only problem is with the form.
Here is my NewPost Component
import React from 'react';
import './NewPost.css';
import { useParams } from 'react-router-dom';
import axios from 'axios';
const NewPost = (props) => {
const params = useParams();
const submitHandler = async (e) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
formData.append('user', params.userId);
console.log(formData.get('user'));
console.log(formData.get('content'));
console.log(formData.get('caption'));
const content = formData.get('content').name;
const imgExt = ['jpg', 'jpeg', 'png', 'avif', 'apng', 'pjp', 'webp', 'svg', 'bmp'];
const ext = content.split('.')[1];
let url;
if (imgExt.includes(ext)) url = `/api/v1/posts/create/contentImage`;
else url = `/api/v1/posts/create/contentVideo`;
try {
const res = await axios.post(url, formData);
if (res.data.status === 'success') {
console.log('Post created successfully!!');
}
} catch (err) {
console.log(err.message);
}
};
return (
<div className="container new-post-box">
<div className="login-form new-post-form">
<button
className="btn-mobile-nav new-post-box-close-btn"
>
<ion-icon name="close" class="overlay-close"></ion-icon>
</button>
<h2 className="heading-secondary heading-login ma-bt-lg">Whats on your mind</h2>
<form className="form form--login" id="login-form" onSubmit={submitHandler}>
<div className="form__group">
<label className="form__label" htmlFor="caption">
Caption
</label>
<input
className="form__input"
id="caption"
type="text"
name="caption"
placeholder="This is an example"
required="required"
/>
</div>
<div className="file-input-box">
<label className="form__label" htmlFor="caption">
Upload Content
</label>
<input
className="form__upload"
type="file"
name="content"
accept="video/*, image/*"
id="content"
/>
<label htmlFor="content" className="form__label fileInput">
Choose file
</label>
</div>
<div className="form__group">
<button className="btn btn--green postSubmitBtn">Submit</button>
</div>
</form>
</div>
</div>
);
};
export default NewPost;
NewPost.css
.form__upload {
width: 0.1px;
height: 0.1px;
opacity: 0;
overflow: hidden;
position: absolute;
z-index: -1;
}
.form__upload:focus + label {
outline: 3px solid #673ab7;
outline-offset: 3px;
}
.form__upload + label {
color: #673ab7;
display: inline-block;
text-decoration: none;
border-bottom: 2px solid #673ab7;
padding: 3px;
-webkit-transition: all 0.2s;
transition: all 0.2s;
cursor: pointer;
}
.form__upload + label:hover {
background-color: #673ab7;
color: #fff;
-webkit-box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.15);
box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.15);
-webkit-transform: translateY(-2px);
transform: translateY(-2px);
}
.new-post-box {
margin: 4rem auto;
}
.form__label {
font-size: 1.6rem;
font-weight: 700;
margin-bottom: 0.75rem;
}
.form__label.fileInput {
margin-bottom: 2.5rem;
font-weight: 600;
}
.postSubmitBtn {
margin: 1rem 11rem;
}
.login-form.new-post-form {
max-width: 51rem;
padding: 4.4rem 7rem;
position: relative;
}
.file-input-box {
display: flex;
align-items: baseline;
gap: 2.4rem;
}
.newpost-caption-closebtn-box {
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.btn-mobile-nav.new-post-box-close-btn {
position: absolute;
top: 20px;
right: 14px;
}
Run it on your local machine and please tell me what Im doing wrong. I have almost completed my project and this is for my resume. Without thi working, my entire 2 months hard work will go to waste! Any suggestions would be appreciated! Thank you for your time.

how to draw excel style data bars in angular?

I want to add databars behind values in the selected column in my grid like the Data Bars Conditional Formatting option in Excel.
This answer show me the thing using jquery data table, Can anyone give me the idea for this in angular 6.
Note: I am not using any 3rd party grid, I have created this grid from my own.
It should look something like this.
Not sure in what scenario you want to add this, but have a look at this:
https://css-tricks.com/css3-progress-bars/
This is classic HTML and CSS "trick" to create a bar which you can define length of.
The basics of it is that you have a "wrapper" element that defines the maximum length, and a "bar" element inside that you set width: [0-100]% and a background color of that.
This would be an example on how to create a 50% wide blue bar.
.wrapper {
width: 100%;
}
.bar {
background: blue;
height: 5px;
}
<div class="wrapper">
<div class="bar" style="width: 50%"></div>
</div>
Use that to create an angular component that you can send you width to, something like this:
import { Component, Input } from '#angular/core';
#Component({
selector: 'app-bar',
template: `
<div class="wrapper">
<div class="bar" [style.width]="width"></div>
</div>
`,
styles: [`
.wrapper {
width: 100%;
}
.bar {
background: blue;
height: 5px;
}
`]
})
export class BarComponent {
#Input() width: number;
}
This will do the job.
#Component({
selector: 'my-app',
template: `
<div class="holder">
<div class="bar" *ngFor="let item of data">
<div #bar class="{{item >= 0 ? 'positive' : 'negative'}}">
<div class="size" [style.width.px]="getWidth(item, bar)">
{{item}}
</div>
</div>
</div>
</div>
`
})
class AppComponent {
maxValue = 100;
data: Number[] = [
10,20,30,-45,90,-90,-80,50,100
]
getWidth(dataItem: number, bar: HTMLElement):number {
return (parseInt(bar.offsetWidth) / this.maxValue) * Math.abs(dataItem);
}
}
CSS:
.holder {
border: 1px solid black;
margin: 10px;
padding: 5px;
width: 200px;
}
.bar {
border: 1px solid grey;
padding: 3px;
margin: 10px 5px;
text-align: center;
}
.positive {
color: blue;
width: 90px;
margin-left: 90px;
}
.negative {
color: red;
width: 90px;
margin-right: 90px;
.size {
margin-left: auto
}
}
.size {
background: green;
}
You can use primeNg data table, and their cell formatting feature, we can format each cell based on certain condition like changing the color or painting it, this may help you.
PrimeNg Cell Style

AutoSizer creates box of size 0 and does not display content

I am trying to add the AutoSizer but keep getting height and width of 0px.
I add the AutoSizer like this:
console.log("width: " + width, "height: " + height);
return (
<div style={{height: '300px'}}>
<AutoSizer>
{({ width, height }) => (
<VirtualScroll
ref="VirtualScroll"
width={width}
height={height}
rowCount={months.length}
rowHeight={this.getMonthHeight}
estimatedRowSize={rowHeight * 5}
rowRenderer={this.renderMonth}
onScroll={onScroll}
scrollTop={this._initScrollTop}
className={classNames(style.root, {[style.scrolling]: isScrolling})}
style={{lineHeight: `${rowHeight}px`}}
overscanRowCount={overscanMonthCount}
/>
)}
</AutoSizer>
</div>
);
The resulting html:
<div class="Cal__Container__listWrapper">
<div style="height: 300px; position: relative;">
<div style="overflow: visible; height: 0px; width: 0px;">
<div aria-label="grid" class="Grid VirtualScroll Cal__List__root" role="grid" tabindex="0" style="line-height: 40px; height: 300px; width: 400px; overflow-x: hidden; overflow-y: auto;">
...
</div>
</div>
</div>
The logs give me:
width: 400 height: 200
If I edit the html of the 0px box in the browser and scroll my box, which by state change then is supposed increases its height, nothing happens. It stays on its manually modified size even if the new height value is being logged to the console.
The console.log statement is outside of your child function, so I'm not sure what it's logging (but it isn't the value passed in by AutoSizer).
It's also worth pointing out that your inner Grid is actually the correct size in your above snippet:
<div style="height: 300px; width: 400px;">
The wrapper <div> around your grid is intentionally sized with a width and height of 0 to enable AutoSizer to expand to fill its parent without stretching it. Its style is also set to overflow: visible to account for this.
So basically- things are working as expected from what you've shown. To get more help than that, I'll probably need you to supply a Plunker.

YUI Tutorial not working

Why does this code from this YUI3 example not work for me?
HTML:
<!-- The original body content is above -->
<div id="form_container">
<form class="yui3-widget-bd" id="theme_form" action="#" method="get">
<fieldset>
<h3>Update Theme</h3>
<label for="font_size">Font size:</label>
<input type="text" size="3" id="font_size" value="16px">
<label for="heading_color">Heading color:</label>
<input type="text" size="12" id="heading_color" value="#005A9C">
<label for="link_hover">Link hover backgound:</label>
<input type="text" size="12" id="link_hover" value="#ffa">
</fieldset>
<input type="submit">
</form>
</div>
Javascript:
// Create a new YUI instance, requiring stylesheet, overlay, slider, and the
// dd-plugin to make the overlay draggable
YUI({
filter: 'raw'
}).use("stylesheet", "overlay", "slider", "dd-plugin", function(Y) {
var myStyleSheet = new Y.StyleSheet(),
overlayContent = Y.one('#form_container'),
overlay, slider, slider_container, fontSizeInput;
// Create the Overlay, using the form container as the contentBox.
// The form is assigned a class yui-widget-bd that will be automatically
// discovered by Overlay to populate the Overlay's body section.
// The overlay is positioned in the top right corner, but made draggable
// using Y.Plugin.Drag, provided by the dd-plugin module.
overlay = new Y.Overlay({
srcNode: overlayContent,
width: '225px',
align: {
points: [Y.WidgetPositionAlign.TR, Y.WidgetPositionAlign.TR]
},
plugins: [Y.Plugin.Drag]
}).render();
// Slider needs a parent element to have the sam skin class for UI skinning
overlayContent.addClass('yui3-skin-sam');
// Progressively enhance the font-size input with a Slider
fontSizeInput = Y.one('#font_size');
fontSizeInput.set('type', 'hidden');
fontSizeInput.get('parentNode').insertBefore(
Y.Node.create('6 <span></span> 36'), fontSizeInput);
slider_container = fontSizeInput.previous("span");
// Create a Slider to contain font size between 6px and 36px, using the
// page's current font size as the initial value.
// Set up an event subscriber during construction to update the replaced
// input field's value and apply the change to the StyleSheet
slider = new Y.Slider({
length: '100px',
min: 6,
max: 36,
value: parseInt(Y.one('body').getStyle('fontSize')) || 13,
after: {
valueChange: function(e) {
var size = e.newVal + 'px';
this.thumb.set('title', size);
fontSizeInput.set('value', size);
myStyleSheet.set('body', {
fontSize: size
});
}
}
}).render(slider_container);
// The color inputs are assigned keyup listeners that will update the
// StyleSheet if the current input value is a valid CSS color value
// The heading input affects all h1s, h2, and h3s
Y.on('keyup', function(e) {
var color = this.get('value');
console.log(color);
if (isValidColor(color)) {
console.log("Valid color", myStyleSheet);
myStyleSheet.set('h1, h2, h3', {
color: color
});
}
}, '#heading_color');
// The link hover affects the background color of links when they are
// hovered. There is no way other than via stylesheet modification to
// change pseudo-class styles.
Y.on('keyup', function(e) {
var color = this.get('value');
if (isValidColor(color)) {
myStyleSheet.set('a:hover', {
backgroundColor: color
});
}
}, '#link_hover');
// Progressive form enhancement complete, now prevent the form from
// submitting normally.
Y.on('submit', function(e) {
e.halt();
}, '#theme_form');
// A rudimentary validator to make sure we're not trying to set
// invalid color values in StyleSheet.
function isValidColor(v) {
return /^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(v) || /^rgb\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\)$/.test(v) || /^[a-z]{3,}$/i.test(v);
}
});
CSS:
/* For supporting browsers, the overlay is rendered semi-transparent with
* fancy rounded corners */
.yui3-overlay {
background: rgba(128,128,128,0.3);
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
padding: 7px;
cursor: move;
}
.yui3-overlay-content {
background: rgba(205,205,205,0.3);
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
padding: 1px;
}
.yui3-overlay form {
background: #f2fbff;
border: 2px solid #fff;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
margin: 0;
padding: 0;
font-size: 13px;
}
.yui3-overlay fieldset {
border: 1px solid #bcd;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
margin: 0;
padding: 20px;
}
.yui3-overlay h3 {
border-bottom: 2px solid #fff;
color: #479;
background: transparent;
margin: 0;
font-size: 175%;
}
.yui3-overlay label {
display: block;
margin: 1.3em 0 0.5ex;
font-weight: bold;
color: #003;
}
.yui3-overlay p {
margin: 2em 0 0;
}
/* override the move cursor for the Slider */
.yui3-overlay .yui3-slider:hover {
cursor: default;
}
I just copied and pasted the code, can anyone help?
Your tag is missing class="yui3-skin-sam yui-skin-sam"
It appears to be working. I copied/pasted your code into this jsfiddle. Change with the slider and header color change field, it seems to update the color and size.
This is not the best forum to do support debugging.
You're welcome to ask in the #yui channel on freenode rather than go through slow, back and forth debugging here.

Resources