I wish to do the following in my application:
1) access the the property of color and option from each object
2) check the property
3) give a class based on that property
4) toggle the class onClick
The json object looks like this{
{
"green": false,
"other": "third",
"option" : 2
},
{
"green": false,
"other": "third",
"option": 1
},
{
"green": true,
"other": "first",
"option": 5
}
And so on...
Each object will be giving back a number for the key ([0],[1] etc).
My React code is as follows:
class Inf extends React.Component {
constructor() {
super();
this.state = {
colorData: data
}
}
renderList(data){
return(
<ul>{Object.keys(this.state.colorData).map(thing =><li>{thing}</li>)}</ul>
)
}
render() {
console.log(this.state.colorData)
return (
<div>
<div>{this.renderList(this.state.colorData)}</div>
</div>
);
}
}
ReactDOM.render(
<Inf />,
document.getElementById('root')
);
Sounds like you can make use of this library: classnames
The Usage section of the readme explains it very well, but basically you can then use it to do something like:
const classes = classNames({
classA: colorData.green,
classB: colorData.red
})
Basically the className on the left hand side will only be applied if the expression on the right hand side is true. And then you can assign the classes to the react className prop
In your renderList function, you can style the li returned by your map with className={desiredClass}.
There are two variables I'm not sure about in your question:
what key you're storing color under in the object
how you determine which class to add based on this color
I assume you use .color and then have a function classBasedOnColor to apply a class name based on this color. You could also use a dictionary with color keys and class name values.
It would look like this:
<ul>{Object.keys(this.state.colorData).map(thing=>{
const color = this.state.colorData[thing].color;
const desiredClass=classBasedOnColor(color);
return <li className={desiredClass}>{thing}</li>
})}</ul>
Related
They would like to function from the component from the child component. This method call: TypeError: Pizza__WEBPACK_IMPORTED_MODULE_2_.default.valid is not a function.
I try to add static function but it will not get the value.
I can add code of pizza to orders, but this not I will.
Can anyone help?
I want to get dish_details from Pizza and Show Pizza form underneath.
In .js no .tsx
Parend class:
class Orders extends React.Component {
constructor(props) {
super(props);
this.order = {
name: "",
preparation_time: "00:00:00",
type: "",
}
}
kind(){
switch (this.order.type) {
case 'pizza':
return <Pizza/>;
}
}
submit(){
console.log(Pizza.dishDetails()); // return error
}
render() {
return (<div>
<div>{this.state.selected ? this.kind() : ""}</div>
<button className={styles.order_submit} onClick={this.submit.bind(this)}>Submit</button>
</div>
);
}
Kids class:
class Pizza extends React.Component{
constructor(props) {
super(props);
this.state = {
noOfSlices : 0,
diameter : 0
}
}
dishDetails(){
return this.state;
}
noOfSlices(e){
this.setState({noOfSlices : e.target.value});
}
If you want your components to have a state you need to declare it with
this.state.[the name of the variable]
That's how react knows that you want to store state inside a component. The error you get probably is because you declared the state of the pizza component wrongly
dish_details = { //Not correct
noOfSlices : 0,
diameter : 0
}
Here you declare it inside the constructor, and that is correct, but in order to work you need to use the component state.
constructor(props) { /
super(props);
this.state.order = {
name: "",
preparation_time: "00:00:00",
type: "",
}
}
Check out the docs on state.
You have several issues here
you say something is static, but you have not created a static function!
submit(){
console.log(Pizza.dishDetails()); // return error or undefined when static
}
This is a call to a static function. To create a static function you would do this:
// ES5
Pizza.dishDetails = function(){ /* do something that does not touch `this` */ }
or in modern ES2015+:
class Pizza {
static dishDetailsfunction(){
/* do something that does not touch `this` */
}
}
The dishDetailsfunction function is not static, but more importantly, it cannot be static, since it uses this. A static function has no reference to this - that's the definition of static.
So you need to reorganize a bit ...
You are not allowed to access the inner state of a component from an outer component, so you need to either do your data and external actions handling outside of your components (like Redux), use some kind of callback logic, or delegate the logic for handling submits down to Pizza.
Here is one way to do it using a callback:
In the order component
renderPizza() {
// the `this` in the callback references the Orders (parent) component
return <Pizza onChange={(pizzaOrder) => this.setState({order: pizzaOrder}) }/>} />
}
In the pizza component:
updateNoOfSlices(e){
this.setState({noOfSlices : e.target.value});
this.prop.onChange({this.state});
}
I removed all the logic that is not necessary for the point, but you should see how a callback solves this easily.
P.S. If you centralize your data handling in one place (for instance a component) you will get simpler and more easily testable code. For instance, you can remove all state from the Pizza class and just let it have noOfSlices and diameter passed to it as props from the Orders class.
I have answer. I create clas Static with static value, and this is working for me.
static
class Static {
static defaultProps = {}
}
export default Static;
order
submit(){
console.log(Static.defaultProps)
pizza
noOfSlices(e){
Static.defaultProps = {noOfSlices : e.target.value};
}
I have a vuejs functional component that mimics a div behavior. To do so, I set it's class based on the props that it receives.
Something like this:
<MyDiv textAlign="left">Div with left aligned text</MyDiv>
Becomes:
<div class="text-left">Div with left aligned text</div>
However, if MyDiv component is the root element for some other component, like:
Card.vue
<template>
<MyDiv display="inline-block" textAlign="center">
<slot />
</MyDiv>
</template>
And if Card receive any class attribute when used, I can't set the class attribute value based on MyDiv props, instead, class (on MyDiv) is overridden by the class received by Card.
So this:
<Card class="cool-style">Card content</Card>
Becomes:
<div class="cool-style">Card content</div>
Ant not this (what I need):
<div class="cool-style inline-block text-center">Card content</div>
Here's MyDiv component:
MyDiv.vue
export default {
name: 'my-div',
functional: true,
props: {
textAlign: {
type: String,
allowed: ['left', 'right', 'center'],
default: null
},
display: {
type: String,
allowed: ['hidden', 'block', 'inline-block', 'flex'],
default: null
}
},
render: function(createElement, context) {
let classes = [];
// Adds parent class to itself
if (typeof context.data.staticClass == 'string') {
classes.push(context.data.staticClass);
}
let classes = classes.concat([
'my-div',
context.props.textAlign && `text-${context.props.textAlign}`,
context.props.display && context.props.display
]);
classes = classes.filter(elm => elm != null);
classes = classes.join(' ').trim();
return createElement(
props.type,
{
attrs: {
class: classes
}
},
context.children
);
}
};
TL;DR
How can I force my custom class to a vue functional component, when it's parent have already a class being set?
As a side note, it can be done using statefull (non-functional and regular) components.
Replace
attrs: {
class: classes
}
by
class: classes
Side note: Not really needed to join the array into a string, you can pass the array.
I am looking a way of determining the type object I clicked in JavaScript.
I populated in React (with PrimeReact - Tree View) a GUI element similar to a Tree View with a JSon object from a Rest call. Now the first layer of the Tree is from ObjectA and 2nd layer from ObjectB.
When user clicks, I don't want to raise events for ObjectA but only for ObjectB, so if I would do in Java, I would do something like following
ClickedObject.isAssignable(ObjectB)
which would tell me this is the type of the object I am interested.
I tried to do something like
ObjectB instanceof ClassB
but while I constructed the object from JSon, I don't have an access to its constructor (or is there a way to get the constructor of an object)..
What would be the best way to achieve what I want to do?
class App extends React.Component {
outer = (e) => {
console.log('outer');
}
inner = (e) => {
e.stopPropagation();
console.log('inner');
}
render() {
return (
<div onClick={this.outer}>
Outer
<div onClick={this.inner}>Inner</div>
</div>
)
}
};
Demo: https://codesandbox.io/s/j2j6x0lo6w
Or:
class App extends React.Component {
click = (e) => {
e.stopPropagation();
console.log(e.target.id);
}
render() {
return (
<div id="outer" onClick={this.click}>
Outer
<div id="inner" onClick={this.click}>Inner</div>
</div>
)
}
};
Or:
class App extends React.Component {
click(id, e) {
e.stopPropagation();
console.log(id);
}
render() {
return (
<div onClick={(e) => this.click('outer', e)}>
Outer
<div onClick={(e) => this.click('inner', e)}>Inner</div>
</div>
)
}
};
Edit
For the PrimeReact Tree component, you could do an object reference equality check. For example:
onSelectionChange(e) {
if (e.selection === data[1].children[2]) {
console.log('Clicked the 3rd child of the second parent');
}
}
If you take a look at Primereact tree node object, you'll notice that there is data property. You can use it to achieve what you want.
Fox example, populate list of nodes on the following way
var data = [
{
"label": "Documents",
"data": "ObjectA",
"expandedIcon": "fa-folder-open",
"collapsedIcon": "fa-folder",
"children": [{
"label": "Work",
"data": "ObjectB",
"expandedIcon": "fa-folder-open",
"collapsedIcon": "fa-folder"
},
{
"label": "Work",
"data": "ObjectB",
"expandedIcon": "fa-folder-open",
"collapsedIcon": "fa-folder"
}]
}];
(1st level nodes have data: "ObjectA", 2nd level nodes have data: "ObjectB",..)
Now you can check selected "object type" inside function onSelectionChange like this
onSelectionChange(e) {
console.log("Node selected");
console.log(e); //check out console to see structure of 'e'
if (e.selection.data == 'ObjectA'){
console.log("ObjectA selected");
} else if (e.selection.data == 'ObjectB'){
console.log("ObjectB selected");
} else {
console.log("Unknown object type selected");
}
}
Please note that you can assign any type to data property and build more complex data structure representing Primereact tree node.
It must be an ultra basic. I want to make a very first demo, without using JSX to be more direct.
const nicolas = {
admin: true,
id: 1,
email: "xyz#zyx.io",
name: "Nicolas",
statement: "Star Wars rocks"
};
class User extends React.Component {
render() {
return React.createElement('div', null,
`<div>name: ${this.props.name}</div>
<div>statement: ${this.props.statement}</div>`
);
}
}
ReactDOM.render(
React.createElement(User, nicolas, null),
document.querySelector('section.app')
);
As a result, div tags are shown directly. Why ? and how to avoid that ? Must I use multiple imbricated React.createElement()
Why ?
Because you are passing a string as a child to the element. The string is literally rendered into the document. It's the same as if you did:
<div>{'<span>something</span>'}</div>
in JSX, which is not the same as
<div><span>something</span></div>
How to avoid that ? Must I use multiple imbricated React.createElement()
Yes, every element needs to be created with React.createElement. There is a way to directly set HTML as content of an element, but you should avoid that.
React.createElement(root, props, elements) accept multiples elements, that can be strings.
const e = React.createElement;
class User extends React.Component {
render() {
return e('div', null,
// strong for the whole line
e('div', null,
e('strong', null, `name: ${this.props.name}`)
),
// strong for left part only
e('div', null,
e('strong', null, 'statement:'),
e('span', null, this.props.statement)
)
}
}
React.createElement Reference ;
React Without JSX
I am learning React-Redux and I have an issue navigating through the objects in my JSON file. I have the following file JSON, the file is designed to render out a side navigation:
export default function(){
return [
{
catId:"parMenu1",
parentCat:"Genres",
subcat:[
{
genre:"8Bit",
genreId:"1"
},
{
genre:"Acid House",
genreId:"2"
}
]
},
{
catId:"parMenu2",
parentCat:"sounds",
subcat:[
{
genre:"blah",
genreId:"3"
},
{
genre:"blah House",
genreId:"4"
}
]
]
}
I have the JSON file mapped to state props for a component. The component looks like so:
class BrowseByCont extends Component {
render () {
return (
<div className="browseByContInner">
{
console.log(this.props.reducerSidenav[0].catId)
}
</div>
)
}
}
function mapStateToProps(state) {
return {
reducerSidenav:state.reducerSidenav
};
}
I am trying to reach the subcats object within the parent object. The JSON object is linked to a variable called "reducerSidenav". So far I have managed to get this far into my JSON file: this.props.reducerSidenav[0].catId. this spits out the value parMenu1 which is the "parent" object I want to target. Where I am stuck though is I am trying to achieve two things:
firstly - I would like to access the first "parent" object by without having to refer to the first item in the array: reducerSidenav[0] but rather by find the catId with a value of parMenu1. This is because this list will be dynamic in future and referring to the first array object is not reliable.
secondy - I would then like to access the subcat object and get to the value thats associated to the key genre ie to return the value "8Bit"
You can use .find() to achieve both things.
class BrowseByCont extends React.Component {
render () {
let first = this.props.reducerSidenav.find(item => item.catId === "parMenu1");
let second = first.subcat.find(subcat => subcat.genre === "8Bit")
return (
<div className="browseByContInner">
<div>{first.catId}</div>
<div>{second.genre}</div>
</div>
)
}
}
Edit
In order to print all the subcats, you have to use .map()
class BrowseByCont extends React.Component {
render () {
let first = this.props.reducerSidenav.find(item => item.catId === "parMenu1");
return (
<div className="browseByContInner">
{first.subcat.map(genreItem =>
<div key={genreItem.genreId}>{genreItem.genre}</div>)
}
</div>
)
}
}
jsfiddle