how to create an array of arrays in react? - javascript

I'm trying to code a wordle clone using React, but the twist is that the player can choose the number of attempts and the length of the word. And i want to rendre the box depending on these two parameter so i used the following line :
var grid = Array(this.props.nbrAttempts).fill(0).map(row => new Array(this.props.wordLenght).fill(' '))
the first time the component render i get a 4*4 array, but after changing the parameter i get always a 1*1, and i can't figure what's the problem.
the Box component:
function App() {
const [boxParam, setBoxParam] = useState({nbrAttempts: 4, wordLenght : 4,});
let renderBox = ()=>{
setBoxParam({
nbrAttempts: document.getElementById('nbAttempts').value,
wordLenght : document.getElementById('wordLength').value,
})
}
return (
<div className="App">
{/* add input field with number of attempts as label */}
<label htmlFor="nbAttempts">Attempts</label>
<input type="number" id="nbAttempts"/>
<label htmlFor="nbAttempts">Word length</label>
<input type="number" id="wordLength"/>
<button onClick={()=>renderBox()}>OK</button>
<Box nbrAttempts={boxParam.nbrAttempts} wordLenght={boxParam.wordLenght} />
</div>
);
}

I just replaced
var grid = Array(this.props.nbrAttempts).fill(0).map(row => new Array(this.props.wordLenght).fill(' '))
with
let grid = [];
for (let i = 0; i < this.props.nbrAttempts; i++) {
grid.push(new Array(this.props.wordLenght).fill('_'));
}
and everything just worked fine

Related

How to preserve spacing when storing a string into an array? JavaScript React.js

I have a form with a <textarea>. On submit that string gets stored into an array. Sometimes the strings have blank lines or additional spacing and I want to preserve this spacing. Right now, the only spacing preserved is the spacing between words. The handleSubmit component consist of a useRef hook that is pushed into the array. I'm looking for another approach for storing the string that would preserve spacing. I appreciate all ideas! Thank you for your time!
const textAreaRef = useRef();
const [entryArray, setEntry] = useState([]);
const handleSubmit = (event) => {
event.preventDefault();
const updatedList = [...entryArray];
updatedList.push(textAreaRef.current.value);
textAreaRef.current.value = ""; // Clears value
setEntry(updatedList);
}
return (
<div>
<form class="entryForm" onSubmit={handleSubmit} >
<label for="newEntryId">
<span>New Entry:</span>
<textarea type="text" id="newEntryId" name="newEntryName" rows="30" cols="75"
defaultValue="What's on your mind?" ref = {textAreaRef}
/>
</label>
<button type="submit">Submit</button>
</form>
</div>
)
Can't replicate the issue, works fine.
Vanilla js example, but works the same in React
const area = document.querySelector('textarea')
const button = document.querySelector('button')
const saved = []
button.addEventListener('click', () => {
saved.push(area.value)
area.value = ''
console.log(saved)
})
<textarea></textarea>
<button>save</button>

How to dynamically add and remove text input fields in Svelte correctly?

I am new to Svelte and web development and I hope you could point me in the right direction.
The current code belongs in a svelte component.
As shown here: https://svelte.dev/repl/f0e5c30117724ec38b7d19781d2c4de6?version=3.48.0
It is supposed to show one text field by default, while allowing for an additional text field to be added and removed on dynamically added buttons.
Currently, this code can dynamically add the text field, however, it cannot dynamically remove the text field on button click.
I believe there might be an error in the GetDynamicElement function. However, I am not sure where exactly. Any suggestions?
p.s. I know there are answers here that are close, but I don't think they are applicable in this situation, especially on Svelte.
<script>
var num_links = 1;
let container;
const GetDynamicElement = (value) => {
return (
'<input name = "DynamicField" type="text" size =111 id =link placeholder="Enter Next link! " value = "' +
value +
'" />' +
'<input type="button" value="Remove" on:click = {RemoveField(this)}>'
// "RemoveSuggestionCart(this)" />'
);
};
const addField = () => {
if (num_links < 2) {
console.log("addField");
const div = document.createElement("DIV");
div.innerHTML = GetDynamicElement("");
container.appendChild(div); // Append timetable space
num_links += 1;
}
};
//Removes the entire division inclusive of it's text field.
const RemoveField = (div) => {
console.log("RemoveField");
div.removeChild(div.parentNode);
num_links -= 1;
};
</script>
<div>
<input
name="DynamicField"
type="text"
size="121"
id="link"
placeholder="Enter First Link!"
/>
<div bind:this={container} />
</div>
<button on:click|preventDefault={addField}>[+ add timetable link]</button>
<style>
</style>
Add/ remove fields and have a button to log or send to endpoint or whatever with "Log" button.
<script>
// to display one empty inputs before clicking add needed
let values=[{
"url": "",
"name": "",
}];
const addField = () => {
values = [...values, {url: '', name: ''}]
};
const removeField = () => {
values = values.slice(0, values.length-1)
};
</script>
{#each values as v, i}
<div>
<input id={i} type="text" bind:value={values[i].url} placeholder="url"/>
<input id={i} type="text" bind:value={values[i].name} placeholder="name"/>
</div>
{/each}
{#if values.length >= 2}
<input type="button" value="Remove" on:click={removeField}>
{/if]
<button on:click|preventDefault={addField}>Add</button>
<button on:click={() => console.log(values)}>Log Me</button>
Try: https://svelte.dev/repl/2441993f8d9946aa894bf07a8a8f9b4f
Edited: thanks #Corrl - edited nicer.
You can use your num_link and svelte's #each to create to inputs using svelte:
{#each Array(num_links) as _, i}
<div>
<input
name="DynamicField"
type="text"
size="121"
id={`link_${i}`}
placeholder="Enter First Link!"
/>
</div>
{/each}
Working example: https://svelte.dev/repl/04169e030b6944258cfd07af15873b48?version=3.48.0

how to disable a button if more than once check box is checked in React JS

I have to create a button that activates when a check box is checked and disables when unchecked.
I was able to achieve this by the following code.
import React from "react";
import "./styles.css";
import{useState} from 'react'
export default function App() {
const [change, setChange] = useState(true);
function buttonHandler(){
setChange(!change)
}
return (
<div className="App">
<button disabled={change}>Click Me</button>
<input type="checkbox" onChange={buttonHandler}/>
<input type="checkbox" onChange={buttonHandler}/>
<input type="checkbox" onChange={buttonHandler}/>
</div>
);
}
Now I have another challenge where I have to keep it disabled if more than 1 check box is checked. I tried to use object and array manipulation but it does not work. Any advice on how this can be achieved.
import React from "react";
import{useState} from 'react'
export default function App() {
const [checkboxStatus, setCheckboxStatus] = useState(Array(3).fill(false));
function buttonHandler(index){
let status = [...checkboxStatus];
status[index] = !status[index]
setCheckboxStatus(status)
}
return (
<div className="App">
<button disabled={checkboxStatus.filter(status => status === true).length != 1}>Click Me</button>
{Array(3).fill(0).map((_, index) => <input type="checkbox" checked={checkboxStatus[index]} onChange={() => buttonHandler(index)}/>)}
</div>
);
}
You can do that by keeping track of the status of the checkbox rather than tracking the status of the button. This is because if you know the status of all the checkboxes, you can easily calculate the status of the button.
I have also taken the liberty of converting the checkbox to map it since the content is the same. You can do the same by passing the index to each of them. Something like <input type="checkbox" onChange={() => buttonHandler(0}/> and so on for each of the inputs.
Wrap your input elements in a parent element like form or div.
Maintain state; an array that contains each box status (either true or false). When a box is changed call the handleChange which will update the state.
The button disabled property should call a function called isDisabled which will check to see if there are zero boxes checked or more than one box checked, returning true if the condition is matched.
const { useEffect, useState } = React;
function Example() {
const [boxes, setBoxes] = useState([]);
// In the text I suggested wrapping the inputs in
// a parent element. This was so we could use the following
// code to find its index within the list of inputs
// without adding any more code to the JSX
// Cribbed from https://stackoverflow.com/a/39395069/1377002
function handleChange(e) {
// Destructure the children from the parent of
// the element that was changed (ie all the input elements)
const { parentNode: { children } } = e.target;
// Find the index of the box that was changed
const index = [...children].indexOf(e.target);
// Copy the state
const newState = [...boxes];
// Toggle the boolean at the index of
// the `newState` array
newState[index] = !newState[index];
// Set the state with the updated array
setBoxes(newState);
}
// `filter` the boxes that return true.
// Return true if the length is 0 or > 1.
function isDisabled() {
const len = boxes.filter(box => box).length;
return len === 0 || len > 1;
}
return (
<div className="App">
<button disabled={isDisabled()}>Click Me</button>
<form>
<input type="checkbox" onChange={handleChange}/>
<input type="checkbox" onChange={handleChange}/>
<input type="checkbox" onChange={handleChange}/>
</form>
</div>
);
}
ReactDOM.render(
<Example />,
document.getElementById('react')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>
Additional documentation
Destructuring assignment
Spread syntax

Adding And Sorting Array Of Integers from html input field Using Javascript

The Task Is To Get 10 Values Of Array Through HTML Input Field
And Sort Them In Acceding Order
In Order To Append 10 Value's from Html Input field To JS Array I Created one input field which data is passed to array in js and Two labels to keep track of array using innerHTML Method
Note:- The Name Of Array Is itself declared array
whenever a button is hit the input value of html data is appended to js array
using id of input field
and the resulted array is shown to label list every time we insert a new digit to array
and the next label similar to this updates array lenght simantaeneously
to limit it upto 10 index i compare array.lenght with 10th value i.e. 9th index
Note:- Here Array index is starting from 0 so 9th index is 10th digit
But even Though Code Is Not Working Well
Here's my code looks like
HTML File
<div id='div3'>
<input type='number' id='ip1' placeholder='Enter values'></input>
<label id='list' >List values are:</label>
<button id='bt3' onClick='task()'>ADD Value</button>
<label id='len' >Length:</label>
</div>
JS FIle
var array =[];
function task()
{
let pr=array.length;
document.getElementById('len').innerHTML=pr;
if(array.length > 9)
{
let item = document.getElementById('task3val').value;
array.push(item);
document.getElementById('list').innerHTML=array;
}
if(array.length<=9)
{
array.sort(function(a, b){return b - a});
document.getElementById("list").innerHTML = array;
}
}
Please Give Insighful Answer
I have made few changes in your code, It should work for you now. in the above code, you were using the wrong id for the text box
HTML code
<div id='div3'>
<input type='number' id='ip1' placeholder='Enter values'></input>
<br/>
<label id='list' >List values are: </label>
<br/>
<button id='bt3' onClick='task()'>ADD Value</button>
<br/>
<label id='len' >Length:</label>
</div>
Jquery code
<script type="text/javascript">
var array =[];
function task()
{
if(array.length < 3)
{
let item = document.getElementById('ip1').value;
array.push(item);
document.getElementById('list').innerHTML = array.toString();
}
else
{
alert('Only 10 Items allowed!')
}
let pr=array.length;
document.getElementById('len').innerHTML=pr;
}
</script>
If I'm getting it right, this is your solution:
var array =[];
function task()
{
let item = document.getElementById('ip1').value;
array.push(item);
let pr=array.length;
document.getElementById('len').innerHTML= "Length: "+pr;
array.sort(function(a, b){return b - a});
document.getElementById("list").innerHTML = array;
if(pr>=10){
array.pop()
//This removes the last element,
//since it is always ordered, last element is always the smallest
}
}
<div id='div3'>
<input type='number' id='ip1' placeholder='Enter values'></input>
<label id='list' >List values are:</label>
<button id='bt3' onClick='task()'>ADD Value</button>
<label id='len' >Length:</label>
</div>
I am not sure what you were trying to do with that if statement, but the long story is you should first add the item in the array, then the length should return the correct length (so, 1 if there is 1 item, 2 if there are 2, etc.) and then re-order the array and print it on screen
EDIT: I guess you only want to keep the biggest 10 numbers at any time, so what we do is we simply remove the last element once pr reaches 10
this way ?
const
array = []
, arrLimit = 10
, in_ip1 = document.querySelector('#ip1')
, lb_list = document.querySelector('#list')
, bt_bt3 = document.querySelector('#bt3')
, lb_len = document.querySelector('#len')
, errors =
{ noVal : 'please enter a number value'
, outLimit : `Only ${arrLimit} Items allowed!`
, exist : 'value already entered !'
}
bt_bt3.onclick = () =>
{
let inVal = in_ip1.valueAsNumber
if ( isNaN(inVal) ) alert( errors.noVal )
else if (array.length >= arrLimit) alert( errors.outLimit )
else if (array.includes(inVal)) alert( errors.exist )
else
{
array.push( inVal )
array.sort((a,b)=>b-a) //.splice( arrLimit )
lb_list.textContent = array.join(', ')
lb_len.textContent = array.length
}
}
#div3 > * {
display : block;
float : left;
clear : left;
margin : .5em;
}
#list:before { content: 'List values are: ' }
#len:before { content: 'Length: ' }
<div id="div3">
<input id="ip1" type="number" placeholder="Enter values">
<label id="list" ></label>
<button id="bt3">ADD Value</button>
<label id="len" ></label>
</div>

Render number of elements based on users input

I am trying to render multiple Input elements based on number that user enters. I store the value in my count constant that dynamically changes. Then in my returnForm function I am trying to return the elements using for loop, but with no luck.
const returnForm = () =>
{
let items = [];
for (var i = 0; i < count; i++)
{
items.push(
<div key={i}>
<TextInput source="name" validate={required()} />
<br></br>
<ArrayInput source="tags" label="resources.vid.fields.tags" style={{ width: '40%' }}>
<SimpleFormIterator>
<TagsEdit addLabel={true} label="resources.vid.fields.tag" />
</SimpleFormIterator>
</ArrayInput>
<br></br>
<TagsList addLabel={true} label="resources.vid.fields.tagsList" />
</div>
);
return items;
}
}
Elements are only rendered one time even though value of count is different. Any ideas what am I doing wrong?
Thank you in advance.
try to move return out of loop

Categories

Resources