react-virtualized Grid.cellRenderer - issues adding style prop - grid

I am using the Grid component and have a cellRenderer. In it I attempt to add a backgroundColor style to the outer div.
customColumnRenderer(props: GridCellProps): React.ReactNode {
...
props.style.backgroundColor = "hotpink";
...
return <div style={props.style}
... </div>;
}
All is good at first, but then I scroll vertically a bit and I get this exception:
Uncaught TypeError: Cannot assign to read only property 'backgroundColor' of object '#<Object>'
When I look in the debugger. props.style looks like a simple Object to me. The doc says
"You can add additional class names or style properties as you would like."
Any thoughts on what I might be doing wrong?

Best workaround I could come up with is to merge in style props from a different object using the spread operator. Something like this:
customColumnRenderer(props: GridCellProps): React.ReactNode {
...
let myStyles = {backgroundColor: "hotpink"};
let styles = {...props.style, ...myStyles};
...
return <div style={styles}
... </div>;
}

Related

How to use urls in React CSS inline styling without `$`?

Learning React and trying to cheat off this codepen. I do not understand 2 things.
What is the ... before largebox, flex, and other css classes?
return <div style={{...largebox, ...flex}} key={props.id}
What does the $ do in the css url param? Is it jQuery?
`url(${props.photo})
const FormCard = (props) => (
<div>
{
DATA.map((props) => {
return <div style={{...largebox, ...flex}} key={props.id}>
<div style={{...Photo,backgroundImage: `url(${props.photo})`}}></div>
<div>
<Author author={props.author}/>
<Something bio={props.bio}/>
<AdBox adpic={props.adpic} />
<IconBox />
</div>
</div>
})
}
</div>
)
The three dots '...' are called spread operator, see here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
The $ sign is no Jquery but is actually referencing template literals: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
Hopefully, the docs are enough as I currently can't find [the link] to [that tutorial] I remember...
Spread operator:
const styleA = { color: 'red' };
const styleB = { background: 'blue' };
const styleC = { ...styleA, ...styleB };
// styleC = {color: "red", background: "blue"}
String Template:
const user = 'Bob';
const greetings = `Hello ${user}`;
// greetings = 'Hello Bob'
for your first question we call it Spread Operator in a simple description for below line :
style={{...largebox, ...flex}}
this is mean copy all property of largebox and flex object into a new object and assing it to style.or this line means :
style={{...Photo,backgroundImage:"myurl}"}
create a new object for me with all property of Photo object and also add a property with name backgroundImage to it. so if Photo is equal to {name:'1.jpg'} the new object is equal to
{name:'1.jpg',backgroundImage:"myUrl"}
Now for your second question, this is template literal and allow you to write variables or call functions inside a string. think we have not this so we must write it like :
backgroundImage: "url(" + props.photo +")"
so as you see it is something like concating props.photo and other strings.but with template literals we can wrap string with backticks and then write variable or function of javascript between ${} like below
backgroundImage: `url(${props.photo})`
then ${props.photo} replace with its value.

How to get access to the children's css values from a styled component?

I am using a REACT BIG CALENDAR and I want to get access to the css values in one of my functions.
I created a style component and override the library
const StyledCalendar = styled(Calendar);
Now for example there is a div inside of the Calendar with the class = "hello",
How would I access the css values of "hello" in a function? Similar to property lookup say in stylus.
I have tried window.getComputedStyle(elem, null).getPropertyValue("width") but this gives the css of the parent component.
If you know the class name, you should be able to select that and give that element to getComputedStyle instead of giving it StyledCalendar. Something like:
const childElement = document.getElementsByClassName('hello')[0];
const childWidth = getComputedStyle(childElement).getPropertyValue('width');
(this assumes that there's only one element with the class 'hello' on the page, otherwise you'll have to figure out where the one you want is in the node list that's returned by getElementsByClassName)
You can do it using simple string interpolation, just need to be sure that className is being passed to Calendar's root element.
Like this:
const StyledCalendar = styled(Calendar)`
.hello {
color: red;
}
`
Calendar component
const Calendar = props => (
// I don't know exact how this library is structured
// but need to have this root element to be with className from props
// if it's possible to pass it like this then you can do it in this way
<div className={props.className}>
...
<span className="hello"> Hello </span>
...
</div>
)
See more here.

How can I view the style attributes of a div in react?

I am using
console.log("+++++++++++++++++++++++++", document.getElementById("liqcont").attributes);
before the return{} part of a .tsx file.
Typescript is returning an error
TS2531: Object is possibly null.
I need the style properties of the liqcont div to see what class properties have been actually rendered. Any other way to do that?
You can try using refs, and then in componentDidMount get all attributes of that element with the ref. Something like this should work :
class Test extends React.Component {
componentDidMount(){
let attributes = this.refs["wrapper"].attributes;
}
render(){
return (
<div ref="wrapper">
........
</div>
)
}
}
React.render(<Test />, document.getElementById('container'));
Hope this helps.

Multiple classNames with CSS Modules and React

I'm using the following code to dynamically set a className in a React component based upon a boolean from props:
<div className={this.props.menuOpen ? 'inactive' : 'active'}>
...
</div>
However, I'm also using CSS Modules, so now I need to set the className to:
import styles from './styles.css';
<div className={styles.sideMenu}>
...
</div>
I'm having trouble with this - I tried using classnames to gain more control with multiple classes, but because I need the end result to be that the className is set to both styles.sideMenu AND styles.active (in order for CSS Modules to kick in) I'm unsure how to handle this.
Any guidance is greatly appreciated.
Using classnames and es6:
let classNames = classnames(styles.sideMenu, { [styles.active]: this.props.menuOpen });
Using classnames and es5:
var classNames = classnames(styles.sideMenu, this.props.menuOpen ? styles.active : '');
Bit late to the party here, but using string templates works for me - you could move the ternary operator out to a const if you'd like as well:
<div className={`${styles.sideMenu} ${this.props.menuOpen ? styles.inactive : styles.active}`>
...
</div>
I wanted to just add on a better way of using the bind api of classnames npm. You can bind the classnames to the styles object imported from css like below:
import classNames from 'classnames/bind';
import styles from './index.css';
let cx = classNames.bind(styles);
and use it like this:
cx("sideMenu", "active": isOpen)
where sideMenu and active are in styles object.
Using logical AND instead of ternary operator makes it even less verbose since classnames omits a falsy value.
<div className={ classNames(styles.sideMenu, this.props.menuOpen && styles.active) }></div>
This is the closest I can get to a working solution:
const isActive = this.props.menuOpen ? styles.inactive : styles.active;
<div className={isActive + ' ' + styles.sideMenu}>
This does work - both allow the styles in the imported stylesheet to be used, and is only applied when this.props.menuOpen is true.
However, it's pretty hacky - I'd love to see a better solution if anyone has any ideas.
Using Array.join
<div className={[styles.sideMenu, this.props.menuOpen ? styles.show : styles.hide].join(' ')}></div>
While I'm not an expert on CSS modules, I did find this documentation: https://github.com/css-modules/css-modules/blob/master/docs/import-multiple-css-modules.md
It appears that you'll need to combine the styles for active and sideMenu together using Object.assign
import classNames from 'classnames/bind'.
then you can use like this:
let cx = classNames.bind(styles);
In case like that styles['bar-item-active'] , you can wrap it . in second square brackets like [styles['bar-item-active']] : your condition
I don't think anyone has suggested using both the style and the className attributes in your React DOM element:
const sideMenu={backgroundColour:'blue',
border:'1px black solid'}
return <>
<div style={sideMenu} className={this.props.menuOpen ? styles.inactive : styles.active}>
...
</div>
</>
It's not the neatest solution, but it does avoid adding another dependency to your project and if your sideMenu class is small then it could be a option
Using classnames library
import classNames from "classnames";
classNames is a function. if you pass some strings, it joins them together if they all are truthy. If there is any falsy string it will not pass it. For example
let textColor=undefined
classNames(textColor, "px-2","py-2" )
since textColor variable is falsy, classNames will ignore it and returns this string
"px-2 py-2"
You can also pass an object to classNames function.
const active=true
const foo=false
Let's say I have this expression
classNames({
'text-green':active,
'text-yellow':foo
})
classNames function will look at "VALUE" of each pair. if the "value" is truthy, it will take the "KEY" but if the "VALUE" is falsy it will ignore the "KEY". In this example since "active" true and "foo" is false it will return this string
'text-green'
In your example, you want to add a className based on if the prop is truth or falsy in other words if the prop exists or not:
let classNames=classNames(
styles.sideMenu,
// based on props that you are passing you can define dynamic classnames in your component
{
"active":this.props.menuOpen
}
)

knockout foreach css multiple classes $data

In this example I have two additional css classes I want to add to a DIV.
<div data-bind="foreach: [{name: 'Hello', size:'Triple'}]">
<div class="tile"
data-bind="css: {'tile-selected': true, $data.size : true}">
</div>
</div>
The first being 'tile-selected' based on a boolean. This works well.
The second is actually a name of a class 'Triple', (and in this example, always add it, ie 'True')
I get the error:
Uncaught Error: Unable to parse bindings.
Message: SyntaxError: Unexpected token .;
Bindings value: css: {'tile-selected': true, $data.size : true}
I'm assuming that I can't use the $data.size part to pull in the 'Triple' literal from the 'size' property. Is there a way that I can do this? ($data['size'] also didn't seem to work)
You cannot use the ko observables or properties as class names. Instead you would have to create a separate property for this and use the same for dynamic css binding something like below.
<div data-bind="css: sizeCSS"> Profit Information</div>
var viewModel = {
/// some view model properties here.
};
viewModel.sizeCSS = ko.computed(function() {
return this.size();
}, viewModel);
EDIT: Check the dynamic CSS binding example here: http://knockoutjs.com/documentation/css-binding.html

Resources