angularjs object changes affects other object - angularjs

I have AngularJS application. From server I am getting a JSON. I am assigning to two objects. One I am using in my form page to edit. When the user press submit, I want to check whether the new value and old are same. But whenever I update the value in form and checks, the other object value also gets updated., resulting both object becomes same always.
Here is the JSFiddle Demo. Whenever I am trying to change the value, the other value also gets updated.
What is the solution to prevent the other object to not change?
HTML
<div ng-app>
<h2>Form</h2>
<div ng-controller="MainCtrl">
<form name="myForm" ng-submit="saveForm()">
<input type="text" ng-model="obj.name">
<input type="text" ng-model="obj.value">
<input class="btn-primary" type="submit" value="Save" ng-disabled="myForm.$pristine">
</form>
</div>
</div>
JS
function MainCtrl($scope) {
$scope.obj={
name:"N1",
value:"val"};
var oldObj = $scope.obj;
$scope.saveForm=function() {
alert(JSON.stringify($scope.obj));
alert(JSON.stringify(oldObj));
if($scope.obj===oldObj){
alert("same");
} else {
alert("not same");
}
}
}

The problem is, that you just store an reference to oldObj.
So oldObj and the $scope.obj is always the same.
You need to copy it.
Check the fiddle: http://jsfiddle.net/fc0jo1so/1/
I did it with fromJson, toJson

You just change this line
var oldObj = angular.copy($scope.obj);
Try it will work. & give alert not same

Try using jQuery to make a deep copy
var oldObj = jQuery.extend(true, {}, $scope.obj);

Related

Angularjs difference between fetched and locally modified data

I fetch data from an API and it gives my something like this:
{id: 1, name: ''}
The field name is ng-model for an input field.
As soon as I write something in the field, the json object I have a reference to, will have name equals to something else than empty.
That's normal behaviour.
However, if Im interested in knowing if name "was" empty when I fetched data, can I do this in a simple way? Without needing to create new variables?
Basically I want to have 2 ng-if elements and only display one of them. But I cannot trust the data in the object because I don't know if the name-field has been changed locally or on the server:
<input type="text" ng-model="ctrl.name" ng-if="ctrl.name === ''" />
<span ng-if="ctrl.name !== ''">{{ctrl.name}}</span>
Use can the $dirty (this docs are about form but it's true for inputs as well) prop of an input in form so the logic will be: show the input if the name is not defined (undefined or an empty string) or when the input is dirty - means the user typed in the input. And the opposite for the span. This way you'll not have to hold another param.
angular.module('app', []).controller('myController', function() {
// comment this line to simulate name was empty
// this.name = 'text from server';
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="myController as ctrl">
<form name="myForm">
<input type="text" name="name" ng-model="ctrl.name"
ng-if="!ctrl.name || myForm.name.$dirty" />
<span ng-if="!!ctrl.name && !myForm.name.$dirty">{{ctrl.name}}</span>
</form>
</div>
</div>

Angularjs: How to get value of input without ng-model

I need to make some inputs by ng-repeat, and in my json file I have in object where is a property called name, like this:
"url":"find_company",
"values":[
{
"name":"company name",
"type":"input_search"
},{
"name":"company_phone",
"type":"input_search"
}
]
I want to make search in DB, in search you can find by any field or by two or more field. Field called the same as property of object. So by ng-keyup I need to send to my function
search(field, value)
two arguments. I want to do something like this
<div ng-repeat="value in param.values">
<input ng-if="value.type == 'input_search'"
ng-keyup="search(value.name, this.text)"
type="text">
How can a send to function text of this input without using ng-model? Where this.text is value of input.
since you are using ng-keyup, you can retrieve input value with $event.target.value.
comment: this is fit for normal event like onclick, but not fit for angular.
refer the below example.
angular.module("app", [])
.controller("myCtrl", function($scope) {
$scope.showValue = function(val) {
alert(val);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<div ng-app="app" ng-controller="myCtrl">
<input type="test" ng-keyup="showValue($event.target.value)">
</div>
This is how you do it with ngModel:
<div ng-repeat="value in param.values">
<input ng-if="value.type == 'input_search'" ng-model="value.val" ng-keyup="search(value)" type="text">
And in your controller:
$scope.search = function( item ) {
console.log( item.val ); // Here you have the value using ngModel
console.log( item.name ); // Here you have the "name" property of the element inside the loop
}
As you can see, you CAN use ngModel and by passing the object itself to the function you can access its properties from the function in the controller.
Note that there's that this.text in the view - I don't know what it is exactly so I dropped it from the example to make things clearer, but you can use it in your code of course.
I know the question said without using ng-model. But I suspect you may want this because you want to customize when data-binding occurs. If that's the case, you can use ng-model-options with ng-change:
<input type="text" ng-model="yourModel" ng-model-options="{ updateOn: 'keyup' }" ng-change="search()" />
ng-change fires when the model has been updated, which is after keyup in this case. So the value of yourModel will be up to date when search() executes.

AngularJS - unchanged data passed by ng-model is interpreted as undefined instead of the value

I'm using Angular to generate some inputs and populate them with data using ng-repeat. I also want to bind the data inside the input to a save changes button which takes parameters provided by ng-model directives. save changes button prints the passed arguments using the built-in JS arguments object. For some reason, unless I change the text inside the input box, the output is [undefined, undefined]. Once I change the text inside the input boxes, the correct output is printed. Why is that?
JSfiddle code.
HTML:
<div ng-app="myApp" ng-controller="MainCtrl">
<p ng-repeat = "man in men">
<label>name</label><input type="text" ng-model="mname" ng-value="man.name"><br>
<label>status</label><input type="text" ng-model="mstatus" ng-value="man.status"><br>
<button ng-click="save(mname,mstatus)">
save changes
</button>
</p>
</div>
JS:
var app = angular.module('myApp', []);
app.controller('MainCtrl', function($scope) {
$scope.men = [{
name: "jon snow",
status: "depands"
}, {
name: "rob stark",
status: "dead"
}];
$scope.save = function() {
console.log(arguments);
}
});
This is not recommended but for your specific requirement you can use ng-init to bind ng-value to your model
<p ng-repeat = "man in men">
<label>name</label><input type="text" ng-model="mname" ng-value="man.name" ng-init="mname = man.name"><br>
<label>status</label><input type="text" ng-model="mstatus" ng-value="man.status" ng-init="mstatus = man.status"><br>
<button ng-click="save(mname,mstatus)">
save changes
</button>
</p>
This wouldn't bind your changes to the original model.
Fiddle
ngModel doesn't update untill you use a key to change it, or set it from your controller. Because you are setting the field of the input using ngValue, it doesn't register to your ngModel untill you change it.
This problem is similar to how most datepickers don't work with ngModel, as they set the field with DOM-manipulation and NOT by inserting the value by "key".
You can easily fix this by using the following HTML instead:
<label>name</label><input type="text" ng-model="man.name"><br>
<label>status</label><input type="text" ng-model="man.status"><br>
I simply removed the ngValue and linked the ngModel to your "man".

ng-change triggered before value is updated

I have a form which needs to save data each time something is changed. I've used ng-change on all form elements to trigger a form validation and a save. However in case of radio buttons, ng-change is triggered before the actual value is updated, thus resulting in an invalid form on the first try, and an outdated form all subsequent times.
I've set up a JSFiddle to illustrate this. The console prints out whether the form is valid or not. The same applies if I were to print the value of $scope.form.test.$modelValue.
// HTML
<div ng-controller="MyCtrl">
<form name="form">
<input type="radio" name="test" ng-model="test" value="yes" required ng-change="checkRadios()" /> Yes<br/>
<input type="radio" name="test" ng-model="test" value="no" required ng-change="checkRadios()"/> No
</form>
</div>
// JS
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.test = null;
$scope.checkRadios = function(){
console.log($scope.form.test.$modelValue);
}
}
Is my logic faulty, is this a valid bug, or does it work as expected? In the last case, what can I do to always get the actual value?
You need a delay to get the updated value of the $scope.form, so it is possible to achieve by using $timeout
http://jsfiddle.net/loen22/w7dpx57f/
$scope.checkRadios = function(){
$timeout(function () {
console.log($scope.form.$valid);
});
}

injecting error manually to form

Is there any way to inject error manually to form, I know the way via directive but not sure how can inject error from the controller.
<div ng-controller="myController">
<form name="createForm">
<div ng-repeat="item in someItems">
<input type="text" ng-change="customValidation()" />
</div>
<input type="button" ng-disabled="createForm.$invalid" value="Submit" />
</form>
</div>
controller
function myController($scope) {
$scope.customValidation = function() {
//do some validation and made createForm valid/invalid based on it
};
}
Yes, You can do it in two ways.
instead of Creaeform.$invalid. You can use some value inside your scope.
You should set the value true or false depending on the validation result of the input. If this doesn't make sense to you, give a comment. I'll give some code.
another way is passing the form object itself to the controller and set the createForm.$valid = false; in the controller.

Resources