angular ng-model updates parent object after submission and stay bounded - angularjs

I have a form and a display fields above it. I want to update display values only after submission. This works fine for the first submit. Until I submit it, values don't change, and once I click collect it updates values, and then, it seems that ng-model somehow binds and stay bounded to upper object, since when I continue to type on input fields values above update automatically. For me this is a strange behaviour, I want them to update only after I submit them. Any ideas?
and here is the code:
function Ctrl($scope) {
$scope.customFields = ["Age", "Weight", "Ethnicity"];
$scope.person = {
customfields: {
"Age": 0,
"Weight": 0,
"Ethnicity": 0
}
};
$scope.submited = {
"person" : {
"customfields" : {
"Age" : 0,
"Weight" : 0,
"Ethnicity" : 0
}
}
};
$scope.collectData = function () {
$scope.submited.person.customfields = $scope.person.customfields;
console.log($scope.person.customfields);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app ng-controller="Ctrl">
<div ng-repeat="fields in submited.person.customfields">
{{fields}}
</div>
<div class="control-group" ng-repeat="field in customFields">
<label class="control-label">{{field}}</label>
<div class="controls">
<input type="text" ng-model="person.customfields[field]" />
</div>
</div>
<button ng-click="collectData()">Collect</button>
</div>

Change this line
$scope.submited.person.customfields = $scope.person.customfields;
to
$scope.submited.person.customfields = angular.copy($scope.person.customfields);

When you use:
$scope.submited.person.customfields = $scope.person.customfields;
the variables become clones of each other - it's a property in JS. Hence, when you bind using that object, the values stay bound. You're basically just creating another reference for an already existing object.
angular.copy copies only the structure and data of the object onto another. Hence, cloning takes place rather than creating a reference of the object.
Hence, change it to:
$scope.submited.person.customfields = angular.copy($scope.person.customfields);

Related

Remove empty option in the select using ng-model

I am new to angular js. In my code user changes the value of radio buttons. And depending on the value of the selected radio button, a piece of code is loaded from the ng-switch
HTML:
<body ng-app="">
<div ng-repeat="button in modes">
<label>
<input type="radio" ng-model="data.mode" value="{{button.value}}" ng-click="clearObjectIdModal()" name="e_modes">
{button.label}}
</label>
</div>
<div ng-switch on="data.mode">
<div ng-switch-when="client">
<label for="e_selected_object_item_id">Select Client name: </label>
<select id="e_selected_object_item_id" name="e_selected_object_item_id" ng-model="currentDataItem.object_id" required>
<option ng-repeat="item in customersListArr" value="{{ item.id }}">{{ item.Name }}</option>
</select>
</div>
<div ng-switch-when="agent">
// This part is similar to the previous one
</div>
</div>
</body>
Controller part:
$scope.data = {};
$scope.setFile = function () {
if ($scope.data.mode == 'client')
return 'client';
else if ($scope.data.mode == 'agent')
return 'agent';
$scope.modes = [{
value: 'client',
label: 'Client'
},{
value: 'agent',
label: 'Agent'
}];
$scope.currentDataItem = data; // data is preloaded from inputs in form
There is also a ng-click="clearObjectIdModal()" that clears the model when switching radio buttons:
$scope.clearObjectIdModal = function() {
$scope.currentDataItem = "";
}
The problem is that every time when the radio button is switched to the select value, which dynamically changes, the value of the first option in it becomes equal to undefined. Because in the array from where these options are built there is no such object_id (This is the id that is not there, so an empty field is drawn).
That is, there are all works. But the first option in the select(after switching to another radio button) is rendered as an empty string.
There are thoughts, how it can be fixed?
I'm not sure if I understand you problem correctly but I would suggest a few improvements.
change your setFile function to as follows
$scope.setFile = function (){return $scope.data.mode;}
I also do not see the closing brackets for your function in your code. Besides if your function will only return the data.mode then why need the function?
I would suggest initialize your data object properly like:
$scope.data = {mode:'client'};
Change your clearObjectIdModal function as:
$scope.clearObjectIdModal = function(mode)
{
$scope.currentDataItem = "";
$scope.data.mode=mode;
}
and in your HTML use it as ng-click="clearObjectIdModal(button.mode)"
So in function clearObjectIdModal() I wrote:
$scope.clearObjectIdModal = function() {
if ($scope.e_data["mode"] == 'client') {
if ($scope.customersListArr.length > 0) {
$scope.currentDataItem.object_id = $scope.customersListArr[0]['id'];
}
}
else if ($scope.e_data["mode"] == 'agent') {
if ($scope.agentsListArr.length > 0) {
$scope.currentDataItem.object_id = $scope.agentsListArr[0]['id'];
}
}
}
And after this when I change radio buttons the first option in current select(which every time is changed) will be not empty.
Also the problem with an additional empty option is possible to solve when you add a title as the first item in the list:
<option value="" disabled>Select</option>

AngularJs Assign Json value to multiple scope

Hi I have two form in one page one for reference of previous data and one is a actual form. So i have to assign same json(which actually are come from database) to two different form in a page. I have a problem when I change the option value in main form the reference form value also change. What I want is even the main form change value, reference form should retain old value. please check my code.
https://jsfiddle.net/sanuman/kts7je89/24/
thank you for your any help and suggestions.
var app = angular.module('myApp',[])
.controller('MyCtrl', function($scope, $http) {
$scope.muni=[
{
"id": 24001,
"VDC_Muni_Code": "24001",
"VDC_Muni_Name_Eng": "Anaikot",
"tbl_district_id": 24
},
{
"id": 24002,
"VDC_Muni_Code": "24002",
"VDC_Muni_Name_Eng": "Baldthali",
"tbl_district_id": 24
},
{
"id": 24003,
"VDC_Muni_Code": "24003",
"VDC_Muni_Name_Eng": "Balting",
"tbl_district_id": 24
},
{
"id": 24004,
"VDC_Muni_Code": "24004",
"VDC_Muni_Name_Eng": "Baluwapati",
"tbl_district_id": 24
}
];
$scope.service_data=[
{
"tbl_vdc_municipality_id": 24001
},
{
"tbl_vdc_municipality_id": 24004
},
{
"tbl_vdc_municipality_id": 24002
},
{
"tbl_vdc_municipality_id": 24003
}
];
$scope.municipalities_ref = $scope.muni;
$scope.municipalities = $scope.muni;
$scope.wspVdcMuniTbls = $scope.service_data;
$scope.wspVdcMuniTblsRef = $scope.service_data;
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyCtrl">
<h2>
Main Form
</h2>
<div ng-repeat="wspVdcMuniTblRef in wspVdcMuniTblsRef">
<select
ng-model="wspVdcMuniTblRef.tbl_vdc_municipality_id"
options="municipalities_ref"
ng-options="municipality_ref.id as municipality_ref.VDC_Muni_Name_Eng for municipality_ref in municipalities_ref">
</select>
</div>
<h2>
Reference Form
</h2>
<div ng-repeat="wspVdcMuniTbl in wspVdcMuniTbls">
<select
ng-model="wspVdcMuniTbl.tbl_vdc_municipality_id"
options="municipalities"
ng-options="municipality.id as municipality.VDC_Muni_Name_Eng for municipality in municipalities">
</select>
</div>
</div>
</div>
The example you've provided work as expected. The thing is that both $scope.municipalities and $scope.municipalities_ref points to the same object (same for $scope.wspVdcMuniTbls and $scope.wspVdcMuniTblsRef) when this assigment is made:
$scope.municipalities = $scope.muni;
$scope.municipalities_ref = $scope.muni;
$scope.wspVdcMuniTbls = $scope.service_data;
$scope.wspVdcMuniTblsRef = $scope.service_data;
You should create a copy of $scope.muni and $scope.service_data like this:
$scope.municipalities_ref = angular.copy($scope.muni);
$scope.wspVdcMuniTblsRef = angular.copy($scope.service_data);
The documentation of angular.copy(source, [destination]); can be find there.

How to bind a list of checkboxes in AngularJS

I have a list of checkboxes as following :
<div flex="50" ng-repeat="formationType in formationTypeList">
<md-checkbox class="md-warn md-align-top-left"
value="{{formationType.codeFormation}}"
name="formationSelection[]"
ng-checked="formationSelection.indexOf(formationType) > -1"
ng-click="toggleFormationTypeSelection(formationType)">
{{ formationType.nom }}
</md-checkbox>
</div>
This is the format of formationSelection after I send my form :
formationSelection = [
{
codeFormation: 1,
nom: "ENSA"
},
{
codeFormation: 2,
nom: "CPGE"
}
]
In another scenario I want when I open my form to check the checkboxes which are defined in an array as following :
$scope.formationSelection = res.candidatureProjetProfessionnel.formations;
the object res.candidatureProjetProfessionnel.formations contains this :
formationSelection = [
{
codeFormation: 1,
nom: "ENSA"
},
{
codeFormation: 2,
nom: "CPGE"
}
]
And when I inspect $scope.formationSelection it contains the data I got from res.candidatureProjetProfessionnel.formations :
But I don't know why my checkboxes are not checked even though the $scope.formationSelection is not empty.
How can I solve this ?
i'm not sure what the md-checkbox directive is so i'm just going to use a normal checkbox input. Generally speaking, setting a default value for inputs in angular involves 2 things:
Make sure your inputs have ng-model to store the value of the checkbox and for 2 way data binding (so that you can set it from the controller as well)
In your controller set the variable declared in the ng-model to whatever default value you want.
So in you html:
<input type="checkbox" class="md-warn md-align-top-left" ng-
model="formationSelection[$index]" ng-true-value="{{formationType}}"
name="formationSelection[]">
Make sure you use ng-true-value to declare the value of each checkbox when checked. The ng-model is set to formationSelection[$index] which basically means each checkbox is an item inside the formationSelection array, this way the array will be the collection of the values of all checked inputs.
Now $scope.formationSelection = res.candidatureProjetProfessionnel.formations should work
Here's a working plunker:
http://plnkr.co/edit/sGm39DRWH9EOReiiSrIl?p=preview
You have to use ng-model as shown below.It should be an object like $scope.data = {};.This is just an example where hope you can get the point and work on your scenario. Actually you're having individual check boxes as shown below but values are being set through the loop.So you can apply this concept for your use case as well.Hope this will help to you.
Html
<md-checkbox ng-model="data.cb1" aria-label="Checkbox 1">
Checkbox 1: {{ data.cb1 }}
</md-checkbox>
JS
$scope.data = {};
$scope.data.cb1 = true;
Play with it on Codepen
I think that your method isFormation(formationType) on the directive ng-checked it's not return the result.
In your controller create a function
$scope.isFormation(_type){
return $scope.formationSelection.filter(function(f){return f.nom === _type;}).length > 0;
}

Angular ng-if how do i reset the value of the model, in an angular way

<div ng-app>
<form ng-controller='chip'>
<select data-ng-options="n for n in simOptions" data-ng-model="simQuantity"></select>
<div ng-if="simQuantity>=1">
<select name="sim" ng-model="formData.sim[0]" ng-options="sim for sim in sims" ></select>
</div>
<div class="suscriptor_fields" ng-if="simQuantity>=2">
<select name="sim"
ng-model="formData.sim[1]"
ng-options="sim for sim in sims" ></select>
</div>
<div class="suscriptor_fields" ng-if="simQuantity>=3">
<select name="sim"
ng-model="formData.sim[2]"
ng-options="sim for sim in sims" ></select>
</div>
<div class="suscriptor_fields" ng-if="simQuantity>=4">
<select name="sim"
ng-model="formData.sim[3]"
ng-options="sim for sim in sims" ></select>
</div>
{{formData.sim}}
If in the first select i choose 2 to 4 and select a value in the second to fourth select options and then i reselect the first one with a lower value, the ng-if turns to false but the ng-model doesnt change i need to get it to null again, so if doesnt get sent when i submit the form. In a nutshell, if a user selects 2, will get two options, if he/she selects two options but then changes his/her mind and decides only wants 1, the field disappears but the value is still getting send when submit.
this is the fiddle
jsfiddle.net/U3pVM/13524/
and the javascript part
function chip($scope) {
$scope.formData = {
'sim' : {
'0' : null,
'1' : null,
'2' : null,
'3' : null
}
};
$scope.simQuantity = 1;
$scope.simOptions = [1,2,3,4];
$scope.sims = [
'Mini-SIM',
'Micro-SIM',
'Nano-SIM',
];
}
You can clean the data during ng-change to remove the extra properties.
I have cleaned up your jsfiddle that was not working and implemented a solution:
http://jsfiddle.net/k1m3cd60/
code:
$scope.clean = function(n) {
for (var i = 4; i >= +n; i--) {
delete $scope.formData.sim[i];
}
};
html:
ng-change="clean(simQuantity)"

Edit object inside array - AngularJS

http://jsfiddle.net/cnnMQ/2/
You can see here I have a pretty nice functioning Add/Remove/Edit functionality for removing objects from an array.
What I am struggling with is
Editing inline and pushing the changes back into the array.
Adding new input fields to the DOM in order to push new objects into the array.
http://jsfiddle.net/cnnMQ/2/
app = angular.module("sparta", []);
window.CompetitionController = function($scope) {
$scope.activities = [{
id: 6431,
name: "Meeting",
points: 20
}, {
id: 6432,
name: "Deal",
points: 100
}];
$scope.addNewActivity = function() {
//This function should create 2 new input fields
//The user should input the name and points
//We can ignore the id for now
//Then the object should be craeted and pushed in as you see below with the mock data.
var updatedActivities = {
id: 6433,
name: "Call",
points: 5
};
$scope.activities.push(updatedActivities);
}
$scope.editActivity = function(activity) {
var selectedActivity = activity;
console.log(selectedActivity);
}
$scope.removeActivity = function(activity) {
activityId = activity.id; //the activity id
var i = 0;
for (var item in $scope.activities) {
if ($scope.activities[item].id == activityId)
break;
i++;
}
$scope.activities.splice(i, 1);
}
}
The HTML is as follows:
<body ng-app="sparta">
<div class="container" ng-controller="CompetitionController">
<div ng-repeat="activity in activities">
{{activity.name}} - {{activity.points}}
<button ng-click="editActivity(activity)">Edit</button>
<button ng-click="removeActivity(activity)">Remove</button>
</div>
<div class="addNew">
<button ng-click="addNewActivity()">Add New</button>
</div>
</div>
</body>
I've tried to give as much as possible in the fiddle - what I would love is some guidance on the addNewActivity() function and the editActivity() function and how to inline edit the two input fields and save the changes back into the array.
Thanks in advance!
You can change your html from:
{{activity.name}} - {{activity.points}}
To:
<input type="text" ng-model="activity.name"/> - <input type="text" ng-model="activity.points"/>
So you get 2-way binding.
Working example: http://jsfiddle.net/CFx7m/
Here's another simple example: http://jsfiddle.net/A5xZ9/2/
Basically you hide input field until activity edit button is clicked, in which case you show input field and hide text:
<div ng-show="activity.isEdited">
<input type="text" ng-model="activity.name"/> - <input type="text" ng-model="activity.points"/>
<button ng-click="activity.isEdited = false">Ok</button>
</div>
<div ng-hide="activity.isEdited">
{{activity.name}} - {{activity.points}}
<button ng-click="activity.isEdited = true">Edit</button>
<button ng-click="removeActivity(activity)">Remove</button>
</div>
There's a lot of improvement possible, for example editing local copy of the activity and updating original attributes only when user presses Ok, and providing Cancel button as well.

Resources