I made this button handle function, when clicked it will check the entered character against the stored "hangman" word.
If the letter exists in the string it shows its correct and increase
"guesses"
If it isn't present it will increase both "guesses" and "incorrect"List item
If the letter has already been tried or contains "" / " " it will do
nothing
However the functionality is acting strange, initially putting in "a" will show that it is not currently stored, the lives is default yet the guesses is still 0, it is not updating guesses.
Then inputting "b" shows it is not stored and incorrect. However it does not add a value to incorrect.
Inserting "b" on the next input shows it is stored. However correctly displays lives.
Lastly this functionality doesnt seem to work at all when removing the
This functionality just seems really strange to me. Not sure where i am going wrong
Console output:
Objecthint:
hint: "the start of something"
id: 1
title: "initial"
value: 1
word: "initial"
Hangman.js:62 not stored
Hangman.js:77 lives5
Hangman.js:78 guesses0
Hangman.js:79 incorrect0
Hangman.js:72 not stored and incorrect
Hangman.js:77 lives5
Hangman.js:78 guesses1
Hangman.js:79 incorrect0
Hangman.js:52 stored
Hangman.js:77 lives4
Hangman.js:78 guesses1
Hangman.js:79 incorrect1
code:
const [letter, setLetter]=useState('')
const [letters, setLetters]=useState([])
const [guesses, setGuesses]=useState(0)
const [incorrect, setIncorrect]=useState(0)
const [lives, setLives]=useState(5)
var hangman = { id:1,title:"initial",word:"initial",hint:"the start of something",value:1}
const handleInputButton = (e) => {
e.preventDefault();
if (letter !== "" && letter !== " "){
if (letters.includes(letter))
{
console.log("stored")
// show that this letter is correct
}
// doesnt update lives when incorrect until second click of same character?
else{
if ( hangman.word.toUpperCase().includes(letter.toUpperCase()) ) {
console.log("not stored")
letters.push(letter)
setGuesses(guesses + 1)
// update display here
}
else{
letters.push(letter)
setIncorrect(incorrect + 1)
setLives(lives - 1 )
console.log("not stored and incorrect")
}
}
}
console.log("lives" + lives)
console.log("guesses" +guesses)
console.log("incorrect" + incorrect)
}
const [Attempt, setAttempt] =([]);
const handleSubmitButton = (e) => {
e.preventDefault();
console.log("submit")
// put request here to post
}
const handleHint = (e) => {
e.preventDefault();
// reveal hint text here
console.log("hint")
}
return (
<div className='app'>
<br/> <br/> <br/> <br/> <br/> <br/>
{/* display will go here */}
<img alt="hangman figure"/>
<br/> <br/>
{/* current lives will go here */}
<p> lives: {lives} </p>
{/* attempted letters will go here */}
<ul> attempted letters:
{letters.map(letter=>(
<li className="tag auto" key={letters.indexOf(letter)}> <p> {letter} </p> </li>
))}
</ul>
<Form>
<div className="form-group">
<input value={letter} onChange={(e)=>setLetter(e.target.value)}
type="text" className="form-control stuff" id="letter" placeholder="Enter Letter" required/>
</div>
<br/> <br/>
<Button onClick={handleInputButton} type="buton" className="btn btn-primary submit" id="submit">Submit</Button>
</Form>
<br/> <br/> <br/> <br/>
{/* hint button */}
<Button>Hint</Button>
<p> {hangman.hint} </p>
<br/> <br/>
{/* finalise button */}
<Button onClick={handleSubmitButton} type="buton" className="btn btn-primary submit" id="submit">Finalize</Button>
{/* {showResult ? (
<div className='result'>
Your result is {result} of {questionList.length}
</div>
) : (
<>
<div className='question'>
<div className='index'>
<span>Question {current + 1}</span>/{questionList.length}
</div>
<div className='text' onCopy={handleCopy} >{questionList[current].question}</div>
</div>
<div className='answer-section'>
{questionList[current].answers.map((answer, index) => (
<button key={answer.id} onClick={()=> handleAnswerButton(answer.correct, startTime, timeLimit)}>{answer.content}</button>
))}
</div>
</>
)} */}
</div>
);
}
Related
My code has got 3 input fields i.e first name, last name, email and 1 useState to hold its value, I want to remove the div part containing all the input fields after i hit Sign up and display only Thank You
My code has got 3 input fields i.e first name, last name, email and 1 useState to hold its value, I want to remove the div part containing all the input fields after i hit Sign up and display only Thank You
Before signing up
AFter signing up
const Home = () => {
const [saveInput, setInput] = useState({
fname: '',
lname: '',
email: '',
});
const [message, setMessage] = useState('enter email');
const inputFields = (event) => {
const { value, name } = event.target;
setInput((preValue) => ({
...preValue,
[name]: value,
}));
};
const onSubmits = (event) => {
setMessage('thanks');
};
return (
<div className="homeMain">
<div className="row">
<img
className="home_img"
src="https://i.pinimg.com/originals/53/b5/d7/53b5d70023efa05ec6797b25df413b73.jpg"
/>
<h1 className="home_h1 text-center">Maryam's Restaurant</h1>
<Link
style={{
color: 'white',
textDecoration: 'inherit',
textAlign: 'center',
}}
to="/Restaurant"
className="home_button"
>
View Menu
</Link>
<h2 className="home_h2 text-center">
Binging with Babish is a cooking show dedicated to discovering what
the delectable (and occasionally horrible) foods from fiction actually
taste like.
</h2>
{receipeList.map((curElem) => (
<div className="home2Main">
<img className="home_img2" src={curElem.img} />
<p className="home2Mainp1">{curElem.h1}</p>
<p className="home2Mainp2">{curElem.date}</p>
</div>
))}
</div>
<homeMainDetails />
<div className="home4Main">
<h4>
<bold>Subscribe</bold>
<br />
<small>
Sign up with your email address to receive news and updates.
</small>
</h4>
<input
className="home4MainInput"
name="fname"
onChange={inputFields}
value={saveInput.fname}
type="text"
placeholder="First Name"
/>
<input
className="home4MainInput"
name="lname"
onChange={inputFields}
value={saveInput.lname}
type="text"
placeholder="Last Name"
/>
<input
className="home4MainInput"
name="email"
onChange={inputFields}
value={saveInput.email}
type="text"
placeholder="Email Address"
/>
<button onClick={onSubmits}>Sign Up</button>
<h4 className="home4Mainh4">
<small>{message}</small>
</h4>
</div>
</div>
);
};
export default Home;
You could use another state to indicate your submit state.
This way you can hold state value without affecting to the message state:
Use another state:
const [isSubmited, setIsSubmited] = useState(false);
Change that state when you submit:
const onSubmits = (event) => {
setMessage('thanks');
setIsSubmited(true);
};
Then render it conditionally:
{isSubmited ? (
<div className="home4Main">
...
</div>
) : message}
You can do it with a basic condition message !== "Thank you" like this:
<div className="home4Main">
{message !== "Thank you" && (
<>
<h4>
<bold>Subscribe</bold>
<br />
<small>Sign up with your email address to receive news and updates.</small>
</h4>
<input
className="home4MainInput"
name="fname"
onChange={inputFields}
value={saveInput.fname}
type="text"
placeholder="First Name"
/>
<input
className="home4MainInput"
name="lname"
onChange={inputFields}
value={saveInput.lname}
type="text"
placeholder="Last Name"
/>
<input
className="home4MainInput"
name="email"
onChange={inputFields}
value={saveInput.email}
type="text"
placeholder="Email Address"
/>
<button onClick={onSubmits}>Sign Up</button>
</>
)}
<h4 className="home4Mainh4">
<small>{message}</small>
</h4>
</div>
And update message
const onSubmits = (event) => {
setMessage('Thank you');
};
Create a useState that contains the value on the state of the form.
const [isSubmited, setIsSubmited] = useState(false);
Then use this value in the JSX to conditional render the elements you want to display.
isSubmitted ? <div> Thank You! </div> : <div> your form.... </div>
You can call setIsSubmited(true) when you submit the form.
I am using react-hook-form for the validation of my form in react.
What I am doing
I have one select dropdown, which has some numbers as a dropdown.
On change of select dropdown I am creating the input field, if 2 is selected then 2 input field, initially one is there by default.
Now when I select 2 or 3 options and create 2-3 input fields, on click of a button it is only taking last field validation as well as giving me the last field value only.
In react-hook-form we use ref to hold the value of particular input and for validation as well.
But here it is only validating the last one only, I do not know what I am missing.
This is what I am doing.
<div className="row">
{[...Array(inputHolder).keys()].map((li, index) => (
<div className="col-12 col-sm-12 col-md-8 col-lg-4 col-xl-4">
<div className="form-group">
<input
type="text"
name="name"
id={'name' + index}
className="form-control"
placeholder="F Name"
ref={register({required: 'F name is required'})}
/>
<label className="common_label_form" htmlFor={'name' + index}>
F Name
</label>
{errors.name && (
<div>
<span className="text-danger">{errors.name.message}</span>
</div>
)}
</div>
</div>
))}
</div>;
This my code sandbox
I need to make my refs dynamic but I don't know how can I achieve that.
I want to have data like [{ name: 'name1' }, { name: 'name2' }], that's why I have been stuck, once I will get data then I can push it inside array.
When using form, any input elements (input, select...) inside it is identified via a name attribute, not id as you may think.
Solution 1:
map(_, index) => (
<input
name={`name[${index}]`}
ref={register}
/>
)
When you log the submit data, here is what it looks like
{
"name": ["1", "2", "3"]
}
Error displaying:
{errors.name && errors.name[index] && (
<div>
{errors.name[index].message}
</div>
)}
Solution 2:
map(_, index) => (
<input
name={`data[${index}].name`}
ref={register}
/>
)
Output
{
"data": [
{ "name": "1" },
{ "name": "2" },
{ "name": "3" }
]
}
Error displaying
{errors.data && errors.data[index] && errors.data[index].name && (
<div>
{errors.data[index].name.message}
</div>
)}
Solution 3:
map(_, index) => (
<input
name={`name_${index}`}
ref={register}
/>
)
Output:
{
"name_0": "1",
"name_1": "2",
"name_2": "3"
}
Error displaying:
{errors["name_" + index] && (
<div>
{errors["name_" + index].message}
</div>
)}
Live Demo
I think you shoud simply change the input name li ke this
...
<input
type="text"
name={'name' + index} // you should change this
id={'name' + index}
className="form-control"
placeholder="F Name"
ref={register({required: 'F name is required'})}
/>
...
I am trying to use the concept of field array because in my app a user should be able to fill multiple value for same kind of field. I could do as per redux-form field array example, however, in an example there is no initial field we have to first click on add member and then only we can have the field to fill the value but i need one field initially and then add further field if user wants to.
I tried from the redux-form example but its not allowing me to input the value at all. Here is the demo
https://codesandbox.io/s/n47qr2pvzl
The format of that field value should be like this
general: {
general_information: {
members: [
{
name: ''
},
{
name: ''
}
]
}
}
Here is the code
const renderMembers = ({ fields, meta: { touched, error, submitFailed } }) => (
<ul>
<li>
<button type="button" onClick={() => fields.push({})}>
Add Member
</button>
{(touched || submitFailed) && error && <span>{error}</span>}
</li>
{fields.map((member, index) => (
<li key={index}>
<button
type="button"
title="Remove Member"
onClick={() => fields.remove(index)}
/>
<h4>Member #{index + 1}</h4>
<Field
name={`${member}.name`}
type="text"
component={renderField}
label="Name"
/>
</li>
))}
</ul>
);
const FieldArraysForm = props => {
const { handleSubmit, pristine, reset, submitting } = props;
return (
<form onSubmit={handleSubmit}>
<Field
name="general.general_information.clubName"
type="text"
component={renderField}
label="Club Name"
/>
<Field
name="general.general_information.members.name"
type="text"
component={renderField}
label="Name"
/>
<FieldArray
name="general.general_information.members"
component={renderMembers}
/>
<div>
<button type="submit" disabled={submitting}>
Submit
</button>
<button type="button" disabled={pristine || submitting} onClick={reset}>
Clear Values
</button>
</div>
</form>
);
};
According to Redux-Form, we can set the initial fields by specifying it like (in your case):
export default reduxForm({
form: "fieldArrays", // a unique identifier for this form
validate,
initialValues: {"general": {
"general_information": {
"members": [
{}
]
}
}
}
})(FieldArraysForm);
Here is the live demo
Hope it helps :)
I'm very new to Javascript and I'm trying to filter/update data based on a checkbox. If you see below I can filter the data based on values in the data I created (dataset2). Dataset3 is the problem... I want to click on the checkboxes and update the dataset based on the values that are checked.
First, I'm not sure how to pass the array of values into the filter (e.g. how would I pass "Books" && "Supplies" into the filter. As you can see in dataset2 I can only get it to equal "Books". Second, how do I get it to update when checkboxes are checked/unchecked. I created a fiddle for this also. Thanks you. https://jsfiddle.net/at2046/mqjyjfox/8/
var dataset = [['Books','GEB'],
['Books','Decision Theory'],
['Supplies','Pencil'],
['Supplies','Paper']
];
document.getElementById("demo").innerHTML = dataset;
var dataset2 = dataset.filter(function (el) {
return el[0] == "Books";
});
document.getElementById("demo2").innerHTML = dataset2;
$(":checkbox").change(function() {
var dataset3 = dataset.filter(function(el) {
var checkboxes = document.getElementsByName('result');
for (var index = 0; index < checkboxes.length; index++) {
return el[0] == checkboxes[index].value;
}
});
document.getElementById("demo3").innerHTML = dataset3;
});
First, you added a $(:checkbox'), which is a jQuery syntax and you didn't have the library loaded in your fiddle.
Then, you use a return inside the for, which means that at the first iteration (choice Books) the script will exit returning only the elements belonging to the first item in the choice list.
An option is to replace the for for a while to check if the el[0] exists in any of the choices.
Lastly, you weren't checking if the checkboxes are checked, which means it would return everything no matter the state of the check box.
$(":checkbox").change(function() {
var dataset3 = dataset.filter(function(el) {
var checkboxes = document.getElementsByName('result');
var index = 0;
var found = false;
while (index < checkboxes.length && !found) {
if (checkboxes[index].checked && el[0] == checkboxes[index].value) found=true;
++index;
}
return found;
});
document.getElementById("demo3").innerHTML = dataset3;
});
https://jsfiddle.net/mqjyjfox/10/
Here I used cuisines for my checkbox items. The following code snippet gives the logic for checkboxes filtering. handleCuisineChange is the function that contains the logic. The length of for loop is 8 since the number of cuisines (the number of checkbox items) I have taken here is 8. Replace the cuisines here with your checkbox data. Apply this logic and your checkbox items are ready for filtering.
Inside axios I used my own backend API getCuisine and port number 7000.
axios I used my own backend API getCuisine and port number 7000.
handleCuisineChange=(cuisine_id)=>
{
const {cuisineArray}=this.state; //an empty array declared in constructor
if (cuisineArray.indexOf(cuisine_id) == -1)
{
cuisineArray.push(cuisine_id);
}
else
{
var index=cuisineArray.indexOf(cuisine_id);
cuisineArray.splice(index,1);
}
const {cuisineArray2}=this.state; //an empty array declared in constructor
let i=0;
for (i=0;i<8;i++)
{
if(cuisineArray[i]==undefined)
{
cuisineArray2[i]=cuisineArray[0];
}
else
{
cuisineArray2[i]=cuisineArray[i];
}
}
this.props.history.push(`/checking3?cuisine_id1=${cuisineArray2[0]}&cuisine_id2=${cuisineArray2[1]}&cuisine_id3=${cuisineArray2[2]}&cuisine_id4=${cuisineArray2[3]}&cuisine_id5=${cuisineArray2[4]}&cuisine_id6=${cuisineArray2[5]}&cuisine_id7=${cuisineArray2[6]}&cuisine_id8=${cuisineArray2[7]}`);
let filterObj={cuisine_id1:cuisineArray2[0],cuisine_id2:cuisineArray2[1],cuisine_id3:cuisineArray2[2],cuisine_id4:cuisineArray2[3],cuisine_id5:cuisineArray2[4],cuisine_id6:cuisineArray2[5],cuisine_id7:cuisineArray2[6],cuisine_id8:cuisineArray2[7]};
axios(
{
method:'POST',
url:`http://localhost:7000/getCuisine`,
headers:{'Content-Type':'application/json'},
data:filterObj
}
)
.then(res=>
{
this.setState({restaurants:res.data.restaurants});
})
.catch(err=>console.log(err))
}
render()
{
const {restaurants}=this.state;
return(
<div>
<input type="checkbox" name="cuisines" id={"1"} onChange={(event) => this.handleCuisineChange("1")} />
<span className="checkbox-items" > North Indian </span> <div style={{display: "block"}}> </div>
<input type="checkbox" name="cuisines" id={"2"} onChange={(event) => this.handleCuisineChange("2")} />
<span className="checkbox-items" > south indian </span> <div style={{display: "block"}}> </div>
<input type="checkbox" name="cuisines" id={"3"} onChange={(event) => this.handleCuisineChange("3")} />
<span className="checkbox-items" > chinese </span> <div style={{display: "block"}}> </div>
<input type="checkbox" name="cuisines" id={"4"} onChange={(event) => this.handleCuisineChange("1")} />
<span className="checkbox-items" > fast food </span> <div style={{display: "block"}}> </div>
<input type="checkbox" name="cuisines" id={"5"} onChange={(event) => this.handleCuisineChange("1")} />
<span className="checkbox-items" > Street food </span> <div style={{display: "block"}}> </div>
<input type="checkbox" name="cuisines" id={"6"} onChange={(event) => this.handleCuisineChange("1")} />
<span className="checkbox-items" > American </span> <div style={{display: "block"}}> </div>
<input type="checkbox" name="cuisines" id={"7"} onChange={(event) => this.handleCuisineChange("1")} />
<span className="checkbox-items" > Italian </span> <div style={{display: "block"}}> </div>
<input type="checkbox" name="cuisines" id={"8"} onChange={(event) => this.handleCuisineChange("1")} />
<span className="checkbox-items" > Mexican </span> <div style={{display: "block"}}> </div>
</div>
)
} //render end
I have an array of emails (as a part of a bigger model). These are displayed in seperate rows witha remove button for each (the address itself can be updated in the input box directly). Unfortunately I dont know how to do this in react when the inputs are renderd using a map function.
(I am converting a meteor blaze project to meteor react).
Everything renders but how do I attach to change event so I can update my array of emails? onChange + value need to be set somehow.
This is the map function
return this.data.emailGroup.emails.map((email) => {
return (
<div key={email} className="input-group">
<input type="text" className="form-control" onChange={self.handleEmailListChange} value={email}/>
<div className="input-group-btn">
<button type="button"
className="btn btn-default remove-email"><span
className="glyphicon glyphicon-remove"></span></button>
</div>
</div>
);
});
The initial state(which is populated with data from the db:
getInitialState() {
return {
name : '',
description: '',
emails : [],
newEmailAddress : ''
}
},
Upon request here is the render method(it requires a getContent method.The getcontent method is there because in meteor I need to wait for data so in the meantime I need a loading state.
getContent() {
return (
<div className="box box-success">
<div className="box-header with-border">
<h3 className="box-title">List of emails</h3>
</div>
<form role="form" className="form-horizontal">
<div className="box-body">
<p>Below is a list of email addresses which are added to this email group. If
you
want
to add more
you can add them one by one by inputting in the box below or add a list into
the
same box (email
addresses have to be seperated by either a space or ;) then press Add to add
to
the
list. You can edit
the addresses directly as well as remove them.</p>
<div className="input-group">
<input type="text" className="form-control"
value={this.state.newEmailAddress}
onChange={this.handleAddNewEmail}
placeholder="Email addresses seperated by a space or a semicolon ; i.e. test1#test.se;test2#test.se"/>
<span className="input-group-btn">
<button type="button" onClick={this.handleAddNewEmailButton} className="btn btn-info btn-flat add-email">Add</button>
</span>
</div>
<br/>
{this.renderEmail()}
</div>
</form>
</div>
)
},
render()
{
var contentStyle = {
minHeight : '946px'
};
return (
<div className="content-wrapper" style={contentStyle}>
<section className="content-header">
<h1>
{this.data.emailGroup? this.data.emailGroup.name : 'hello'}
</h1>
<small> Created by: Christian Klinton</small>
<br/>
<small> Last updated by: Christian Klinton - 2015-11-12 08:10:11</small>
<ol className="breadcrumb">
<li><i className="fa fa-dashboard"></i> Home</li>
<li>Email groups</li>
<li className="active">{this.data.emailGroup? this.data.emailGroup.name : 'loading'}</li>
</ol>
</section>
<section className="content">
<div className="row">
<div className="col-md-6">
<div className="box box-primary">
<div className="box-header with-border">
<h3 className="box-title">Information</h3>
</div>
<form role="form">
<div className="box-body">
<div className="form-group">
<label htmlFor="inputName">Name</label>
<input type="email" className="form-control" id="name"
onChange={this.handleNameChange}
placeholder="Set the name of the email group" autoComplete="off"
value={this.state.name}/>
</div>
<div className="form-group">
<label>Description</label>
<textarea className="form-control" rows="3" id="description"
placeholder="Enter a description what and how the template is used..."
onChange={this.handleDesriptionChange}
value={this.state.description}
></textarea>
</div>
</div>
</form>
</div>
</div>
<div className="col-md-6">
{this.data.emailGroup? this.getContent() : <p>Loading</p> }
</div>
<div className="form-group">
<div className="col-sm-offset-8 col-sm-4">
<div className="pull-right">
<button className="btn btn-primary">Delete all</button>
<button className="btn btn-primary save">Save</button>
</div>
</div>
</div>
</div>
</section>
</div>
)
}
React requires you to have something unique for every element in the rendered array, it's called a key, and it's an attribute.
If you don't know what to assign to the key, just assign it the array's indexes:
this.props.doors.map((door, index) => (
<div key={index} className="door"></div>
));
Here's the same solution applied to your problem:
return this.data.emailGroup.emails.map((email, index) => {
return (
<div key={index} className="input-group">
<input type="text"
className="form-control"
onChange={self.handleEmailListChange.bind(this, index)} value={email}/>
</div>
);
});
Notice how I bound handleEmailListChange to receive the index of the modified email. If handleEmailListChange accepts an index, it can update the modified email within the state:
handleEmailListChange: function(index, event) {
var emails = this.state.emails.slice(); // Make a copy of the emails first.
emails[index] = event.target.value; // Update it with the modified email.
this.setState({emails: emails}); // Update the state.
}
I believe what you're looking for is something like this:
MyPage = React.createClass({
mixins: [ReactMeteorData],
getMeteorData() {
// ...
},
render() {
const emails = this.data.emailGroup.emails.map((email) => {
return (
<div key={email} className="input-group">
<input type="text" className="form-control"
onChange={this.handleEmailListChange} value={email} />
<div className="input-group-btn">
<button type="button"
className="btn btn-default remove-email"><span
className="glyphicon glyphicon-remove" /></button>
</div>
</div>
);
});
return <div>
{emails}
</div>
}
});
I changed self to this. Since you're using the ES6 arrow function, there's no need to assign self = this.
You should place your Array.map directly inside your render() function. Just take care that each array element is wrapped inside a parent element (<div> here) and must have a unique key={}
class ArrayMap extends React.Component{
//your functions
handleEmailChanged(key){
// Handle email
}
render(){
return(
<div>
{
this.data.emailGroup.emails.map((email) => {
<div key={email.key}>
<button onClick={this.handleEmailChanged.bind(this,email.key)}/>
</div>
});
}
</div>
);
}
}