Kendo-react-ui TreeList how to customize cells on the different levels of hierarhy? - reactjs

class TableCell extends React.Component {
render() {
const { dataItem, field } = this.props
const cellData = this.getFieldValue(dataItem, field)
const { participantType } = dataItem
let styles = { position: 'relative' }
switch (participantType) {
case 'direct':
styles = {
fontSize: '14px',
}
break
case 'indirect':
styles = {
fontSize: '14px',
fontStyle: 'italic',
}
break
case 'addressable':
styles = {
fontSize: '13px',
fontStyle: 'italic',
}
break
}
return (
<td style={styles}>
<span>{cellData}</span>
</td>
)
}
}
It's work with columns that didn't expandable. If i use with 'expandable' column it's restyling, but expand/collapse behaviour is overrited and arrow for expanding disappearing.
Is there possibilities to customize cells another way??

There answer that helps me is TreeList prop rowRender.
rowRender? (row: ReactElement<HTMLTableRowElement>, props: TreeListRowProps) => React.ReactNode
It helps me to styling all cells in a row according to data of a row.
It's possible to override current row using React.cloneElement and add some additional props like style.

Related

AntD table - change cell color on mouse hover

I'm trying to change background color of the cell in antD table using onCell property and onMouseOver function, but without success.
onCell: (record, rowIndex) => {
return {
onMouseOver: () => {
console.log("record, row", record, rowIndex);
return {
props: {
style: { background: "yellow", fontWeight: "bold" }
}
};
}
};
}
Working sandbox example:
demo
Any help would be highly appreciated.
If the goal is to add a custom background on hover to the cells of a certain column, perhaps a simple solution would be adding this as a custom class with onCell.
Forked demo with modification: codesandbox
onCell: (record, rowIndex) => {
return {
className: "custom",
};
};
In CSS, define :hover styles with a higher specificity so that it overrides default style for selected cells:
.ant-table-cell.ant-table-cell-row-hover.custom:hover {
background-color: hotpink;
color: white;
}

Remove (or at least hide) card on react-admin List

I want to get rid of the Card on the background react-admin's List (v3.4.2). I get the desired effect if I define a string on the component property:
<List component={"some string"}/>
But this spams the console with an error:
And I don't want to have that error. On top of that, I think I shouldn't be changing the component property (I can't find it on the official docs).
The code should be the following: https://github.com/marmelab/react-admin/blob/master/packages/ra-ui-materialui/src/list/List.js
How should I do this? Is it possible to pass a style? Is there any component that works out of the box? Or should I just go custom?
You can hide the background using styling:
import { makeStyles } from '#material-ui/core/styles'
const useListStyles = makeStyles(theme => ({
content: {
boxShadow: 'none',
backgroundColor: 'inherit',
},
main: {
// backgroundColor: 'red',
},
root: {
// backgroundColor: 'red',
},
}))
const MyList = (props) => {
const classes = useListStyles()
return (
<List classes={classes} {...props} >
...
</List>
)
}

Set dynamic style for Checkbox in Ant Design

Is it possible to set tick container's style backgroundColor and borderColor in Checkbox dynamically from JSX?
I can do it with CSS/LESS, but I need to set specific color based on data from API.
Example:
.
If the colors from API are completely unknown to you until the time of running, then there is no way to accomplish the task with Antd library. Because the class you need to update colors for (.ant-checkbox-checked .ant-checkbox-inner) is nested inside the parent component , and can be changed only in your .less file.
As you can see in Rafael's example, you can only control the colors of the parent (.ant-checkbox-wrapper) from .js file.
On the other hand, if you know there will always be, let's say "#1890FF", "#FA8072", and "#008100" colors, you just don't know in what order, you can easily change the colors dynamically, by creating your logic around CSS classes. Which means you can map through all your checkboxes and give the classNames based on the color you get from API (getColor function). In order to do so, in your .js file import the data from API and define getColor function:
import React, { PureComponent } from "react";
import { Checkbox } from "antd";
export default class ColoredCheckboxes extends PureComponent {
getColor = color => {
let checkboxClassName = "checkbox-green";
if (color === "#FA8072") {
checkboxClassName = "checkbox-orange"
}
if (color === "#1890FF") {
checkboxClassName = "checkbox-blue"
}
return checkboxClassName;
};
render() {
const dataFromAPI = [
{
key: "first",
name: "First",
color: "#008100",
},
{
key: "second",
name: "Second",
color: "#FA8072",
},
{
key: "third",
name: "Third",
color: "#1890FF",
},
]
return (
<div>
{dataFromAPI.map(item => (
<div key={item.key}>
<Checkbox className={this.getColor(item.color)}>
{item.name}
</Checkbox>
</div>
))}
</div>
);
}
}
Then in your .less file reassign the colors for ".ant-checkbox-checked .ant-checkbox-inner" class originally coming from Antd Library:
.checkbox-green {
.ant-checkbox-checked .ant-checkbox-inner {
background-color: #008100;
border-color: #008100;
}
}
.checkbox-orange {
.ant-checkbox-checked .ant-checkbox-inner {
background-color: #FA8072;
border-color: #FA8072;
}
}
.checkbox-blue {
.ant-checkbox-checked .ant-checkbox-inner {
background-color: #1890FF;
border-color: #1890FF;
}
}
You just styled it, something like
<Checkbox
style={{
backgroundColor: data.backgroundColor,
borderColor : data.borderColor
}}
/>

Uncaught TypeError: Cannot assign to read only property '' of object '#<Object>'

i don't know what difference in this code.
class a is component and example is example.js
import React, {Component} from 'react';
const styles = {
border: {
display: 'inline-block',
height: '19px',
padding: '1px 8px 0',
border: '2px solid',
borderRadius: '12px',
lineHeight: '20px',
fontSize: '14px',
verticalAlign: 'top',
},
default: {
display: 'inline-block',
height: '20px',
padding: '1px 10px 0',
borderRadius: '10px',
lineHeight: '21px',
fontSize: '13px',
verticalAlign: 'top',
},
state: {
display: 'inline-block',
width: '14px',
height: '13px',
paddingTop: '1px',
lineHeight: '14px',
fontSize: '11px',
color: '#fff',
letterSpacing: '-0.5px',
textAlign: 'center',
verticalAlign: 'top',
}
};
class A extends Component {
static defaultProps = {
type: 'default',
};
render() {
const {
label,
style,
type,
...other
} = this.props;
switch (type) {
case 'border':
elementStyle = styles.border;
break;
case 'default':
elementStyle = styles.default;
break;
case 'state':
elementStyle = styles.state;
break;
}
return (
<span style={Object.assign(elementStyle, style)} {...other}>{label}</span>
);
}
}
export default A;
and example code is example.js
import A from './A';
export default class Example extends React.Component {
render() {
return (
<div>
<A style={{background: '#fe6969', color: '#fff'}} />
<A style={{background: '#ff8137', color: '#fff'}} />
<A style={{background: '#fcb400', color: '#fff'}} />
</div>
);
}
}
this code error is Uncaught TypeError: Cannot assign to read only property 'background' of object '#'
i use babel-loader 8, babel7 ,webpack4
if i correct Object.assgin({}, elementStyle, style) is working.
i think this error occur when rerendering A component.
i don't know why this error...
please help me.
All you need to do is concat/merge two objects like this using spread
{{...elementStyle, ...style}} or
{Object.assign({}, elementStyle , style) }
You should understand the nature of how Object.assign works. It returns the target object as the return value of its operation.
So, in the first syntax:
Object.assign({}, elementStyle , style)
you are creating a brand new object with the enumerable properties of elementStyle and style.
If you do this:
Object.assign(elementStyle, style)
Then elementStyle itself is the target object, so that will be mutated and that will be what is returned from Object.assign.
Here is an example what I mean.
Example 1 :
// With no new target object
const original = [{id:1}, {id:2}, {id:3}];
const newArray = original.map(elem => {
return Object.assign(elem, {id:2});
});
console.log('Original object has changed');
console.log(original);
//------------------------------
// With a new target object
const original2 = [{id:1}, {id:2}, {id:3}];
const newArray2 = original2.map(elem => {
return Object.assign({}, elem, {id:2});
});
console.log('Original object has not changed');
console.log(original2);
Example 2 :
var styles = {
circle: {backgroundColor: 'yellow', height: '1005', width: '100%'},
circleA: {backgroundColor: 'blue'},
};
So we need all circle to have default cir some circle style, but we need to change some property,
// background yellow
<div style={styles.circle}></div>
// background blue
<div style={Object.assign(styles.circle, styles.circleA)}></div>
// expeted background yellow, but it's blue. cus styles.circle still have it's merged value
<div style={styles.circle}></div>
The solution is to pass an empty object to Object.assign(). By doing this, you're telling the method to produce a NEW object with the objects you pass it.
Example 3:
const obj1 = {
name: "J"
}
const obj2 = {
gander: "m"
}
// Here, obj1 is the same after the Object.assign call
console.log(Object.assign({}, obj1, obj2));
console.log(obj1)
console.log(obj2)
console.log("without empty obj passed")
// Note that after this call, obj1 holds both keys. So this will mutate it:
console.log(Object.assign(obj1, obj2));
console.log(obj1) // This is different now
console.log(obj2)
In your case,
`<A propstyle={{background: '#fe6969', color: '#fff'}} />
<A propstyle={{background: '#ff8137', color: '#fff'}} /> `
component A defined twice in Parent, which means that we will get two circles and child component will render twice.
and in Child component you defined like below:
<span style={Object.assign(elementStyle , style) }{...other}>{label}</span>
first render :
Object.assign overwrite properties from right to left props style to elementStyle,here elementStyle itself is the target object,that will be what is returned from Object.assign.
style props : { background: "#fe6969", color: "#fff" }
elementStyle : { background: "#fe6969", borderRadius: "10px", color: "#fff" }
Second render :
Object.assign tries to overwrite properties from right to left, but elementStyle have { background: "#fe6969", borderRadius: "10px", color: "#fff" }
and Object.assign is still in loop (remember example 1 .map())
style props : { background: "#ff8137", color: "#fff" }
error thrown: 'TypeError: Cannot assign to read only property 'background' of object ' when {Object.assign(elementStyle , style) } because there's no new target object.
please find the full code here
Hope it helps. read more
Instead of assigning values directly to the object, clone the object first instead of mutating an object that is immutable due to the fact that the object is a props object or because Object.defineproperties was used to set writable to "false", but just clone the object and assign the values to the cloned object and use the cloned object, but assign the values to the cloned object properly as well.
Instead of assigning and mutating directly like:
object.field = value
Do:
let clonedObject = {...object}
clonedObject = {...clonedObject, field: value}
Otherwise using object.defineproperties to set the writable property to "true" might also be another way that would work.
Object.defineProperty(object, 'field1', {
value: 1,
writable: true
});

How to setState of a particular index in an array React Native

I have an array of objects that I am currently mapping over to generate as buttons. When clicked, I want the background color of the specific button the user clicks on to change color ( I want it to toggle on, like a switch, so I can eventually save to async storage). Right now when the user clicks, all buttons change color. I'm not quite sure how I should handle this.setState in the selectMetric function.
import React, {Component} from 'react';
import {View, Text, ScrollView} from 'react-native';
import {Button} from 'react-native-elements';
const RISK_DATA = [
{id: 1, text: 'cats', flag: false, buttonColor: null},
{id: 2, text: 'dogs', flag: false, buttonColor: null},
]
class IssueSelectionScreen extends Component {
state = {flag: false, buttonColor: null}
selectMetric = (index) => {
for (let i=0; i < RISK_DATA.length; i++) {
if (index === (RISK_DATA[i].id - 1)) {
console.log("RISK_DATA:", RISK_DATA[i]); // logs matching id
// ------------------------------------------------------
// Problem setting correct state here:
RISK_DATA[i].buttonColor = this.setState({flag: true, buttonColor: '#03A9F4'})
// this.setState({flag: true, buttonColor: '#03A9F4'})
// this.setState({update(this.state.buttonColor[i], {buttonColor: {$set: '#03A9F4'}}) })
// ----------------------------------------------------------
}
}
}
showMetric() {
return RISK_DATA.map((metric, index) => {
return (
<View key={metric.id}>
<Button
raised
color={'black'}
title={metric.text}
borderRadius={12}
onPress={() => this.selectMetric(index)}
backgroundColor={this.state.buttonColor}
>
{metric.text}
</Button>
<Text>{/* intentionally blank*/} </Text>
</View>
)
})
}
render() {
return(
<ScrollView style={styles.wrapper}>
<View style={styles.issues}>
{this.showMetric()}
</View>
</ScrollView>
);
}
}
const styles = {
issues: {
justifyContent: 'center',
flexDirection: 'row',
flexWrap: 'wrap',
alignItems: 'flex-start',
marginTop: 10,
justifyContent: 'space-between',
},
wrapper: {
backgroundColor: '#009688'
}
}
export default IssueSelectionScreen;
so the short answer to your question would look something like this:
class IssueSelectionScreen extends Component {
constructor(props) {
super(props);
this.state = {
data: cloneDeep(RISK_DATA),
};
}
selectMetric = (index) => {
const tempData = cloneDeep(this.state.data);
tempData[index].flag = !tempData[index].flag;
this.setState({ data: tempData });
}
showMetric() {
return this.state.data.map((metric, index) => {
// same
})
}
render() {
// same
}
}
It involves putting the whole array of buttons into state since the state of those buttons is what can change. You could also maintain the flags as an array in state and keep the button info as a separate constant
This solution uses cloneDeep (from lodash) to prevent the code from mutating the state of the objects but you could probably also do it with this.state.data.map and creating new objects (which works as long as your objects aren't deeply nested).
If you're using Redux, the list would probably come into the component as a prop, then selectMetric would be dispatching an action to update the flag in Redux.
For anyone else viewing this post, the answer above is very helpful. To add a few last remarks, if you're trying to get the buttons to light up I added a simple if else to selectMetric:
if (tempData[index].flag) {
tempData[index].buttonColor = '#03A9F4';
console.log('tempData true:', tempData);
} else {
tempData[index].buttonColor = null;
console.log('tempData false:', tempData);
}
and updated the backgroundColor property on Button in showMetric with:
backgroundColor={this.state.data[index].buttonColor}

Resources