I m trying to make the default value for the input field from an array in the state..i could
put the values but after that i am not able to change the field any more ( it works wrong i can add only one letter which is strange )
(PS: there is only one input in my code ) :
when i change the value="" in the input it works but i need this table to contain the values from the state.
state ={
splitAmount : [ {
SplitAmount0: this.props.data.amount1
},
{
SplitAmount1: this.props.data.amount2
},
{
SplitAmount2: this.props.data.amount3
}
],
}
}
StopTyping = (event) => {
const self = this;
if (self.state.typingTimeout) {
clearTimeout(self.state.typingTimeout);
}
self.setState({
val : event.target.value,
name : event.target.name,
id : event.target.id,
typingTimeout: setTimeout(function () {
self.setAmount(self.state.name,self.state.id,self.state.val);
}, 1000)
});
}
setAmount=(name,id,val)=>{
this.removeSplitAmount(name);
let some=0;
for(var i=0;i<this.state.splitAmount.length;i++){
let splitAmountState=`SplitAmount${i}`;
some+=this.state.splitAmount[i][splitAmountState]
}
let newAmount=this.props.data.amount-(some+val);
if(some>0){
let newValues=[{[val]:val},{[`SplitAmount${id+1}`]:newAmount}]
let newSplitAmount=this.state.splitAmount.concat(newValues);
this.setState({splitAmount:newSplitAmount})
}
}
return(
<div>
{this.state.splitAmount.map((splitAmount,i)=>{
const splitAmountKey=i
return(
<table className="middle-table"key={i}>
<tbody>
<tr>
<th>DueDate</th>
<th>Status</th>
<th>Amount</th>
<th>VAT</th>
<th>Otherexpenses</th>
<th>SocialSecurity</th>
<th>Miscelaneous</th>
<th>TaxableAmount</th>
</tr>
<tr style={{height:40}}>
<td className="middle-table-
col">05.12.2018</td>
<td className="middle-table-colright-align">
{this.props.data.status}</td>
<td className="middle-table-colright-align">
<input className="tax-value" value=
{this.state.splitAmount[i][`SplitAmount ${i}`]} id={i} name=
{'SplitAmount'+i}
onChange=
{this.StopTyping}/>
</td>
<td className="middle-table-colright-align">
{this.props.data.vatAmount}</td>
<td className="middle-table-colright-align">
{this.props.data.otherExpenses}</td>
<td className="middle-table-colright-align">
{this.props.data.socialSecurityAmountIncluded}</td>
<td className="middle-table-colright-align">
{this.props.data.miscellaneousDeduction}</td>
<td className="middle-table-colright-
align"style={{backgroundColor:'#F4F6F8'}}>1000</td>
</tr>
</tbody>
</table>
)
})}
If you update state, never use the current state array or object: we always have to create a new structure and update the state with that. So, in your 'StopTyping' method (which should be renamed to 'taxValueChangeHandler', really!), say:
let newSplitAmount=[...this.state.splitAmount].concat(newValues);
It creates a new array with all values of splitAmount and concatenates that with the new values.
Then, in the input element, I'd always explicitly pass the event, if the event is needed in the method:
onChange={(e) => StopTyping(e)}
Hope this already helps!
Related
I have an issue of updating state values of a particular key. Using multiple radio button and textbox.
Here is my state
this.state = {
PStudent:[{"flag_sts":1,"id":8472229,"remark":null,"status":"P","studentid":"12010013"},
{"flag_sts":1,"id":8472218,"remark":null,"status":"P","studentid":"12108051"},
{"flag_sts":1,"id":8472219,"remark":null,"status":"P","studentid":"12108052"}
],
};
On change value on radio:
const handleChange = (e,studentid) =>{
this.setState({
data: this.state.PStudent.map(item=>{
if (item.studentid !== e.target.name) {
return item;
}else{
return{
studentid: studentid,
status : e.target.value
}
}
})
})
}
And this is sending parameter form radio:
{(Object.keys(this.state.PStudent).length > 0) ? (
this.state.PStudent.map((v)=>(
<tr>
<td>{v.studentid}</td>
<td><input type="radio" name={v.studentid} value="P" onChange={(e)=>handleChange(e,v.studentid)} defaultChecked={(v.status == "P") ? true:false} /> </td>
<td><input type="radio" name={v.studentid} value="A" onChange={(e)=>handleChange(e,v.studentid)} defaultChecked={(v.status == "A") ? true:false} /> </td>
<td><input type="text" name="remarks" value="" /> </td>
</tr>
))
) : ''}
Would you like to help me how to update some value of particular key? In this case i would like to update value from key 'status' by radio button and key 'remarks' by text box. And object from PStudent will auto updated with the new value after do handleChange() by radio.
Thank you for your consider.
You may want to make use of the dynamic key and index here.
The dynamic key would allow you to reuse the same function for the value change.
The index can be used to identify the object's index in the array.
const handleChange = (e, index, field) =>{
const newPStudent = _.cloneDeep(this.state.PStudent); // or you can use this.state.PStudent.map(i => I);
newPStudent[index][field] = e.target.value
this.setState({PStudent: newPStudent})
}
{(Object.keys(this.state.PStudent).length > 0) ? (
this.state.PStudent.map((v, index)=>(
<tr>
<td>{v.studentid}</td>
<td><input type="radio" name={v.studentid} value="P" onChange={(e)=>handleChange(e, index, 'status')} defaultChecked={(v.status == "P") ? true:false} /> </td>
<td><input type="radio" name={v.studentid} value="A" onChange={(e)=>handleChange(e, index, 'status')} defaultChecked={(v.status == "A") ? true:false} /> </td>
<td><input type="text" name="remarks" value="" onChange={(e)=>handleChange(e, index, 'remark')}/> </td>
</tr>
))
) : ''}
If you are using underscore.js in your project, it's best to use _.cloneDeep() as it creates an independent copy of the object.
You can use functional version of setState as:
Live Demo
handleChange = (e, studentid) => {
const status = e.target.value;
this.setState((state) => {
return {
PStudent: state.PStudent.map((item) => {
if (item.studentid !== e.target.name) return item;
else return { ...item, status };
})
};
});
};
The count outside the handleCheckCount function is 0, so how can pass down the actual count of the checked boxed in the tag in render? I tried passing down the state as
Total Number of Checkbox Selected:{this.state.count} but that just returns 0.
If I console.log(count) inside the handleCheckCount function it display the number of the checked boxes in the console but outside it returns 0.
state={
checked: false,
count: 0
}
handleCheckCount=()=> {
let input = document.getElementsByTagName('input');
let count= this.state.count
for (var i = 0; i < input.length; i++) {
if (input[i].type === "checkbox" && input[i].checked === true) {
count++
}
}
console.log(count)
}
render(){
return(
<div>
<table>
<thead>
<tr>
<th className="select_all">
<input type="checkbox" name="check" id="parent"
onClick={this.onSelectAll.bind(this)} onChange={this.handleCheckCount}/>
</th>
<th>Score</th>
<th>FirstName</th>
<th>LastName</th>
</tr>
</thead>
</table>
<h2>Total Number of Checkbox Selected: </h2>
</div>
)
}
Here's a working example:
class App extends React.Component {
state={
checked: false,
count: 0
}
handleCheckCount=(e)=> {
// let input = document.getElementsByTagName('input');
const { checked, type } = e.target;
// let count= this.state.count
// for (var i = 0; i < input.length; i++) {
if (type === "checkbox" && checked === true) {
this.setState(state => state.count++, this.logCount)
} else {
this.setState(state => state.count--, this.logCount)
}
// }
}
logCount() {
console.log(this.state.count);
}
render(){
return(
<div>
<table>
<thead>
<tr>
<th className="select_all">
<input type="checkbox" name="check" id="parent" onChange={e => this.handleCheckCount(e)}/>
</th>
<th>Score</th>
<th>FirstName</th>
<th>LastName</th>
</tr>
</thead>
</table>
<h2>Total Number of Checkbox Selected: {this.state.count}</h2>
</div>
)
}
}
Your problem was that you didn't update your state, just the scoped variable count inside the function (the same one you also logged).
I also added an else block to decrease the count, and removed the onClick listener.
Update: There's no need to use getElementsbyTagName and the for loop. You can use the event to get the target and its properties.
See on Codepen
Hope this helps.
I have a column input field in <td> which is in the loop due to this each Row has input field I got a javascript from which it storing local storage for input field but the issue is this javascript is working only for one input For Example :
I have five rows and due to loop input field generated for 5 rows automatically
What I am looking for is to store different values for each row..due to this script its not implementing for each row individually
Code
<input type="text" id="txt_1" onkeyup='saveValue(this);'/>
Javascript
<script type="text/javascript">
document.getElementById("txt_1").value = getSavedValue("txt_1"); // set the value to this input
document.getElementById("txt_2").value = getSavedValue("txt_2"); // set the value to this input
/* Here you can add more inputs to set value. if it's saved */
//Save the value function - save it to localStorage as (ID, VALUE)
function saveValue(e){
var id = e.id; // get the sender's id to save it .
var val = e.value; // get the value.
localStorage.setItem(id, val);// Every time user writing something, the localStorage's value will override .
}
//get the saved value function - return the value of "v" from localStorage.
function getSavedValue (v){
if (!localStorage.getItem(v)) {
return "";// You can change this to your defualt value.
}
return localStorage.getItem(v);
}
</script>
Image Showing
COde
<table class="table table-hover table-striped table-bordered" id="input-group">
<thead ><tr >
<th class="text-right"><?php echo "Contact No."; ?></th>
<th><?php echo "Followup 1 Date"; ?>
</th></tr></thead>
<tbody>
<?php
if (empty($enquiry_list)) {
?>
<?php
} else {
foreach ($enquiry_list as $key => $value) {
$current_date = date("d/m/Y");
$next_date = $value["next_date"];
if (empty($next_date)) { $next_date = $value["follow_up_date"];
}if ($next_date < $current_date) {
$class = "class='danger'";} else {
$class = ""; } ?>
<td class="mailbox-name"><?php echo $value['contact']; ?> </td>
<td class="mailbox-name" >
<div style="width:200px" style="height:200px" >
<input id="txt_<?= $row[id] ?>" onkeyup='saveValue(this);'
autocomplete="off" type="text" class="form-control" /></div></td>
</tr> </tr>
<?php }}?> </tbody> </table>
var inputGroup = document.getElementById('input-group');
var inputs = inputGroup.getElementsByTagName('input');
for(i=0;i<inputs.length;i++)
{
var id = inputs[i].getAttribute('id');
inputs[i].value = getSavedValue(id);
}
//Save the value function - save it to localStorage as (ID, VALUE)
function saveValue(e){
var id = e.id; // get the sender's id to save it .
var val = e.value; // get the value.
localStorage.setItem(id, val);// Every time user writing something, the localStorage's value will override .
}
//get the saved value function - return the value of "v" from localStorage.
function getSavedValue (v){
if (!localStorage.getItem(v)) {
return "";// You can change this to your defualt value.
}
return localStorage.getItem(v);
}
<table id="input-group">
<tr>
<th>Text 1</th>
<th><input type="text" id="txt_1" onkeyup='saveValue(this);'/> </th>
</tr>
<tr>
<th>Text 2</th>
<th><input type="text" id="txt_2" onkeyup='saveValue(this);'/> </th>
</tr>
<tr>
<th>Text 3</th>
<th><input type="text" id="txt_3" onkeyup='saveValue(this);'/> </th>
</tr>
<tr>
<th>Text 4</th>
<th><input type="text" id="txt_4" onkeyup='saveValue(this);'/> </th>
</tr>
<tr>
<th>Text 5</th>
<th><input type="text" id="txt_5" onkeyup='saveValue(this);'/> </th>
</tr>
</table>
First of all you need to pass the event listener to the function that you have implemented, so i've solved it adding the events on the js file.
So instead of this:
<input type="text" id="txt_1" onkeyup='saveValue(this);'/>
You need to add the event on the js:
<input type="text" id="txt_1"/>
<input type="text" id="txt_2"/>
document.getElementById("txt_1").onkeyup = saveValue;
document.getElementById("txt_2").onkeyup = saveValue;
After this you need to access the id and the value from the event.target like this:
function saveValue(e) {
var id = e.target.id; // get the sender's id to save it .
var val = e.target.value; // get the value.
localStorage.setItem(id, val); // Every time user writing something, the localStorage's value will override .
}
Look at this codesandbox and see if it helps you out
Html is not reliable. You can use pure javascript code for cleaner way. Here is the working sample. Slackblitz https://stackblitz.com/edit/js-xycijp
function saveValue({ target }, index) {
localStorage.setItem(target.id, target.value); // Every time user writing
// OR
localStorage.setItem("target.id"+index, target.value); // Every time user writing something, the localStorage's value will override .
}
//get the saved value function - return the value of "v" from localStorage.
function getSavedValue(v) {
if (!localStorage.getItem(v)) {
return ""; // You can change this to your defualt value.
}
return localStorage.getItem(v);
}
document.querySelectorAll(".textField").forEach((elm, index) => {
elm.addEventListener("input", (e) => saveValue(e, index), false);
});
// Can ignore
window.saveValue = saveValue;
window.getSavedValue = getSavedValue;
<input class='textField' type="text" id="txt_1" />
<input class='textField' type="text" id="txt_2" />
I have a small problem. This is my HTML code fragment:
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Quantity</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr th:each="boiler : ${boilers}">
<td th:text="${boiler.value[0].model}"></td>
<td th:text="${boiler.value[0].brand}">
<td th:text="${#lists.size(boiler.value)}"></td>
<td th:text="${boiler.value[0].price}"></td>
<td>
<form>
<input type="text" th:class="boiler_model" th:id="boiler_model"
th:value="${boiler.value[0].model}" style="width:75px;"/>
<input class="form-control" type="number" id="quantity" style="width: 80px"/>
</form>
<td>
<button type="submit" class="btn btn-primary btn_submit" th:text="Add">Add</button>
</td>
</tr>
</tbody>
</table>
this is my jQuery:
$(document).ready(function () {
$('.btn_submit').on("click", function (e) {
e.preventDefault();
var quantity = $("#quantity").val();
// var boilerModel = $(".boiler_model").val();
var boilerModel = document.getElementById('boiler_model').value;
if (quantity === 0) {
alert("You must fill the quantity");
}
else if ($.trim(boilerModel) === "") {
alert("You must choose the model");
}
else {
var productIds = [];
$.ajax({
type: "POST",
url: "/order",
data: {quantity: quantity, model: boilerModel},
success: function (data) {
window.reload();
}
});
}
});
My problem is when I click the button it does read the quantity, but only reads the first model, even though it is printed in input correctly. I even removed the "hidden" type so I could see it for myself.
As you can see - the input is printed correctly, but when I debug this the controller always receives a quantity that is null if clicked on 2nd or 3rd model, but correct for the first one and model that is always the same. It always is "Super Hot Premium".
Could you please help me modify the table so it reads input separately from each row and then sends it to my controller?
Thank you very much.
There are several issues with your code :
you are looping through your boilers collection and generating a row for each loop. Each row contains two input fields with the same ids : quantity and boiler_model
in your click event handler, you are not looping through each row to submit data.
To fix this :
Follow this example to keep track of your loop status
Use the row index to generate unique ids for both your input fields
Store the size of your boilers collection in some hidden field to be able to send data from all rows
In your event handler, retrieve the size of your boilers collection and retrieve/send data for each row.
Here is a suggestion for your template (please note that I haven't tested it) :
<tr th:each="boiler, iterStatus : ${boilers}">
<td th:text="${boiler.value[0].model}"></td>
<td th:text="${boiler.value[0].brand}">
<td th:text="${#lists.size(boiler.value)}"></td>
<td th:text="${boiler.value[0].price}"></td>
<td>
<form>
<input type="text" th:class="boiler_model" id="boiler_model_${iterStatus.index}"
th:value="${boiler.value[0].model}" style="width:75px;"/>
<input class="form-control" type="number" id="quantity_${iterStatus.index}" style="width: 80px"/>
</form>
<td>
<button type="submit" class="btn btn-primary btn_submit" th:text="Add">Add</button>
</td>
</tr>
<input type="hidden" id="boilersLength" th:value="${#lists.size(boilers)}"/>
And your event handler :
$(document).ready(function () {
$('.btn_submit').on("click", function (e) {
var quantity, boilerModel, boilersLength, i;
e.preventDefault();
// retrieving the length of the boilers collection
boilersLength = $("#boilersLength").val();
// looping and sending data for each row :
for (i=0;i<boilersLength;i++) {
// retrieving data from both inputs :
quantity = $("#quantity_" + i).val();
boilerModel = $("#boiler_model_" + i).val();
if (quantity === 0) {
alert("You must fill the quantity");
}
else if ($.trim(boilerModel) === "") {
alert("You must choose the model");
}
else {
var productIds = [];
$.ajax({
type: "POST",
url: "/order",
data: {quantity: quantity, model: boilerModel},
success: function (data) {
// I wouldn't reload the window here, or you may reload before all data is sent
// window.reload();
}
});
}
}
});
}
You need to send a unique-id to identify on which Row the button is clicked so that you could get those values on your controller on the basis of that 'unique-id'
For Example :--
<tr th:each="boiler : ${boilers}">
<td th:text="${boiler.uniqueID}"></td>
<td th:text="${boiler.value[0].model}"></td>
<td th:text="${boiler.value[0].brand}">
<td th:text="${#lists.size(boiler.value)}"></td>
<td th:text="${boiler.value[0].price}"></td>
//Rest of your Code
<td>
<button type="submit" th:onclick="'javascript:addFunction(\'' + ${boiler.uniqueID} +'\');'" >Add</button>
</td>
</tr>
I am newbie to Angular js.'this' operator will be helpful, but no idea how to use it.
On Each First Column, user will input the data, and corresponding that data should be fetched. Now data is fetched from php to Angular js, but how to push the data from angular js to that text box using "this" operator.
For eg: If 'Y' is entered then, X and Z should be push to textbox
If 'Q' is entered then, P and R should be push to textbox.
HTML:
<tr>
<td><input type="text" ng-model="bot.Wo_Id" /></td>
<td><input type="text" ng-click="acc1()" ng-value="b_code" /</td>
<td><input type="text" ng-value="Pre_req" /></td>
<td><a href ng-click="remove_bottle(bottle)">Remove</a></td>
</tr>
<tr>
<td><a href ng-click="add_bottle()">Add</a></td>
</tr>
Angular Js:
$scope.acc1 = function () {
$http.get("machin.php", {
params: {
"W_id": this.bot.Wo_Id,
"MC": "Machine"
}
})
.success(function (response) {
var values = response.split("#");
$scope.b_code = ?
$scope.Pre_req = ? // what should be code here
});
};
machin.php
echo X."#".Z //for input Y
echo P."#".R //for input Q
I am unable to sort this problem.Please help me.Thanks in advance.
This should do the trick:
Don't use this, use $scope.
Change ng-value to ng-model
HTML
<tr>
<td><input type="text" ng-model="bot.Wo_Id" /></td>
<td><input type="text" ng-click="acc1()" ng-model="b_code" /</td>
<td><input type="text" ng-model="Pre_req" /></td>
<td><a href ng-click="remove_bottle(bottle)">Remove</a></td>
</tr>
<tr>
<td><a href ng-click="add_bottle()">Add</a></td>
</tr>
Angular:
$scope.acc1 = function () {
$http.get("machin.php", {
params: {
"W_id": $scope.bot.Wo_Id,
"MC": "Machine"
}
})
.success(function (response) {
var values = response.split("#");
$scope.b_code = values[0];
$scope.Pre_req = values[1];
});
};
Here's a plunker with example. I can't do the http request so I just resolve the promise.
https://plnkr.co/edit/f6EzxBlaFInJghNwsXaU?p=preview