Changing state doesn't remove input values in React - reactjs

I have a table with different rows (react components). This rows are named service_users. When i click the save button of a row, a registerServiceUser method is called which updates the state in the parent component with a splice function. But after the state changes the input values from the saved row are passed to the next component (see screenshots).
The saved row is here the one with the name Milan den Vliet, after the save (which involves a state change) the value 23:00 and 1,00 are passed to the row of Finn de Dekker.
How can i prevent this behavior?
Service user child component code:
return (
<tr>
<td style={tdStyle}>{driverIcon}</td>
<td style={tdStyle}>{this.props.name}</td>
<td style={tdStyle}>{moment(this.props.startTime).zone('00:00').format('HH:mm')}</td>
<td><input type="text" onChange={this.handleEndTimeChange} className="form-control" /></td>
<td><input type="number" onChange={this.handlePauseChange} className="form-control" defaultValue={this.state.pause_time} /></td>
<td><input type="number" step="any" onChange={this.handleWorkHoursChange} className="form-control" value={this.state.work_hours} /></td>
<td><input type="number" step="any" onChange={this.handleExtraHoursChange} className="form-control" placeholder="Extra uren" style={extraHoursBackground} /></td>
<td style={tdStyle}>{driverField}</td>
<td style={tdStyle}>Opslaan</td>
</tr>
);
After save i update the state with this:
this.setState({ service_users: update(this.state.service_users, {$splice: [[index, 1]]}) });

I assume that you have a for-loop somewhere to generate the user rows. If this is the case, each row must have a unique key, preferably user ID or something similar. In that case
return (
<tr>...</tr>
)
must be changed to
return (
<tr key={this.props.id}>...</tr>
)
Unless you tell React to use a key, it just assumes that the top row is always the same, and just changes the values that have changed.
Update: Take a look at this fiddle. It doesn't do the same thing as your app, but the concepts of changing state and removing the proper elements should apply nevertheless: https://jsfiddle.net/jy0cgemz/

Related

Values are duplicated into all input field which is created using the ng-repeat and ng-model

I am using the ng-repeat to create the input fields dynamically, everything seems to be working fine and the input fields are created but due to some reason when I enter some value into that created input field then due to two-way data binding the value is entered simultaneously in all the text fields that were created.
As per my knowledge, I am assigning the different ng-model to each of the created fields so I am not sure why the values are being copied. When I try to print the values which are assigned to the input field just above the field then I see the id is different wanted to know why all the fields are taking the same value and also how can I prevent it.
HTML Code:
<tr>
<td ng-repeat="extension in ExtensionList">
<!-- Here the value displayed are different -->
{{ formdata.extension.ExtensionVlaues }}
<input type="text" class="form-control" id="extension.ExtensionVlaues" ng-model="formdata.extension.ExtensionVlaues">
</td>
</tr>
Here is the screenshot from the front-end:
Here is the example of my ExtensionList: {"Field1":"","Field2":"","Field3":1,"ExtensionVlaues":2}
As per my knowledge, the given ng-model is different but still not working. Can anyone please help me with this? I tried few things like ng-model="formdata.extension[ExtensionVlaues]" but still no luck.
I tried to assign ng-model like this but it is not working:
ng-model="formdata.extension[ExtensionVlaues]"
Based on the below answer I tried 2 different things it but it's not working and getting the same issue. Please let me know how can I resolve this:
<td ng-repeat="(key, extension) in ExtensionList">
<input type="text" ng-model="formdata.extension.key">
</td>
<td ng-repeat="(key, extension) in ExtensionList">
<input type="text" ng-model="formdata.extension.ExtensionVlaues">
</td>
You are trying to use ExtensionList as an array. You need to use it as an object with ng-repeat:
<td ng-repeat="(key, extension) in ExtensionList">
<input type="text" ng-model="formdata[extension][key]">
</td>
<td ng-repeat="(key, extension) in ExtensionList">
<input type="text" ng-model="formdata[extension][ExtensionVlaues]">
</td>
Just incase anyone else also struck at this issue:
<span ng-repeat="(key, extension) in ExtensionList" class="form-inline">
<br/>
<span>
{{ extension.NameSpace + ":" + extension.LocalName }}
</span> 
<input type="text" class="form-control" id="extension.ExtensionVlaues" ng-model="ExtensionList.extension[key].FreeText" ng-blur="ExtensionText(ExtensionList.extension[key].FreeText, extension.ExtensionVlaues)">
</span>

Modify an array object that construts a table and then post that object

I am trying to post an array object that constructs a table. I want to from the table to modify(add new data) the data and post it.
Code:
<tr ng-repeat="cus in postObj.custs">
<td>{{$index + 1}}</td>
<td><input type="checkbox" ng-model="postObj.custs[$index].principal"/></td>
<td>{{cus.Name}}</td>
<td>{{cus.Phone}}</td>
<td>{{cus.AddPre}}</td>
<td><input type="text" class="form-control" ng-model="postObj.custs[$index].relation"/></td>
<td>
<button ng-click="deleteCus(cus)">Delete</button>
</td>
In the above code the tags inside the is the field for new values.
But when I console.log() the object the new objects are never there. So what can be done with this?

How to apply different validation to different ng-repeat field and calculate its total automatically in ng repeat itself

Example Code:
<table>
<tr>
<td>Class</td>
<td> Input one </td>
<td> Input two </td>
<td> Total </td>
</tr>
<tr ng-repeat= "x in records">
<td>My {{x.class}} </td>
<td><input type="tel" ng-value="x.tel" ng-model="telephone"></td>
<td><input type="tel" ng-value="x.inone" ng-model="inone"></td>
<td><input type="tel" ng-value="x.intwo" ng-model="intwo"></td>
<td><input type="tel" ng-value="x.total" ng-model="total"></td>
</tr>
<tr>
<td colspan="5" class="text-center"> <input type="button" value="Save" ng-click="mydata(records)"> </td>
</tr>
</table>
Initially ng repeat records contains only details part bydefault.
$scope.records = [
{
"class" : "Personal",
},
{
"class" : "Socail",
},
]
After submit, angular dynamically add those field which filled by user
Intially User will see only
1.Class part with 3 blank input field for inone, intwo and total and one blank telephone field.
What I want
1.There should be validation to telephone field of
A. Personal class which allow only 6 digits, and
B. for Social class it should allow 10 digits.
The range for entering value in Personal's inone field is 0-10 and intwo field is 11-30.
The range for entering value in Social's inone field is 30-40 and intwo field is 40-60.
4.Total field should calculate total of whatever entered in inone and intwo model of there respective class .Note that total field is generated from ng repeat so we cannot directly make total.
What about something along the line ...
<td ng-if="x.class=='Personnal'"><input type="tel" ng-maxlength="5" ng-model="x.inone" ng-change="x.total=x.inone+x.intwo"></td>
<td ng-if="x.class=='Social'"><input type="tel" ng-maxlength="5" ng-model="x.inone"></td>
<td ng-if="x.class=='Personnal'"><input type="tel" ng-minlength="11" ng-maxlength="15" ng-model="x.intwo" ng-change="x.total=x.inone+x.intwo"></td>
<td ng-if="x.class=='Social'"><input type="tel" ng-minlength="16" ng-maxlength="20" ng-model="intwo"></td>
Tu sum it up :
ng-value is useless, bind your data directly to x.[value]
use ng-if to switch between the different classes
use ng-minlength/ng-maxlength for the validation
use ng-change to recompute total everytime, you may want to add a readonly/disabled flag in the total field. If total is not a string concatenation, use a function that will be called in your controller for the proper conversion and sum it up.

How to see both masked and unmasked values with AngularUI ui-mask and ng-repeat?

I'm using AngularUI's ui-mask directive to mask phone numbers. We'd like to save both the masked and unmasked value to the database.
I see the docs have the option to use the model-view-value="true" to store the $viewValue as the model giving us the masked value.
However since we'd like both I'd prefer a way to leave this false and access the $viewValue on my own. I see in the demo however this is for a single input. It looks like it is bound to the name of the inputs.
My issue is this is a ng-repeat and so the names vary. I got it working for a single item (you can see in the first table it works).
The last <td> is where I'm trying to show the $viewValue. I'm also trying to pass it in to the setPhoneValue function but it is undefined there also.
Edit: Created a fiddle: https://jsfiddle.net/n35u7ncz/
<form name="phone_form" id="crm_phonegrid" ng-app="crm_phonegrid" ng-controller="phoneCtrl">
<table cellpadding="2">
<tr>
<td><input type="text" name="new_phone" placeholder="Number" ng-model="addNumber.phoneNumber" onfocus="onFocusUpdateMask()" ui-mask="{{mask}}" ui-mask-placeholder ui-mask-placeholder-char="_" /></td>
<td><select name="phoneTypeSelect" ng-model="addNumber.phoneType" ng-options="option.name for option in phoneTypeOptions track by option.Value"></select></td>
<td><input type="button" ng-click="addNumber()" value="Add" /></td>
<td>{{phone_form.new_phone.$viewValue}}</td>
<td>{{addNumber.phoneNumber}}</td>
</tr>
</table>
<table cellpadding="2">
<thead>
<tr>
<th>Phone Link</th><th>Phone Number</th><th>Phone Type</th><th>Primary Flag</th><th>Mask</th><th>View</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="number in numbers">
<td><a style="color:#1160B7;text-underline-position:below" href="" ng-click="openPhoneRecord(number)">{{ number.crm_phonenumber }}</a></td>
<td><input type="text" id="crm_phonegrid_number" name="phone_number_input" model-view-value="true" ng-model="number.crm_phonenumber" ng-change="setPhoneValue(number)" ui-mask="{{number.crm_crm_country_crm_phonenumber.crm_PhoneMask}}" ui-mask-placeholder ui-mask-placeholder-char="_" /></td>
<td><select name="phoneTypeSelect" ng-model="number.crm_phonetypecode" ng-change="setValue(number)" ng-options="option.name for option in phoneTypeOptions track by option.Value"></select></td>
<td><input type="radio" name="primary" id="primaryRadio" ng-checked="number.crm_isprimary" ng-model="number.crm_isprimary" ng-change="setValue(number)" ng-value="number.crm_isprimary" ng-click="setFlag(number)" /></td>
<td>{{number.crm_crm_country_crm_phonenumber.crm_PhoneMask}}</td>
<td>View: {{phone_form.phone_number_input.$viewValue}}</td>
</tr>
</tbody>
</table>
</form>
We got this working. The trick was to use the $index to generate a unique Id for the element and then pass that to the controller.
I've updated the fiddle here: https://jsfiddle.net/n35u7ncz/3/
The general idea is that the input field needs to be tagged and have an ng-change:
<input type="text" id="phone_input_id" name="phone_input_name_{{$index}}" ng-model="number.crm_phonenumber" ng-change="setValue(number, $index)" ui-mask="{{number.crm_crm_country_crm_phonenumber.crm_PhoneMask}}" ui-mask-placeholder ui-mask-placeholder-char="_" />
And then:
$scope.setValue = function(item, index)
{
item.crm_phonenumbermasked = $scope.phone_form["phone_input_name_" + index].$viewValue;
}

save data from a table when a select or checkbox is selected in angular js

im trying to save the data from a table when a checkbox or selectbox is selected.
Table when loaded
code Product Checkbox SelectBox
0 45 checkbox selectoption
11 78 check box selectoption
html code:
<tr id="TableBody" ng-repeat="code in Codes.CodesDetails">
<td><input type="checkbox" ng-model="code.Presentstatus" id="Checkbox" name="Checkbox" /></td>
<td><select id="reasons" name="reasons" ng-model="code.Category" ng-disabled="code.Presentstatus" ng-clicked="code.Presentstatus && O" ></td>
</tr> <input type="button" value="save" ng-click="module.RegisterDetails"/>
the checkbox is checked it must show me a value of one and ignore the selectbox and vice versa.
but this is the output I get
Code= 0,Product=45,CheckBox="",selectbox=""
sorry about the table structure
on the ng-click you just add the following`
<td><input type="checkbox" ng-model="code.Presentstatus" id="PresentCheckbox" name="PresentCheckbox" ng-click="code.Category=0"/></td>
<td><select id="reasons" name="reasons" ng-model="code.Category" ng-disabled="code.Presentstatus" ng-click="code.PresentStatus=false" ></td>
`

Resources