I'm fairly new to ReactJS. I am looking to get the value inside a <div> when contentEditable is set to true.
const listResults = this.state.results['1'].map((result) =>
<div key={result.toString()} contentEditable="true">
{result}
</div>
);
return (
<h1> listResults </h1>
<div> {listResults} </div>
)
I am currently outputting a list into pre-filled text-boxes which allows the user to edit them. I am looking to add in a button which once clicked captures the data inside all of the text-boxes. Can anyone point me in a direction on how to capture the changed data.
It may also be worth noting I am using ReactJS on the client side through a CDN.
To get value of editable div:
class App extends React.Component {
constructor(){
super();
this.state = {
arr: [1,2,3,4,5]
}
this.change = this.change.bind(this);
}
change(e, index){
let tmpArr = this.state.arr;
tmpArr[index] = e.target.textContent;
this.setState({arr: tmpArr})
}
render(){
console.log(this.state);
return (
<tr>
{this.state.arr.map((el, index) => <td key={index} id="test" onBlur={(e) => this.change(e, index)} contentEditable="true">{el}</td>)}
</tr>
);
}
}
https://jsfiddle.net/69z2wepo/84647/
One note, you can't return two elements on the same level:
return (
<h1> listResults </h1>
<div> {listResults} </div>
)
It should be wrapped like this:
return (
<div>
<h1> listResults </h1>
<div> {listResults} </div>
</div>
)
Related
I have my component CountDownSquare I want to disappear once the timer is done fully counting down. I have Data in homePageData that holds the main text in a h3 element, this text should appear once the timer is fully done. Here's a ternary statement I attempt to assign but it isn't assigned to anything the way I thought it would be. Here is a snippet of what I thought of
const { homePageData } = props;
{homePageData[0].showCountdown ? <CountDownSquare/>: styles.homeBody}
return (
homePageData && (
<Layout>
<div className={styles.Home}>
<Image src={wordmark} alt="Hammer and Hope wordmark" />
<CountDownSquare >
</CountDownSquare>
{/* <div className={styles.homeBody}>
<h3 className={styles.mainText}>{homePageData[0].mainText}</h3> */}
<Nav />
</div>
</Layout>
)
);
} ```
I am assuming homePageData[0].showCountDown is a boolean which is true if the countdown is complete in the parent component.
You need to add conditions while rendering your component.
The following snippet will render the CountDownSquare component and the h3 tag with homePageData[0].mainText if homePageData[0].showCountdown is true.
const { homePageData } = props;
return (
homePageData ?? (
<Layout>
<div className={styles.Home}>
<Image src={wordmark} alt="Hammer and Hope wordmark" />
{homePageData[0].showCountdown ??
<CountDownSquare >
</CountDownSquare>
<div className={styles.homeBody}>
<h3 className={styles.mainText}>{homePageData[0].mainText}</h3>
</div>
}
</div>
</Layout>
)
);
I have data stored in an object and I want to loop through the data and set it as the props for my component.
My component is a card, and I want to show a card for every piece of data in the loop.
This is code so far -
function App() {
let title = [];
for (let key in projectDataObject) {
let newObj = projectDataObject[key].sites;
for (let key in newObj) {
title = newObj[key].title;
}
return (
<div className="App">
<header className="App-header">
<Card title={title}></Card>
</header>
</div>
);
}
}
export default App;
The problem here is because of the "return" it stops the loop at the first item, and does not loop through everything else.
How can I do this?
use it like this:
<div className="App">
<header className="App-header">
{Object.keys(yourObject).map(function(key) {
return <Card title={yourObject[key].title} />;
})}
</header>
</div>
This code doesn't make any sense. You're just taking the last one as the title, so looping is pointless.
for (let key in newObj) {
title = newObj[key].title;
}
Since I can't really tell what you're trying to do there, I'll make an assumption to get you pretty close. It looks like you're trying to pull out all of the titles from your object graph, so let's do that first.
function App() {
const titles = /* I can't tell what your data structure is,
so flatten it to get all of the titles out and into an array here */
return (
<div className="App">
<header className="App-header">
{/* this will put a list of cards in the header */}
{titles.map(title => <Card title={title}/>)}
</header>
</div>
);
}
}
export default App;
I have a page with a bunch of sub-pages:
render(){
let elements = [<Apple>,<Orange>,<Pear>];
return <div>
{Elements}
</div>
}
I want to give each of these elements the same property, e.g. color:
render(){
let elements = [<Apple>,<Orange>,<Pear>];
elements.forEach(i=>i.setAttribute('color','blue')); //???
return <div>
{Elements}
</div>
}
So that it would be equivalent to:
render(){
return <div>
<Apple color='blue'/>
<Orange color='blue'/>
<Pear color='blue'/>
</div>
}
How would I do this?
Fix your elements to
let elements = [Apple, Orange, Pear];
then use array map to pass a common prop.
render() {
let elements = [Apple, Orange, Pear];
const elementsWithColorBlue = elements.map((Element) => (
<Element color="blue" />
));
return <div>{elementsWithColorBlue}</div>
}
An alternate way of writing than the answer above would be as below
render(){
return (
<div>
{[Apple, Orange, Pear].map(Element => <Element color="blue" />)}
</div>
)
}
Recently I started practicing React.
I'm trying to create a simple app that would count how many kg of plastic do we use, according on how many bottles of water we use every day.
Using this info, I want to show what could be produced out of recycled plastic that we use per year.
So I have a component Calculator:
class Calculator extends React.Component {
constructor(props) {
super(props);
this.state = {
resultNumber: null,
resultKg: null
}
}
count = (e) => {
let val = e.target.value;
let resultNumber = val * 52;
let resultKg = Math.round(resultNumber * 0.04);
this.setState({
resultNumber: resultNumber,
resultKg: resultKg
})
}
render() {
return ( <div >
<Menu / >
<div className = "component" >
<h1 > I use < input type = "text" className = "input-data" onChange = {this.count}/> bottles per week</h1 >
<div className = "resultInfo" > {this.state.resultNumber != null ?
<Info resultNumber = {this.state.resultNumber}
resultKg = { this.state.resultKg } /> :null} < /div>
</div>
</div>
)
}
}
I have a component that shows the result:
const Info = (props) => {
return(
<div>
<div className="info">
<div><p>{props.resultNumber} bottles per year</p>
<img src={bottle1} />
</div>
<div><p>{props.resultKg} kg of plastic per year</p>
<img src={trash} />
</div>
</div>
<p>What could be produced out of {props.resultKg} kg of plastic?</p>
</div>
)
}
The problem is that I don't know how to get the {props.resultKg} in another component that renders what could be produced:
const Recycle = (props) => {
return({props.resultKg})
}
The last component, of course, returns "undefined".
I tried to learn Redux but it became overwhelming and I got even more confused. Could you help me to understand how I can get state from Calculator in my Recycle component?
In the end I had to learn Redux to make it. :)
I have a render function like this one:
render() {
const statement = true
return (
<div>
{
statement &&
<div>
<p>
{this.buildStuff()}
</p>
<p>
{this.buildStuff()}
</p>
<p>
{this.buildStuff()}
</p>
</div>
}
</div>
);
}
To avoid calling buildStuff() three times, I would like to assign it to a variable. How can I declare a variable after the line with statement &&?
A quick solution would be to do
const statement = true
const stuff = statement ? buildStuff() : null;
but this solution use two branches instead of one.
You can try this code on StackBlitz.
This what it would look like in Razor.
You can try something like this as well:
You can create a function that deals with this UI representation.
In this function, you can call buildStuff and have it return 3 <p> tags.
Then in main render, you can check your condition and render accordingly. This will make your render clean and declarative.
getBuildJSX() {
const stuff = this.buildStuff();
return Array.from({ length: 3}, () => <p> { stuff }</p>);
}
render() {
const statement = true
return (
<div>
{
statement ? this.getBuilsJSX() : null
}
</div>
);
}
Try it online
First solution (edit: alternative)
render() {
const statement = true;
const stuff = this.buildStuff(statement, 3); // jsx result looped in divs
return (
<div>
{
statement &&
<div>
{ stuff }
</div>
}
</div>
);
}
Alternative, memoization (caching of functions) if this is your goal:
const memoize = require('fast-memoize');
const memoized = memoize(this.buildStuff);
...
render() {
const statement = true;
return (
<div>
{
statement &&
<div>
<p>
{memoized()}
</p>
<p>
{memoized()}
</p>
<p>
{memoized()}
</p>
</div>
}
</div>
);
}
The true power of memoization however is, if you cache based on the parameter you give to buildStuff (maybe you move statement into buildstuff?). In your case I would just clean up the component and parameters in favour of readability rather than optimising something. So last alternative:
// Stuff is a component now
const Stuff = ({statement, stuff}) => {
if(!statement)
return null;
const result = stuff();
return (
<div>
<p>
{result}
</p>
<p>
{result}
</p>
<p>
{result}
</p>
</div>
)
}
render() {
return (
<div>
<Stuff statement={true} stuff={this.buildStuff} />
</div>
);
}
The benefit, you can now choose to pass the result or the function itself through props, and in the downward component either call the function or simply have its results passed through.
Single answer to your question in the headline: you cant, JSX is not a templating engine like Razor.
Explanation:
// JSX
<div id="foo">Hello world</div>
// Translates into
React.createElement("div", {id: "foo"}, "Hello world");
// JSX
<div>{ statement && <div /> }</div>
// Translates to
React.createElement("div", null, statement && React.createElement("div"));
Either you declare a new variable with an attribute, or you simply cant, since javascript does not allow variable creation inside parameters of functions.
I think one of the main ideas of react is to use components to structure your code.
So one way to do it would be like this:
render() {
const statement = true;
const Stuff = ({statement}) => {
if (!statement) { return null; }
return this.buildStuff();
}
return (
<div>
<p>
<Stuff statement={statement} />
</p>
<p>
<Stuff statement={statement} />
</p>
<p>
<Stuff statement={statement} />
</p>
</div>
);
}
Updated StackBlitz.
This answer is an answer to the problem but not a solution to the question. If you cannot declare a variable inside brackets in react (as you could do in Razor for example). Calling twice a statement can still be your best bet.
render() {
const statement = true
const stuff = statement ? this.buildStuff() : null
return (
<div>
{
statement &&
<div>
<p>
{stuff}
</p>
<p>
{stuff}
</p>
<p>
{stuff}
</p>
</div>
}
</div>
);
}
At least, we call this.buildStuff() only if needed and if we do, we call it only once.