I've made such a table to put articles with their respective prices, quantity... What's more there's a button and with every click it's created a new article. (put a photo to see it clearer)
The fact is that I need a way to differentiate every line, what i say is that in the square "Num" there should be 1,2,3... this is very important to me because later I need to send the information to a database, but my problem is I don't know how to differentiate every line. Here I put the code
class LinArt extends Component{
constructor(){
super()
this.state = {
quan:2,
price:20,
dto:10,
count:1
}
this.newArt = this.newArt.bind(this)
}
newArt(){
this.setState({count:this.state.count+1})
}
showArt(){
const total = (this.state.cant * this.state.preu) * (1-(this.state.dto/100));
let lines =[];
for(let i=0; i < this.state.count; i++){
lines.push(
<div key={i}>
<TextField type="number" disabled={true} value={this.state.count} label="Num"/>
<TextField label="DescripciĆ³" variant="outlined"/>
<TextField type="number" label="Cant" value={this.state.quan}/>
<TextField type="number" label="Price" value={this.state.price}/>
<TextField type="number" label="Dto" value={this.state.dto }}/>
<TextField type="number" disabled={true} value={total} label="Total"/>
<TextField type="number" disabled={true} value="21" label="IVA"/>
<br/><hr/>
</div>
)
}
return linies || null;
}
render(){
return(
<div>
{this.showArt()}
<Button onClick={this.newArt}>New article </Button>
</div>
)
}
Thank you for your attention, I appreciate so much your help!
Looking at your code, if you want the num column to increment, you should add i + 1 increment variable as the value to your num field so as it runs the loop, it gives the incremented value and starts from 1 rather than 0. Like so,
<TextField type="number" disabled={true} value={i + 1} label="Num"/>
Related
I have an onClick function that is attached to rows of a table by the characterID that is provided from an array of objects (instantiated from a constructor function).
I'm using styled-components, hence the odd tag names further down.
Here's the function:
//this is an onClick function for use in record rows in the JSX populated table for characters
function barkCharData(idIn){
console.log("==========================");
try{
//Get the fields...
let idField = document.getElementById("txt_idField");
let nameField = document.getElementsByName("first_name_field");
//Set the fields
idField.innerHTML = String(ar_charBin[idIn-1].id);
console.log("\n---> idField: "+idField);
console.log("---> idField.innerHTML: "+idField.innerHTML+"\n")
nameField.innerHTML = String(ar_charBin[idIn-1].id);
console.log("\n---> nameField: "+nameField);
console.log("---> nameField.innerHTML: "+nameField.innerHTML+"\n")
}
catch(error)
{
console.log("Pants were shat in the 'barkCharData' function [line 72]:\n\t" +error)
}
}
}
I can access each objects properties fine because they're all stored in an array called ar_charBin. Had them console logged earlier with no issues.
The problem I'm having is that I want to put these properties in to disabled text boxes.
These are defined as JSX here:
export const ExpTable = () => {
let Char1 = new char_Obj(1,"Saloth", "Saar", 45, "Male", "Dragonborn", "Sorcerer", 10);
let Char2 = new char_Obj(2,"Kaedwen", "Isaani", 36, "Male", "Dragonborn", "Sorcerer", 8);
let Char3 = new char_Obj(3,"Euridice", "Swiftblade", 23, "Female", "Human", "Bard", 5);
//array to store characters
let ar_charBin = [];
//push all chars into the array
ar_charBin.push(Char1, Char2, Char3);
return(
<>
...table head stuff...
<tbody>
{ar_charBin.map((character) => (
<TableRow key={character.id} onClick={() => barkCharData(character.id)}>
<td>{character.full_name}</td>
<td>Level {character.level} {character.classType}</td>
</TableRow>
))}
</tbody>
</Table>
<Wrapper>
<h2>Object elements</h2>
<p>These fields should update with object<br/>attributes when the records above are clicked</p>
<input type="text" id="txt_idField" name ="id_field" placeholder="ID"/>
<input type="text" id="txt_fNameField" name ="first_name_field" placeholder="First Name" disabled={true} />
<input type="text" id="txt_sNameField" placeholder="Second Name" disabled={true} />
<input type="text" id="txt_ageField" placeholder="Age" disabled={true} />
<input type="text" id="txt_cNameField" placeholder="Full Name" disabled={true} />
<input type="text" id="txt_genderField" placeholder="Gender" disabled={true} />
<input type="text" id="txt_raceField" placeholder="Race" disabled={true} />
<input type="text" id="txt_classField" placeholder="Class" disabled={true} />
<input type="text" id="txt_levelField" placeholder="Level" disabled={true} />
</Wrapper>
</Wrapper>
</>
)
So in the onClick function, it doesn't update the innerHTML of any element. Not sure why. I've tried inputting strings in VScode and in the page when I run npm start too but nothing seems to change them.
Screenshot of the app:
Looked for solutions but got nowhere so far. What am I doing wrong?
React avoids re-rendering unless state was changed. Since all of the changes happen on local variable scale and no state updates were caused by your onClick event, React will keep all HTML as it was.
Try holding the ID of the selected character in the state and hopefully you should see some updates of HTML.
So my child component has a function that renders textfields based on state.count and every time a user presses a button the state.count will go plus one. As result, more textfields will render. The textfields has onChange and value that take props. How can I make those props unique for each textfield. Here I am rendering my textfields:
let objects = [];
const teamVelden = () => {
for(let i = 0; i < this.state.count; i++){
objects.push(
<div>
<div className="col s5">
<TextField
id="standard-dense"
label="Teamlid volledige naam"
className={classNames(classes.textField, classes.dense)}
margin="dense"
value={this.props.teamlidValue}
onChange={this.props.onTeamlidChange}
error={this.props.tlnaamError === true ? true:false}
/>
</div>
<div className="col s6">
<TextField
id="standard-dense"
label="Teamlid email"
className={classNames(classes.textField, classes.dense)}
margin="dense"
value={this.props.teamlidEmailValue}
onChange={this.props.onTeamlidEmailhange}
error={this.props.tlemailError === true ? true:false}
/>
</div>
</div>
)
}
return objects;
};
In the mother component i'm currently giving the textfield values like this:
case 1:
return <StapTwee
teamlidValue={this.state.tlnaam}
onTeamlidChange={this.onTeamlidChange}
teamlidEmailValue={this.state.tlemail}
onTeamlidEmailhange={this.onTeamlidEmailhange}
/>;
These values need to get dynamic as well I assume.
I think I'm going crazy. I have 2 nearly identical pieces of code and in 1 of them the keyword this references the correct scope while in the other it doesn't. I've been staring at it for 3 hours and need other eyes.
The first function is this:
renderField({input, options, label, name, multi}){
let list = options.map(category=>{
return {value:category.name, label:category.name}
});
return(
<div>
<label>{label}</label>
<Select
value={this.state.selected}
multi={multi}
name={name}
className="basic-multi-select"
classNamePrefix="select"
options={list}
onChange={(e)=>{
this.setState({selected:e});
input.onChange(e);
}}
/>
</div>
)
}
the this I'm referring to is the line this.setState({selected:e});. This code works. the 'this' is called in the correct scope. I needed to refactor the code so I wrote another function in a higher level component and bound it to that class. I then proceeded to chane the above to the following:
renderField({defaultValue, input, options, label, name, multi, initialValues}){
let list = options.map(category=>{
return {value:category.name, label:category.name}
});
return(
<div>
<label>{label}</label>
<Select
value={this.props.selected}
multi={multi}
name={name}
className="basic-multi-select"
classNamePrefix="select"
options={list}
onChange={(e)=>{
this.props.changeState(this.props.state_handler, e);
input.onChange(e);
}
}
/>
</div>
)
}
suddenly this is no longer in scope and is now pointing at the e argument that I'm passing in. Why is this happening and how can I fix it?
In event handler, this means the event target.
So you should set a variable to remember the this in renderField.
Here's an example with comment.
renderField({defaultValue, input, options, label, name, multi, initialValues}){
let list = options.map(category=>{
return {value:category.name, label:category.name}
});
// set that to current this
let that = this;
return(
<div>
<label>{label}</label>
<Select
value={this.props.selected}
multi={multi}
name={name}
className="basic-multi-select"
classNamePrefix="select"
options={list}
onChange={(e)=>{
// this.props.changeState(this.props.state_handler, e);
// use that instead
that.props.changeState(that.props.state_handler, e);
input.onChange(e);
}
}
/>
</div>
)
}
I am creating a react input component and need to show the character limit underneath the input ex: (0/500 characters remaining). I have passed the maxLength as a prop into the input component but am unsure of how to show the number of characters remaining before the limit is reached.
The max length works properly - how can I add the visual feedback of showing how many characters are remaining (2/500 characters... etc).
<input
{...customAttributes}
maxLength={maxLength}
required={required}
/>
And then I call my component like so:
<InputComponent maxLength={10} />
The question does not have enough information to answer correctly, but based on the reaction to the comment, something like this should work:
<div>
{this.props.maxLength - this.state.whateverYouNamedTheValue.length}/{this.props.maxLength}
</div>
In the context of a component, cleaned up with ES6 a bit:
class InputComponent extends React.Component {
// ... class and state stuff ...
render() {
const { maxLength } = this.props;
const { whateverYouNamedTheValue } = this.state;
return (
<div>
<input
{...customAttributes}
maxLength={maxLength}
required={required}
/>
{ whateverYouNamedTheValue ? (
<div>
({ maxLength - whateverYouNamedTheValue.length }/{ maxLength })
</div>
) : null }
</div>
);
}
}
I use React Material-UI for my project. I put many components in render method. Then weird things happened. Some components can not be referred by 'this.refs.REFNAME'. And then I checked 'this.refs' object, it shows as the pic below:
As you can see, only some of the components, which can be referred, are showed on the first line. I don't understand why. Can anyone explain it to me? Thanks lot.
Update: Thanks to James, I get it that the first line should be the status of 'this.refs' at that moment. But still, why some of the components are not in the refs object?
Here's the relevant part of code:
render(){
return <div>
<Table ref='fromform'>
<TableHeader>
<TableRow>
<TableHeaderColumn tooltip='The ID'>No.</TableHeaderColumn>
<TableHeaderColumn tooltip='The Name'>Name</TableHeaderColumn>
<TableHeaderColumn tooltip='The Status'>Notes</TableHeaderColumn>
</TableRow>
</TableHeader>
<TableBody ref='fromformb'>
{playerList.map(function(player, index){
return <TableRow onTouchTap={this._onShowInfo.bind(this, index)} key={'row' + index}>
<TableRowColumn>{index + 1}</TableRowColumn>
<TableRowColumn>{player.name}</TableRowColumn>
<TableRowColumn>{player.notes}</TableRowColumn>
</TableRow>;
}.bind(this))}
</TableBody>
</Table>
<Dialog
title='Player Info'
ref='playerInfoDialog'>
<form role='form' ref='fromfo'>
<div className='form-group' ref='frowwmformb'>
<TextField type='text' hintText='Player Name' ref='txtName' fullWidth={true} />
<TextField type='text' hintText='Notes' ref='txtNotes' fullWidth={true} />
</div>
</form>
</Dialog>
<MainButtonGroup page='players' />
<Spinner />
</div>;
}
_onShowInfo(index){
var player = playerList[index];
console.log(this.refs);
this.refs.playerInfoDialog.show();
this.refs.txtName.setValue(player.name);
this.refs.txtNotes.setValue(player.notes);
}
}
What I want to do with this code is to generate rows in a table with player list, and when I tap a row, a dialog shows up with the data of the row.
But the two 'TextField's with refs of 'txtName' and 'txtNotes' can't be referred(as on the last 2 lines, produce errors). The pic above is produced by 'console.log' in '_onShowInfo' method.
I added some 'ref's with random names just to test.
I found a solution. Change _onShowInfo as below:
_onShowInfo(tid){
var player = playerList[index];
this.refs.playerInfoDialog.show();
setTimeout(function(){
console.log(this.refs);
this.refs.name.setValue(player.name);
this.refs.notes.setValue(player.notes);
}.bind(this), 0);
}
But I don't know why.
This happens because when the dialog is hidden, its children are not mounted yet. So the refs defined in the children are not set yet.
You see them in the console, though, as Chrome automatically updates it when it gets set because there is referential equality between the old this.refs and the new one. If you want to log the refs at a given point in time and make sure it is not updated by Chrome, you could do : console.log({ ...this.refs })
Another approach would be to hold a reference to the selected player in your component's state. Then you would have:
_onShowInfo(tid){
var player = playerList[index];
this.setState({selectedPlayer: player});
}
and
<Dialog
title='Player Info'
open={ !!this.state.selectedPlayer }
>
<form role='form'>
<div className='form-group'>
<TextField type='text' hintText='Player Name' defaultValue={ this.state.player.name} fullWidth={true} />
</div>
</form>
</Dialog>