Set variable when object changes in Angular - angularjs

I'm using Angular and attempting to show a button to a form only when the object changes that the form manipulates.
html:
<input ng-model="form.field1" />
<input ng-model="form.field2" />
<div ng-show="formChanged">Show button</div>
controller:
$scope.form = {
field1: 'hello'
}
$scope.$watch('form', function(){
$scope.formChanged = true;
});
I was under the impression that $watch would fire whenever any part of the object changed. It seems, however, that the $watch is called at the very beginning and only once after the object changes.
I have a plunker here: http://plnkr.co/edit/Hv8oLLviOzSLMUg2iBXt
Parenthetical information:
I have found that if I set $watch to explicitly look at each property that the $watch functions as I expect it to, though it still is run at the beginning.
To stop it from being called at the beginning I've tried to use the newValue and oldValue variables as follows:
$scope.$watch('form', function(newVal, oldVal){});
but that doesn't work either.

Use $dirty property from the FormController, or set the third parameter on $watch callback to true for object equality comparison.
Solution A:
<form ng-submit="submit()" name="myForm">
<div>
<input type="email" name="email" ng-model="formData.email" required />
<span ng-show="myForm.email.$dirty && myForm.email.$error.required">required</span>
</div>
<div>
<button ng-show="myForm.$dirty" type="submit">Submit</button>
</div>
</form>
Solution B:
$scope.$watch('form', function(){
$scope.formChanged = true;
}, true);

Related

Get pristine value in Angular controller

I need to be able to see in the Angular controller if the datepicker is pristine or not. Tried all sorts of things including sending the pristine value in a method but cannot get this value. Below is the view code:
<form name="myForm">
<!-- Datepicker From -->
<div class="small-6 medium-5 large-2 columns" ng-if="vm.subViewActive">
<div class="input-group">
<input name="valuationDatePickerFrom" ng-model="name" type="text" class="datepicker" id="valuationDatePickerFrom" placeholder="DD/MM/YYYY" pikaday="vm.datePickerFrom" on-select="vm.selectStartDate(pikaday)" year-range="{{ vm.yearRange }}" >
<div class="input-group-addon">
<label for="valuationDatePickerFrom" class="postfix">
<i class="fa fa-calendar"></i> From
</label>
</div>
</div>
</div>
</form>
and then I also tried :
var isPristine = $scope.myForm.valuationDatePickerFrom.$pristine;
console.log(isPristine);
in my controller but cannot get the pristine value. Read lots of posts here but mainly to do with CSS classes and front-end control or setting the pristine state from the backend not getting or checking the pristine state.
Thanks anybody that can help.
You are using:
var isPristine = $scope.myForm.valuationDatePickerFrom.$pristine;
but your form's name is not myForm.
Change <input name="name"... <input name="valuationDatePickerFrom"...
Then you can use:
var isPristine = $scope.userForm.valuationDatePickerFrom.$pristine;
Also, the controller is getting called before the view is created, so no myForm exists at the time the controller runs. Try adding a $timeout like so:
$timeout(function() {
var isPristine = $scope.userForm.valuationDatePickerFrom.$pristine;
console.log(isPristine);
}, 100);
plunkr
The above solution only works on page load, but you need to know this value when the page is being used. Instead pass the value to the controller when an action happens:
<form name="myForm">
<input type="text" name="valuationDatePickerFrom" ng-model="valuationDatePicker" ng-blur="alerty(myForm.$pristine)">
</form>
.controller('MainController', function($scope) {
$scope.alerty = function(isPristine){
alert('isPristine: ' + isPristine);
};
https://plnkr.co/edit/f0EWvYmoXCn8UOH3QCfE?p=preview

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.

ng-change not working on a text input

I am new to angular js. In my code there is color picker initialized from a text field. User changes the value of color and I want that color to be reflected as a background of a text in a span. It is not working. What is missing?
HTML:
<body ng-app="">
<input type="button" value="set color" ng-click="myStyle={color:'red'}">
<input type="button" value="clear" ng-click="myStyle={}">
<input type="text" name="abc" class="color" ng-change="myStyle={color:'green'}">
<br/>
<span ng-style="myStyle">Sample Text</span>
<pre>myStyle={{myStyle}}</pre>
</body>
Plunker - http://plnkr.co/edit/APrl9Y98Em0d6rxuzRDE?p=preview
However when I change it to ng-click it works.
ng-change requires ng-model,
<input type="text" name="abc" class="color" ng-model="someName" ng-change="myStyle={color:'green'}">
I've got the same issue, my model is binding from another form, I've added ng-change and ng-model and it still doesn't work:
<input type="hidden" id="pdf-url" class="form-control" ng-model="pdfUrl"/>
<ng-dropzone
dropzone="dropzone"
dropzone-config="dropzoneButtonCfg"
model="pdfUrl">
</ng-dropzone>
An input #pdf-url gets data from dropzone (two ways binding), however, ng-change doesn't work in this case. $scope.$watch is a solution for me:
$scope.$watch('pdfUrl', function updatePdfUrl(newPdfUrl, oldPdfUrl) {
if (newPdfUrl !== oldPdfUrl) {
// It's updated - Do something you want here.
}
});
Hope this help.
When you want to edit something in Angular you need to insert an ngModel in your html
try this in your sample:
<input type="text" name="abc" class="color" ng-model="myStyle.color">
You don't need to watch the change at all!
Maybe you can try something like this:
Using a directive
directive('watchChange', function() {
return {
scope: {
onchange: '&watchChange'
},
link: function(scope, element, attrs) {
element.on('input', function() {
scope.onchange();
});
}
};
});
http://jsfiddle.net/H2EAB/
One can also bind a function with ng-change event listener, if they need to run a bit more complex logic.
<div ng-app="myApp" ng-controller="myCtrl">
<input type='text' ng-model='name' ng-change='change()'>
<br/> <span>changed {{counter}} times </span>
</div>
...
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.name = 'Australia';
$scope.counter = 0;
$scope.change = function() {
$scope.counter++;
};
});
https://jsfiddle.net/as0nyre3/1/
First at all i'm seing your code and you haven't any controller. So i suggest that you use a controller.
I think you have to use a controller because your variable {{myStyle}} isn't compile because the 2 curly brace are visible and they shouldn't.
Second you have to use ng-model for your input, this directive will bind the value of the input to your variable.

Referencing the element that is calling a controller function Angularjs ( ng-change / ng-blur / ng-* ? )

The original question asked about how to determine which element called the controllers blurr function, but I didn't clarify that I was not specifically asking about ng-blur, but ng-* (ng-change, ng-focus, ng-mouseover, ng-*) in general. So, with that in mind:
How do I determine which element input is calling the blurr() and/or check() functions?
html
<body ng-app="test">
<div ng-controller="Cntrlr as cntrlr">
<form name="meta_test">
<input type="text" name='inpt' ng-model="cntrlr.inpt" ng-blur="cntrlr.blurr()" ng-change="cntrlr.check()" />
<input type="text" name='second' ng-model="cntrlr.second" ng-blur="cntrlr.blurr()" ng-change="cntrlr.check()" />
</form>
</div>
</body>
js
var app = angular.module("test", []);
app.controller("Cntrlr", ["$scope", function($scope){
this.blurr = function(){
alert("which input am I?");
alert("this is so meta.");
// ?
};
this.check = function(){
alert("this is how meta I am:");
alert(this);
}
$scope.Cntrlr = this; // see: (reference)
return $scope.Cntrlr;
}]);
You may be asking yourself "why would he want to do this?"
There are 2 reasons:
because I want to call:
$scope.user_form[meta_test.[(whatever this element is.name)]].$setValidity('spike', false);
because I'm curious. There has to be a simple way to do this.
(reference):
controller as syntax
Use this -
<input type="text" name='inpt' ng-model="cntrlr.inpt" ng-blur="cntrlr.blurr($event)" ng-change="cntrlr.check()" />
This returns the jQuery lite version of the event that causes the blurr function. Once you receive this element in your controller, you can pretty much do whatever you want with it.
The .target attribute of the event will give you the required element.
Should work
Try this:
<form name="meta_test">
<input type="text" name='inpt' ng-model="cntrlr.inpt" ng-blur="cntrlr.blurr()"
ng-change="cntrlr.check('One')" />
<input type="text" name='second' ng-model="cntrlr.second"
ng-blur="cntrlr.blurr()" ng-change="cntrlr.check('Two')" />
</form>
In JS,
this.check = function(Type){
if(Type == "One"){
//Then it is the first text box.
}else if(Type == "Two"){
//Then it is the second text box.
}
}

Resources