Add class when model value is changed - angularjs

I have 2 datepickers and by default I am setting today's date in Check In Date and tomorrow's date in Check Out Date using ng-model.
The model value is changed when another dates are selected through the datepicker.
<div class="col-md-4">
<label class="control-label" for="date">Check In Date</label>
<input class="form-control" id="date" name="date" value="{{date | date: 'yyyy-MM-dd'}}" ng-model="checkinDate" type="text"/>
</div>
<div class="col-md-4">
<label class="control-label" for="date1">Check Out Date</label>
<input class="form-control" id="date1" name="date" value="{{date1 | date: 'yyyy-MM-dd'}}" ng-model="checkoutDate" type="text"/>
</div>
<div class="col-md-4">
<md-button class="md-raised" md-ripple-size="full" id="checkAvail" ng-click="checkAvail(roomdata.data)">CHECK AVAILABILITY</md-button>
</div>
I want to add a class 'shake' in my md-button when my ng-model="checkoutDate" is changed.
How do I use ng-class for this?

Your best bet is to use ng-class and have your condition set in there. Something like:
ng-class="{'shake': myModel == true}"

You give the model name checkoutDate in the class expression,
<div class="col-md-4">
<md-button class="md-raised" md-ripple-size="full" id="checkAvail" ng-click="checkAvail(roomdata.data)" ng-class="{shake: checkoutDate}">CHECK AVAILABILITY</md-button>
</div>
So, when ever you select a value in checkoutDate the class shake gets added.

<md-button class="badge" [ngClass]="{'md-raised': (status ==
'NOT-CHANGED'), 'shake': (status == 'CHANGED')}" md-ripple-
size="full" id="checkAvail" ng-click="checkAvail(roomdata.data)">
Check Availability</md-button>
Here in code you can employ a change function to capture that checkout date has been selected and in that function change 'status' as 'CHANGED' this will, in turn inject the class you require to the button you have defined
<input class="form-control" id="date1" name="date" value="{{date1 |
date: 'yyyy-MM-dd'}}" ng-model="checkoutDate" ng-
click="changeStatus()" type="text"/>
change status will contain converting status of variable from 'NOT-CHANGED' to 'CHANGED'
changeStatus(){
this.status = 'CHANGED';
}
Do not forget to define status in the constructor. Hope this helps

Related

ng-change not triggering for second time when value updated with event.target.value

I'm trying to reset value of input:textbox if the value entered is non-numeric. I'm using ng-change to validate the input. Refer the code below
<input type="text" ng-change="onChange(this.P)" ng-model="P" class="col-xs-4 col-sm-4 col-md-4 col-lg-4" placeholder="Principle" />
<input type="text" ng-change="onChange(this.R)" ng-model="R" class="col-xs-4 col-sm-4 col-md-4 col-lg-4" placeholder="Rate" />
<input type="text" ng-change="onChange(this.T)" ng-model="T" class="col-xs-4 col-sm-4 col-md-4 col-lg-4" placeholder="Time" />
Note onChange function is getting called from all three textboxes.
The onChange function is as follows
$scope.onChange = function(n) {
if (!$scope.isNumeric(n)) {
event.currentTarget.value = '';
}
Issue: The problem is that if I enter the same non-numeric alphabet twice the ng-change event is not triggered.
For example if the key q is pressed twice the ng-change will not trigger when the key is pressed for the second time.
See jsFiddle here
Additional question: Is there any better way to reset the value of the textbox?
You can use input type 'number' which is an inbuilt feature of HTML5. It allows only numeric values. You don't need the onChange function.
<input type="number" ng-model="P" class="col-xs-4 col-sm-4 col-md-4 col-lg-4" placeholder="Principle" />
However, that comes with up/down arrows in the corner. You can hide them with CSS if you don't need them.
The reason ng-change is not firing again for same alphabet because you are updating the currentTarget.value but not the ng-model.
Suppose you enter d in the text box. Now $scope.P = "d". Now ng-change will fire and you clear the text box, remember $scope.P is still "d". Now if you enter "d" again $watch wont fire because previous value of $scope.P is "d".
To resolve this update the model instead of currentTarget.value.
Here is the updated fiddle: https://jsfiddle.net/vwmfbgy2/4/
You can pass model key along with ng-change and just update model value so it will automatically update your input
angular.module('SimpleInterestApp', [])
.controller('simpleCtrl', function($scope) {
$scope.onChange = function(obj, modelKey) {
var n = obj[modelKey];
if (!$scope.isNumeric(n)) {
obj[modelKey] = '';
}
};
$scope.isNumeric = function(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular.min.js"></script>
<body ng-app="SimpleInterestApp" ng-controller="simpleCtrl">
<div class="container">
<div class="row">
<input type="text" ng-change="onChange(this, 'P')" ng-model="P" class="col-xs-4 col-sm-4 col-md-4 col-lg-4" placeholder="Principle" />
<input type="text" ng-change="onChange(this, 'R')" ng-model="R" class="col-xs-4 col-sm-4 col-md-4 col-lg-4" placeholder="Rate" />
<input type="text" ng-change="onChange(this, 'T')" ng-model="T" class="col-xs-4 col-sm-4 col-md-4 col-lg-4" placeholder="Time" />
</div>
</div>
</body>

What is the best way to calculate field values with a function? AngularJS

I have some fields in an AngularJS form that need to record a total percentage. Form example;
Gender split of a group - % Males, % Females
Currently I am using a field for each gender.
<div class="form-group col-md-2">
<label for="male">% Male:<span class="error">*</span></label>
<input type="number"
name="males"
max="100"
class="form-control"
ng-model="newReport.males"
required>
</div>
<div class="form-group col-md-2">
<label for="female">% Female:<span class="error">*</span></label>
<input type="number"
class="form-control"
ng-model="newReport.females"
ng-readonly="true"
value="#{{ females() }}"
placeholder="#{{ females() }}"
required>
</div>
Then I use this function to calculate the Female %
$scope.females = function() {
return 100 - this.newReport.males;
};
However, my ng-model="newReport.females" never seems to get set. The placeholder does get the correct value from the function but won't persist since the model is not picking it up.
Is there a better way to do this? Also, once I am getting it to set the model properly, what is the best way to validate that the 2 fields add up to 100?
Thanks!

How to make field required with k-ng-model?

I have validation issue if i use k-ng-model on field that field is not required with Angularjs validation , User can submit the form so below code field is required even i dont select the value user can still submit the form.. Any idea how to solve it ?
main.html
<div class="row">
<div class="form-group col-md-12">
<label for="themesList" class="required col-md-4">Themes:</label>
<div class="col-md-8">
<select class="multiselect" kendo-multi-select="themes"
k-options="challengThemesOptions" data-text-field="'text'"
data-value-field="'id'" name="themesList"
k-ng-model="challengesDTO.themesKyList" required
id="themesList"></select>
<p class="text-danger" ng-show="addChallengeForm.themesList.$touched && ddChallengeForm.themesList.$error.required">Theme(s) is required</p>
</div>
</div>
</div>
You can use ng-model with k-ng-model, Try assigning ng-model to a seperate variable and use ng-required.
<select class="multiselect" kendo-multi-select="themes"
k-options="challengThemesOptions" data-text-field="'text'"
data-value-field="'id'" name="themesList"
k-ng-model="challengesDTO.themesKyList" ng-model="challengesDTO.themesKyListValue" ng-required
id="themesList"></select>
This solution worked for me: kendo ui, angular require validation for numeric text box
Just create a hidden input for the each kendo widget and bind the model from your k-ng-model also to the ng-model of the hidden field. The k-ng-model seems to be no NgModelController, which is why the validators cannot hook into the models $validators and do their work.
<input kendo-date-time-picker k-ng-model="$ctrl.event.endDate"></input>
<input type="hidden" name="endDate" ng-model="$ctrl.event.endDate" required></input>

angular ui date picker causing $valid to be set to false

I have three radio buttons: Active, Dissolved, Concluded.
If Active chosen then "Active" is stored in the column in the table.
If Dissolved is chosen then an input with a date picker is displayed. This is the same for Dissolved. Therefore the column is set to nvarchar.
What I'm finding is when I save the screen nothing happens. I stepped through the code and got to this line:
if ($scope.addeditregulatoryapprovalForm.$valid)
$valid evaluates to false. If I hover over it, I see $error, if I expand that I see date, if I expand that I see an array with one element, when I expand that I see the date that is displaying in the input field.
If what I'm seeing is correct and that it's the date that is causing the issue I just don't know why it's causing an issue. I have to pick a date, even if it's the same date that's already picked, before I can save.
Any ideas?
Here's the code:
<div class="col-xs-7 form-inner-group padRt0">
<div class="clearfix stackDate">
<input name="DissolutionConcludedStatusDate" id="DissDate1_0" type="radio" ng-model="vm.regulatoryApproval.DissolutionConcludedStatusID" ng-value="1"> Active<br />
</div>
<div class="clearfix stackDate">
<input name="DissolutionConcludedStatusDate" id="DissDate1_1" type="radio" ng-model="vm.regulatoryApproval.DissolutionConcludedStatusID" ng-change=vm.setDate() ng-value="2">
Dissolved <span ng-if="vm.regulatoryApproval.DissolutionConcludedStatusID==2">
<input class="form-field cal-field" type="text" ng-required="vm.regulatoryApproval.DissolutionConcludedStatusID==2"
name="DissolvedStatusDate"
ng-model="vm.regulatoryApproval.DissolutionConcludedStatusDate"
datepicker-popup="dd-MMM-yyyy" close-text="Close" ng-model="vm.regulatoryApproval.DissolutionConcludedStatusDate"><br />
<div ng-show="addeditregulatoryapprovalForm.submitted || addeditregulatoryapprovalForm.DissolvedStatusDate.$touched">
<span class="error" ng-show="addeditregulatoryapprovalForm.DissolvedStatusDate.$error.required">Please select a Dissolved date</span>
</div>
</span>
</div>
<div class="clearfix stackDate">
<input name="ConcludedStatusDate" id="DissDate1_2" ng-model="vm.regulatoryApproval.DissolutionConcludedStatusID" type="radio" ng-change=vm.setDate() ng-value="3">
Concluded <span ng-if="vm.regulatoryApproval.DissolutionConcludedStatusID==3">
<input type="date" class="form-field cal-field" ng-required="vm.regulatoryApproval.DissolutionConcludedStatusID==3"
name="ConcludedDate"
ng-model="vm.regulatoryApproval.DissolutionConcludedStatusDate"
datepicker-popup="dd-MMM-yyyy" close-text="Close" ng-model="vm.regulatoryApproval.DissolutionConcludedStatusDate"><br />
<div ng-show="addeditregulatoryapprovalForm.submitted || addeditregulatoryapprovalForm.ConcludedStatusDate.$touched">
<span class="error" ng-show="addeditregulatoryapprovalForm.ConcludedStatusDate.$error.required">Please select a Concluded date</span>
</div>
</span>
</div>
</div>
I figured out what the issue was. Because I had to save the date as a string in the database when the form was being saved it was considered invalid because it wanted a date from the datepicker. I had to convert the string to a date when it pulled it from the database before assigning it to the model.

AngularJS - how to sync result of calculated input field to a scope variable

I'm trying to sync the result of a calculated form field into a scope variable. For example:
<div class="form-group">
<label for="val1" class="control-label">Val 1</label>
<input class="form-control" name="val1" type="number" ng-model="data.val1" id="val1">
</div>
<div class="form-group">
<label for="val2" class="control-label">Val 2</label>
<input class="form-control" name="val2" type="number" ng-model="data.val2" id="val2">
</div>
<div class="form-group">
<label for="score" class="control-label">Score</label>
<input class="form-control" name="score" value="{{data.val1+data.val2}}" type="text" id="score">
</div>
<br/>data: {{data}}
How can I sync the result (i.e. the score field) into the scope variable $scope.data.score? I have tried ng-model="data.score" but that breaks the calculation.
You can see the example in action here:
http://plnkr.co/edit/fc9XcyyYGtAk0aGVV35t?p=preview
How do I get the last line to read data: {"val1":1,"val2":2,"score":3}?
Note that I'm looking for a solution that involves minimal to no code support at the controller level. For example, I know you can set up a watch in the controller for both val1 and val2 and then update the score in the watcher. This is what I wanted to avoid, if it's possible in angular at all. If it's not (theoretically) possible, I'd really appreciate an explanation of why it's not.
A quick background might help. Basically we have a simple form builder app that defines a form and all its fields in an xml file. Here's a sample of what the xml would look like:
<form name="test">
<field name="val1" control="textbox" datatype="number">
<label>Val 1</label>
</field>
<field name="val2" control="textbox" datatype="number">
<label>Val 2</label>
</field>
<field name="score" control="textbox" datatype="number">
<label>Score</label>
<calculate>[val1]+[val2]</calculate>
</field>
</form>
When a form is requested, the system will need to pick up the xml, loop through all the fields and generate an angular style html to be served to the browser and processed by angular. Ideally, I want to keep all the form specific logic (validation, show/hide, calculation etc) confined to the html, and keep the controller (js) logic generic for all forms.
The only solution I can come up with is to dynamically load watcher functions, through something like this: eval("$scope.$watch('[data.val1,data.val2]')..."), but as I said, I really want to avoid this, because it's just tedious, and feels extremely dodgy :)
The first dirty way.
In your case you can move all logic from controller into html with using combination of ng-init and ng-change directives.
<div class="form-group">
<label for="val1" class="control-label">Val 1</label>
<input class="form-control" name="val1" type="number" ng-model="data.val1" ng-change="data.score = data.val1 + data.val2" id="val1">
</div>
<div class="form-group">
<label for="val2" class="control-label">Val 2</label>
<input class="form-control" name="val2" type="number" ng-model="data.val2" ng-change="data.score = data.val1 + data.val2" id="val2">
</div>
<div class="form-group" ng-init="data.score = data.val1 + data.val2">
<label for="score" class="control-label">Score</label>
<input class="form-control" name="score" ng-model="data.score" type="text" id="score">
</div>
<br/>data: {{data}}
I don't think that it's the clearest solution, but you can leave your controller without any changes with it.
Demo on plunker.
The second dirty way.
There is one more way, but now you don't need ng-init and ng-change directives. You can add just one dirty expression in html:
<div id="main-container" class="container" style="width:100%" ng-controller="MainController">
{{data.score = data.val1 + data.val2;""}} <!-- key point -->
<div class="form-group">
<label for="val1" class="control-label">Val 1</label>
<input class="form-control" name="val1" type="number" ng-model="data.val1" id="val1">
</div>
<div class="form-group">
<label for="val2" class="control-label">Val 2</label>
<input class="form-control" name="val2" type="number" ng-model="data.val2" id="val2">
</div>
<div class="form-group">
<label for="score" class="control-label">Score</label>
<input class="form-control" name="score" ng-model="data.score" type="text" id="score">
</div>
<br/>data: {{data}}
;"" in expression stops evaluating of angular expression to text in html.
Demo on plunker.
See if this works, in your HTML change,
<input class="form-control" name="score" ng-model = "data.score" type="text" id="score">
and, in your controller do,
var myApp = angular.module('myapp', [])
.controller('MainController', function($scope) {
$scope.data = { val1: 1, val2: 2, score: 3};
$scope.$watch('[data.val1,data.val2]', function (newValue, oldValue) {
$scope.data.score = newValue[0] + newValue[1];
}, true);
})
Demo plunk, http://plnkr.co/edit/gS0UenjydgId4H5HwSjL?p=preview
If you want to know how you can do it, then i have one solution for you make a ng-change event for both of your text box and sum both the number there and use ng-model in the third text box then, you can see it will work as per your need.
For the first time load you need to calculate it out side only.

Resources