how to sync different model in angular - angularjs

<input ng-model='yourName'>
<p>{{yourName}}</p>
when I type some words in the input yourName, the <p> will display what I typed immediately.
===
If I need do some sync in different model,
eg.
<input ng-model='start'>
<input ng-model='end'>
<input ng-model='step'>,default 10.
when I changed the model start to 1, it automatically update the model end to 11,vice versa.
what should I do?
this problem is solved.just add type="number", thanks
<!DOCTYPE html>
<html ng-app>
<head>
<title></title>
<script src="lib/angular/angular.js"></script>
</head>
<body ng-controller='MyController'>
<input type="number" ng-model="start">
<input type="number" ng-model="end">
<input type="number" ng-model="step">
<script>
function MyController($scope){
$scope.$watch('start',function(newStart){
$scope.end = newStart + $scope.step;
console.log(1);
}) ;
$scope.$watch('end',function(newEnd){
$scope.start = newEnd - $scope.step;
console.log(2);
}) ;
$scope.step = 10;
}
</script>
</body>
</html>

In your controller, use a $scope.$watch() to perform behaviour when each property changes.
e.g.
$scope.$watch('dateStart', function (newDateStart) {
if (!newDateStart) return;
$scope.dateEnd = newDateStart;
});
$scope.$watch('dateEnd', function (newDateEnd) {
if (!newDateEnd) return;
$scope.dateStart = newDateEnd;
});
Note that I would recommend that you first check if there is already a value for the other field, or if the user has manually modified it. If so, don't automatically change the other field. Otherwise, you will be forever overwriting what the user chose for the other field.

Related

Using Angular, how to display validation issues on an event?

I do not want to render validation issues until a user attempts to submit my form.
I have a form with 2 fields, one is required and ng-minlength=5, the other is ng-minlength=5. If the fields are invalid, I would like to display them with a red background if the user attempts to submit the form.
I am attempting to do this by determining the style in the controller based on the field's validity and if the submit button has been clicked.
This isn't working for me though, the field never displays as red. Any suggestions as to how I can get this approach to work?
Is this a reasonable approach, or is there a strategy more idiomatic to Angular?
https://jsfiddle.net/dk89dhp2/
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.5/angular.min.js"></script>
</head>
<style>
.my_invalid{
border-color:#ffdddd;
background-color:#ffdddd;
background-image: none;
}
</style>
<body ng-app="myapp">
<div ng-controller="MyController" >
<form name="myFormNg">
<input type="text" class="myForm.getFormFieldCssClass(myFormNg.id)" name="id" ng-model="myForm.id" ng-minlength="5" required> Id <br/>
<input type="text" class="myForm.getFormFieldCssClass(myFormNg.name)" name="name" ng-model="myForm.name" ng-minlength="5"> Name <br/>
<button type="button" ng-click="myForm.submit()">Submit</button>
</form>
<script>
angular.module("myapp", [])
.controller("MyController", function($scope) {
$scope.myForm = {};
$scope.showErrors = false;
$scope.myForm.submit = function() {
$scope.showErrors = true;
}
$scope.myForm.getFormFieldCssClass = function(ngModelController) {
if (ngModelController.$pristine)
return "";
return ngModelController.$valid && $scope.showErrors ? "" : "my_invalid";
// additional logic to check if empty and required?
}
} );
</script>
now it's not working because you're using class that allow you to bind only "static" classes instead of the ng-class directive.
i'd change your code just to add the directive, about your approach, i'd stick with it, you need some sort of control that check if the form is valid and if the error are enabled.
<input type="text" ng-class="{'input1Error': myForm.getFormFieldCssClass(myFormNg.id})" />
<input type="text" ng-class="{'input2Error': myForm.getFormFieldCssClass(myFormNg.id})" />
then at the end of your method change the return type to boolean to determine whether to apply or not the class
$scope.myForm.getFormFieldCssClass = function(ngModelController) {
if (ngModelController.$pristine)
return false;
return ngModelController.$invalid && $scope.showErrors ? true : false;
}
you can try as below also.
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.5/angular.min.js"></script>
</head>
<style>
.my_invalid{
border-color:#ffdddd;
background-color:#ffdddd;
background-image: none;
}
</style>
<body ng-app="myapp">
<div ng-controller="MyController" >
<form name="myFormNg">
<input type="text" class="myForm.getFormFieldCssClass(myFormNg.id)" id="textbox1" name="id" ng-model="myForm.id" ng-minlength="5" required> Id <br/>
<input type="text" class="myForm.getFormFieldCssClass(myFormNg.name)" id="textbox2" name="name" ng-model="myForm.name" ng-minlength="5"> Name <br/>
<button type="button" ng-click="myForm.submit()">Submit</button>
</form>
<script>
angular.module("myapp", [])
.controller("MyController", function($scope) {
$scope.myForm = {};
$scope.showErrors = false;
$scope.myForm.submit = function() {
angular.element('#textbox1').css('border-color', 'red');
angular.element('#textbox2').css('border-color', 'red');
}
$scope.myForm.getFormFieldCssClass = function(ngModelController) {
if (ngModelController.$pristine)
return "";
return ngModelController.$valid && $scope.showErrors ? "" : "my_invalid";
// additional logic to check if empty and required?
}
} );
</script>
</body>
</html>

Input will not update onblur with ng-blur

I am trying to do something that should be pretty simple. When a user tabs out of an input field, I want to take their value and change the value to contain two decimal places for each number even .00
I have a working plunkr
Here is the HTML
<input type="text" class="form-control" only-digits ng-blur="vm.cleanNumbers(vm.order.frameInformation.A)" ng-model="vm.order.frameInformation.A">
The controller is getting called and the value is changed but the input never reflects the change
function cleanNumbers(value) {
if (value !== 0) {
var hasDecimal = value.indexOf('.') > -1;
value = value.replace('$', '');
value = value.replace(/[,]+/g, '');
value = parseFloat(value);
if (isNaN(value)) {
return 0;
}
value = value.toFixed(2);
}
}
In the plunkr I'm logging the values and seeing what I would hope for the input to update with.
Here is your required answer.
The first issue is to use the controller as Syntax,
ng-controller="test as vm"
Since you are converting the value to Float and trying to display it in the text field,
you are getting the same value since the text value of a float is same as the text.
You have to convert the float back to string to display as you like.
Here is the revised code,
// Code goes here
(function () {
'use strict';
angular
.module('admin', [])
.controller('test', test);
test.$inject = ['$log'];
function test($log) {
$log.debug('controller loaded');
/*jshint validthis: true */
let vm = this;
vm.order = {};
vm.cleanNumbers = cleanNumbers;
function cleanNumbers(test) {
$log.debug(test);
let value = vm.order[test];
if (value != 0 && value != undefined) {
var hasDecimal = value.indexOf('.') > -1;
value = value.replace('$', '');
value = value.replace(/[,]+/g, '');
value = parseFloat(value);
if (isNaN(value)) {
return 0;
}
//value = value.toFixed(2);
function toNumberString(num) {
return value.toString() + ".00"
}
vm.order[test] = toNumberString(value);
console.log(value);
console.log(vm.order);
}
}
}
})();
<!DOCTYPE html>
<html ng-app="admin">
<head>
<script data-require="angularjs#1.5.5" data-semver="1.5.5" src="https://code.angularjs.org/1.5.5/angular.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="test as vm">
<div class="col-md-4">
{{vm.order}}
<div class="form-group">
<label class="control-label">A</label>
<input type="text" class="form-control" ng-blur="vm.cleanNumbers('A')" ng-model="vm.order.A" />
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label class="control-label">B</label>
<input type="text" class="form-control" ng-blur="vm.cleanNumbers('B')" ng-model="vm.order.B" />
</div>
</div>
</body>
</html>
PLEASE run above SNIPPET
HERE IS A WORKING DEMO
First of all, I encourage you to use the latest version of AngularJS (1.6.2 for now). There is still some bug fixes and good changes.
Secondly you are using "vm" controller prefix, but you are not saying that to your controller binder. In your index.html(plunkr) this line;
<body ng-controller="test">
Is I believe intended to be;
<body ng-controller="test as vm">
Also, even this is not handling the actual behaviour that you are trying to do, but I'm sure you can figure the rest of it out by yourself.

Is this a bug? Angular removes object params when corresponding input is not valid

Please see this:
http://plnkr.co/edit/soubKCayeLAqgDOel8AL?p=preview
<!DOCTYPE html>
<html ng-app="testApp">
<head>
<script data-require="angular.js#1.4.1" data-semver="1.4.1" src="https://code.angularjs.org/1.4.1/angular.js"></script>
<script src="script.js"></script>
</head>
<body ng-controller="testCtlr">
<pre>{{contacts | json}}</pre>
<div ng-repeat="contact in contacts">
<div ng-repeat="email in contact.emails">
<input type="email" name="email" ng-model="email.email">
<input type="text" name="text" ng-model="email.text">
</div>
</div>
</body>
</html>
var app = angular.module('testApp', []);
app.controller('testCtlr', ["$scope", function ($scope) {
$scope.contacts = [
{
id:'',
name:'',
emails:[
{
email: 'e1',
text: 'fghfgh'
},
{
email: 'e2',
text: 'hjkhjk'
}
],
}
];
}]);
you see if you change the text in the email text box it is removed from the obj unless it is a valid email...
Its not bug, its desired behaviourof angular, when value is not valid , it is not binded to ngModelController ,
https://docs.angularjs.org/api/ng/type/ngModel.NgModelController
But there is possibility to attach custom email validator ($parsers)
https://docs.angularjs.org/api/ng/type/ngModel.NgModelController#$parsers
You can push parser to array of parser so it will be executed as last, and return modelValue so you will "override" angular validator and bind invalidValue to ngModel.
It is not a bug, this is by design. The input type email uses regex to validate email address inputs. If the input is not valid it is removed from the model.
On another note - if you wrap your stuff in a form - you can determine the validation state of the inputs. Also, as you are using a repeat, you will need an index.
Here is an example of what I mean:
<form name="myForm">
<div ng-repeat="contact in contacts">
<div ng-repeat="email in contact.emails track by $index">
<div ng-show="myForm.email{{$index}}.$invalid">Invalid email.</div>
<input type="email" name="email{{$index}}" ng-model="email.email">
<input type="text" name="text" ng-model="email.text">
</div>
</div>
</form>
I have updated your Plunker here.
These are the validation states you can use:
//[formName].[inputFieldName].property
myForm.email1.$pristine;
// Boolean. True if the user has not yet modified the form.
myForm.email1.$dirty
// Boolean. True if the user has already modified the form.
myForm.email1.$valid
// Boolean.True if the the form passes the validation.
myForm.email1.$invalid
// Boolean. True if the the form doesn't pass the validation.
myForm.email1.$error

Angularjs action on click of button

I am trying to do some calculation but it is getting done as soon as I enter the amount. I just want this to happen on click of a button rather than automatically.
What I have done so far:
<!DOCTYPE html>
<html ng-app="myAppModule">
<head>
<title>Angular JS - programming-free.com</title>
<link href="https://dl.dropbox.com/u/96099766/DetailModalExample/bootstrap.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="lib/angularjs.min.js"></script>
</head>
<body>
<div ng-controller="myAppController" style="text-align:center">
<p style="font-size:28px;">
Enter Quantity:
<input type="text" ng-model="quantity"/>
</p>
<h2>Total Cost: Rs.{{calculateval(quantity,10)}}</h2>
</div>
<script type="text/javascript">
var myAppModule = angular.module('myAppModule', []);
myAppModule.controller('myAppController', function($scope,calculateService) {
$scope.quantity=1;
$scope.calculateval = function(xval,yval) {
return calculateService.calculate(xval,yval);
}
});
// Service
myAppModule.factory('calculateService', function(){
return {
calculate: function(xval,yval){
return xval*yval;
}
}
});
</script>
</body>
</html>
The calculation occurs immediately since the calculation call is bound in the template, which displays its result when quantity changes.
Instead you could try the following approach. Change your markup to the following:
<div ng-controller="myAppController" style="text-align:center">
<p style="font-size:28px;">Enter Quantity:
<input type="text" ng-model="quantity"/>
</p>
<button ng-click="calculateQuantity()">Calculate</button>
<h2>Total Cost: Rs.{{quantityResult}}</h2>
</div>
Next, update your controller:
myAppModule.controller('myAppController', function($scope,calculateService) {
$scope.quantity=1;
$scope.quantityResult = 0;
$scope.calculateQuantity = function() {
$scope.quantityResult = calculateService.calculate($scope.quantity, 10);
};
});
Here's a JSBin example that demonstrates the above approach.
The problem with this approach is the calculated result remains visible with the old value till the button is clicked. To address this, you could hide the result whenever the quantity changes.
This would involve updating the template to add an ng-change on the input, and an ng-if on the result:
<input type="text" ng-change="hideQuantityResult()" ng-model="quantity"/>
and
<h2 ng-if="showQuantityResult">Total Cost: Rs.{{quantityResult}}</h2>
In the controller add:
$scope.showQuantityResult = false;
$scope.calculateQuantity = function() {
$scope.quantityResult = calculateService.calculate($scope.quantity, 10);
$scope.showQuantityResult = true;
};
$scope.hideQuantityResult = function() {
$scope.showQuantityResult = false;
};
These updates can be seen in this JSBin demo.

Angular - default value for model

Say I have some html as follows:
<html>
<head> angular etc. </head>
<body ng-app>
<div ng-controller="MyCtrl">
<input ng-model="weight" type="number" min="{{minWeight}}" max="{{maxWeight}}">
<p>{{weight}}</p>
</div>
</body>
</html>
and the following controller:
function MyCtrl($scope){
$scope.weight = 200;
$scope.minWeight = 100.0;
$scope.maxWeight = 300.0;
}
The "min" and "max" will show the user their input is bad, and if I hard code them to say, 100 and 300, it will make sure the value is never bound to the model at all (why isn't the behavior the same??). What I'd like to do is only actually change the "weight" if the value meets the input requirements. Any thoughts?
I don't fully understand what are you trying to do.
HTML:
<html>
<head> angular etc. </head>
<body ng-app="MyApp">
<div ng-controller="MyCtrl">
<input ng-model="weight" type="number" min="{{minWeight}}" max="{{maxWeight}}">
<p>{{weight}}</p>
</div>
</body>
</html>
Angular: [Edit]
var app = angular.module('myApp', []);
app.controller('MyCtrl', ['$scope', function MyCtrl($scope){
$scope.weight = 200;
$scope.minWeight = 100.0;
$scope.maxWeight = 300.0;
$scope.$watch('weight', function (newValue, oldValue) {
if(typeof newValue === 'number') {
if(newValue > $scope.maxWeight || newValue < $scope.minWeight) {
$scope.weight = oldValue;
}
}
});
}]);
But here is an example I made in jsFiddle. I hope this was a solution you were looking for.
[Edit]
http://jsfiddle.net/migontech/jfDd2/1/
[Edit 2]
I have made a directive that does delayed validation of your input field.
And if it is incorrect then it sets it back to last correct value.
This is totally basic. You can extend it to say if it is less then allowed use Min value, if it is more then allowed use Max value it is all up to you. You can change directive as you like.
http://jsfiddle.net/migontech/jfDd2/2/
If you have any questions let me know.

Resources