Dynamic default values for input box in angularJs - angularjs

I have a value which i get from a controller and two input box.
I need that whenever i enter any value in one input box. difference of the value retrieved from controller and input box get displayed in the other input box using angularJs.
e.g:-
{{sum}} --> is the value which I get from controller.
<input type="number" ng-model="firstnumber" />
<input type="number" ng-model="secondnumber"/>
What I tried was making service for setting and getting the sum value and watch to change the value every time a value is changed.
My service is :-
angular.module('myapp').service("cmModalService", function($scope){
var sum= ={};
getSum = function(){
return sum;
}
setSum = function(value){
sum=value;
};
});
In a controller I have defined
$scope.$watch('firstnumber', function(newValue, oldValue) {
var sum=cmModalService.getSum();
if(newValue!=null)
{ secondnumber = sum -firstnumber;
}
});
$scope.$watch('secondnumber', function(newValue, oldValue) {
var sum=cmModalService.getSum();
if(newValue!=null)
{ firstnumber = sum -secondnumber;
}
});
But whenever i change values in input box the flow never goes to watch method, and the values doesn't change.
Is there any other method also to achieve this.?
I have tried using ng-change also but still not able to get the exact result.
And inside controller i have defined the change methods as
$scope.changefirstnumber=function(firstnumber, sum){
$scope.secondnumber = sum- firstnumber;
};
$scope.changesecondnumber=function(secondnumber, sum){
$scope.firstnumber= sum- secondnumber;
};
and in html
[Plunker link]

You are not setting the scoped variable. Try this.
$scope.$watch('firstnumber', function(newValue, oldValue) {
var sum=cmModalService.getSum();
if(newValue!=null)
{ $scope.secondnumber = sum -$scope.firstnumber;
}
});
$scope.$watch('secondnumber', function(newValue, oldValue) {
var sum=cmModalService.getSum();
if(newValue!=null)
{ $scope.firstnumber = sum - $scope.secondnumber;
}
});
Working Plunkr

EDIT
With some new information you provided, is this what you're after? http://jsfiddle.net/37gv1kbe/
var app = angular.module('myApp',[]);
app.controller('MyController', function($scope,cmModalService)
{
$scope.firstnumber = 5;
$scope.secondnumber = 10;
$scope.$watch('firstnumber', function()
{
$scope.total = cmModalService.getSum() - $scope.firstnumber
});
$scope.$watch('secondnumber', function()
{
$scope.total = cmModalService.getSum() - $scope.secondnumber;
});
});
app.controller('MySecondController', function($scope,cmModalService)
{
$scope.rand = Math.round(Math.random() * 100);
cmModalService.setSum($scope.rand);
});
app.service('cmModalService', function()
{
var sum;
return {
getSum: function()
{
return sum;
},
setSum: function(value)
{
sum = value;
}
}
});
ORIGINAL ANSWER
regarding my comment, if you need to access the total in your controller, you can just save the val of firstnumber and secondnumber like so
http://jsfiddle.net/pvqm4tcw/
var app = angular.module('myApp',[]);
app.controller('MyController', function($scope)
{
$scope.firstnumber = 5;
$scope.secondnumber = 10;
$scope.$watch('firstnumber', function()
{
$scope.total = $scope.firstnumber + $scope.secondnumber;
});
$scope.$watch('secondnumber', function()
{
$scope.total = $scope.firstnumber + $scope.secondnumber;
});
});
html:
<body ng-app="myApp">
<div ng-controller="MyController">
<input type="number" ng-model="firstnumber" />
<br>
<input type="number" ng-model="secondnumber"/>
<br>
{{total}}
</div>
</body>
If you're using Angular 1.3+ they have a $watchGroup which can make the code even smaller
var app = angular.module('myApp',[]);
app.controller('MyController', function($scope)
{
$scope.firstnumber = 5;
$scope.secondnumber = 10;
$scope.$watchGroup(['firstnumber','secondnumber'], function()
{
$scope.total = $scope.firstnumber + $scope.secondnumber;
});
});

Related

How to bind data in 'value' attribute of <input tag> to NET core MVC model using angular

I’ve been playing around with Upload file - Streaming method. The original code, here:
https://github.com/aspnet/Docs/tree/master/aspnetcore/mvc/models/file-uploads/sample/FileUploadSample
However, I’m trying to get the data in the value attribute of <input value=” ”> using Angular, the idea is that I can POST the value into my MVC model instead of whatever is typed by the user (as in the original code). So, I have done this change to the input value property.
Streaming/Index.cshtml:
<div ng-app="myApp">
<div ng-controller="myCtrl">
..
<input value="#Model.name” type="text" name="Name" ng-model="name"/>
..
<button ng-click="createUser()">Create User</button>
..
</div>
</div>
#section scripts{
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script src="~/js/app.js"></script>
}
However, with Angular code running under app.js, the following piece of code actually fails with status code 400. This is because the passed value is “” and not the data under of value attribute of the HTML input tag.
App.js:
var User = (function () {
function User(name) {
this.name = name;
}
return User;
}());
var myApp = angular.module('myApp', []);
myApp.directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function () {
scope.$apply(function () {
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
myApp.service('userService', ['$http', function ($http) {
this.createUser = function(user) {
var fd = new FormData();
fd.append('name', user.name);
return $http.post('/streaming/upload', fd, {
transformRequest: angular.identity,
headers: {
'Content-Type': undefined
}
});
};
}]);
myApp.controller('myCtrl', ['$scope', 'userService', function ($scope, userService) {
$scope.createUser = function () {
$scope.showUploadStatus = false;
$scope.showUploadedData = false;
var user = new User($scope.name);
userService.createUser(user).then(function (response) { // success
if (response.status == 200) {
$scope.uploadStatus = "User created sucessfully.";
$scope.uploadedData = response.data;
$scope.showUploadStatus = true;
$scope.showUploadedData = true;
$scope.errors = [];
}
},
function (response) { // failure
$scope.uploadStatus = "User creation failed with status code: " + response.status;
$scope.showUploadStatus = true;
$scope.showUploadedData = false;
$scope.errors = [];
$scope.errors = parseErrors(response);
});
};
}]);
function parseErrors(response) {
var errors = [];
for (var key in response.data) {
for (var i = 0; i < response.data[key].length; i++) {
errors.push(key + ': ' + response.data[key][i]);
}
}
return errors;
}
The solution must be a simple one, but after much research, I haven’t been able to find out how to modify it to make the data in the value=’’” attribute being passed across. This might be a stupid question but a headache for me however since I’m a total newbie regarding Angular. Please have some mercy, help.
Thanks
Use the ng-init directive to initialize the model:
<input ng-init="name= #Model.name" type="text" name="Name" ng-model="name"/>

How to show model and view differently in AngularJS

I am implementing a functionality in AngularJS.
When the user enters 1.5, In view, it should show as 01:30, but when I fetch this scope value in the controller it should return as 1.5.
I have added code in plunker. Please find here.
Index.html:
<!DOCTYPE html>
<html ng-app="wbTimeConverter">
<head>
<link rel="stylesheet" href="style.css">
<script src="https://code.angularjs.org/1.5.8/angular.js"></script>
<script src="script.js"></script>
<script src="wbNumberToTime.js"></script>
</head>
<body ng-controller="AppController">
<h1>Hello Plunker!</h1>
<input type="text" md-maxlength="5" wb-number-to-time-convert ng-model="task" placeholder="task" ng-blur="onDataChange();" />
<input type="text" md-maxlength="5" wb-number-to-time-convert ng-model="project" placeholder="project" ng-blur="onDataChange();" />
<br>
<label>Task : {{task}}</label><br>
<label>Project : {{project}}</label><br>
<label>TotalResult : {{totalHours}}</label>
</body>
</html>
Controller - Script.js
var app = angular.module('wbTimeConverter', []);
app.controller('AppController', function($scope) {
$scope.onDataChange = onDataChange;
function onDataChange(){
console.log("res");
$scope.totalHours= parseFloat($scope.task) + parseFloat($scope.project, 10);
}
});
directive:
// 'use strict';
// /**
// * This directive is convert number into hours and minutes format-HH:MM
// * This will trigger when we change value in input element and gives respective value in time format
// */
app.directive('wbNumberToTimeConvert', function ($filter, $browser) {
return {
require: 'ngModel',
link: function ($scope, $element, $attrs, ngModelCtrl) {
var listener = function () {
var value = $element.val();
var result = convertToTime(value);
$element.val(result.timeFormat);
$element.attr('attr-hrs', result.decimalFormat);
};
// This runs when we update the text field
ngModelCtrl.$parsers.push(function (viewValue) {
return viewValue;
});
$element.bind('change', listener);
$element.bind('keydown', function (event) {
var key = event.keyCode;
// FIXME to handle validations
});
$element.bind('paste cut', function () {
$browser.defer(listener);
});
function convertToTime(value) {
var res = { 'timeFormat': '', 'decimalFormat': '' };
var inputValue = value;
if (inputValue.indexOf(':') > -1) {
inputValue = convertToNumberFormat(inputValue);
res.decimalFormat = inputValue;
} else {
res.decimalFormat = value;
}
inputValue = inputValue.split('.');
var hoursValue = inputValue[0];
if (inputValue.length > 1) {
var hrs = parseInt(hoursValue, 10);
hrs = isNaN(hoursValue) ? 0 : hrs;
hrs = (hrs < 10) ? '0' + hrs : hrs;
var minutesValue = inputValue[1];
var mins = parseInt(minutesValue, 10);
mins = (minutesValue.length < 2 && (mins < 10)) ? Math.round(mins * 6) : Math.round(mins * 0.6);
mins = (mins < 10) ? ('0' + mins) : mins;
inputValue = hrs + ':' + mins;
res.timeFormat = inputValue;
} else {
inputValue = (parseInt(inputValue, 10) < 10) ? '0' + parseInt(inputValue, 10) : parseInt(inputValue, 10);
inputValue = inputValue + ':' + '00';
res.timeFormat = inputValue;
}
return res;
}
function convertToNumberFormat(inputValue) {
var timeValue = inputValue.split(':');
var hours = parseInt(timeValue[0], 10);
var mins = parseInt(timeValue[1], 10);
if (isNaN(hours)){
hours = '00';
}
if (isNaN(mins)) {
mins = '00';
}
mins = Math.round(mins / 0.6);
if (mins < 10) {
mins = '0' + mins;
}
var number = hours + '.' + mins;
return number;
}
}
};
});
Here is the plunker link:
https://plnkr.co/edit/76lwlnQlGC0wfjixicCK?p=preview
On textbox blur, it is working fine of value differ in View and Controller on first time and from second time on blur in textbox, it is showing same value 01:30 in both view and controller. How can I resolve it?
You can keep your input inside the ng-model myValue and call a function format(value) to display what you need
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.myValue = "1.5";
$scope.format = function(value) {
var hrs = parseInt(Number(value));
var min = Math.round((Number(value) - hrs) * 60);
return hrs + ':' + min;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<input type="text" ng-model="myValue">
<br>Formatted Value : {{format(myValue)}}
<br>Base value : {{myValue}}
</div>
It's really easy using a directive! Take this as an example: JSFiddle
If you have a directive that requires ngModelController you can manipulate the viewValue really easily.
ngModelController has two properties that we're interested in, $modelValue and $viewValue. $modelValue is the value that you use on the scope and $viewValue is the one the user sees.
ngModelController also has a property $formatters which is an array of formatters that convert a modelValue to viewValue. So if the modelValue changes on the side of the controller it will go through the formatters until the end, and this will change the viewValue. If you want to create your own formatter, simply add it the array!
//This formatter will convert the modelValue to display as uppercase in the viewValue
ngModelController.$formatters.push(function(modelValue) {
if (modelValue) {
return modelValue.toUpperCase();
}
});
but the $formatters property only works for when the modelValue gets changed, so if the user is typing something into the input field, the viewValue is getting changed, the easiest way to handle this is to attach to the onBlur event in which we will alter the viewValue using another function provided by the ngModel controller. $setViewValue(value) will change the viewValue. If you change the viewValue in the directive, the view won't automatically update, so you need to call the $render function provided by the ngModelController
element.on('blur', function() {
ngModelController.$setViewValue(convertDoubleToTimeString(ngModelController.$modelValue));
ngModelController.$render();
});
For more information about this you can read this.
EDIT:
In this example I haven't written a parser that converts a viewValue (1:30) to a modelValue (1,5). So let's add one. I also have an updated JSFiddle
ngModelController.$parsers.unshift(function(viewValue) {
if (viewValue && viewValue.indexOf(':') < 0) {
return viewValue;
} else {
return convertTimeStringToDouble(viewValue)
}
});
Unshifting the parsers onto the $parsers array means it will be the first one to execute, this isn't really necessary, but why not, eh?
There are other ways of not changing the modelValue when the viewValue changes, but this one is the most correct one.
An alternative would be to just set the $viewValue directly without going through $setViewValue().
//ngModelController.$setViewValue(ngModelController.$modelValue.toUpperCase());
ngModelController.$viewValue = ngModelController.$modelValue.toUpperCase();
In that last line, it wont go through the usual steps of going through all the parsers and validators, so it's the less ideal solution.
You can declare a function in controller to return the calucalted value and in html you can call that function and pass the scope variable.
$scope.calculate = function(value){
var calculatedValue = /*Your operation*/;
return calculatedValue;
}
<input type="text" ng-model="value"\>
<p>{{calculate(value)}}</p>
If you want real time update of the calculated value with respect to the input value then you can use another scope variable to store the calculate value.
$scope.calculate = function(value){
$scope.calculatedValue = /*Your operation*/;
}
<input type="text" ng-model="value" ng-change="calculate(value)"\>
<p>{{calculatedValue}}</p>

Filter Change the color of the word in the sentence angularjs

I want to change the color of the word in the sentence How can i do that?
Controller code:
app.controller("myController",function($scope){
$scope.phrase="This is a bad phrase";
});
app.filter('censor', function(){
return function(input){
var cWords = ['bad', 'evil', 'dark'];
var out = input;
for(var i=0; i<cWords.length;i++){
out = out.replace(cWords[i], <span class="blue"></span>);
}
return out;
};
})
My view:
{{phrase | censor}}
First of all, if you want to bind html in your filter, you need to use ngSanitize and binding with the directive: ng-bind-html instead of {{ }}, like this:
<p ng-bind-html="ctrl.phrase | censor"></p>
In your js file you need to check if the phrase contain any of the words you want to filter out, then update the phrase.
angular
.module('app', ['ngSanitize'])
.controller('MainCtrl', function() {
var ctrl = this;
ctrl.phrase = 'This is a bad phrase';
})
.filter('censor', function() {
return function(input) {
var cWords = ['bad', 'evil', 'dark'];
var splitPhrase = input.split(' ');
var out = splitPhrase.reduce(function(acc, curr) {
if (cWords.indexOf(curr) > -1) {
acc.push('<span class="blue">' + curr + '</span>');
} else {
acc.push(curr);
}
return acc;
}, []);
return out.join(' ');
}
});
You can find an example here: http://jsbin.com/koxekoq/edit?html,js,output

Angularjs not updating variables

I want to display/update the calculation answer directly without the need of aditional buttons.
Or do i need a function and button to apply the changes?
<div ng-app="myApp" ng-controller="myCtrl">
A_Number: <input type="number" step="1" ng-model="A_Number"><br>
Display (A_Number): {{A_Number}}
<br>
square: {{square}}
</div>
controller:
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.square = $scope.A_Number * $scope.A_Number;
});
</script>
Make square as a method & use that method in interpolation directive, so that will evaluate on each digest.
Markup
square: {{square()}}
Code
$scope.square = function(){
//made error free
if(!isNaN($scope.A_Number))
return $scope.A_Number * $scope.A_Number;
return 0;
};
Add watch on A_Number to achieve the same. JSFiddle for reference -
https://jsfiddle.net/9a2xz61y/3/
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.square = 0;
$scope.$watch('A_Number', function(newValue, oldValue) {
{
if (!isNaN(newValue)) {
$scope.square = $scope.A_Number * $scope.A_Number;
}
}
});
});

$watch not updating in ng-repeat

I'm trying to calculate a total by multiplying 2 ng-models.
The models are in a ng-repeat, where I have a own controller for the rows.
On reload, it does the console log, but when I update the ng-models, they don't console log anymore and just don't work.
The controller:
app.controller('RowCtrl', function ($scope) {
$scope.unit_price = 0;
$scope.quantity = 0;
$scope.$watchCollection('[unit_price, quantity]', function(newValues) {
console.log(parseInt(newValues));
}, true);
$scope.total = $scope.unit_price * $scope.quantity;
});
UPDATED with fiddle: http://jsfiddle.net/r9Gmn/
Watch a function that calculates the total:
$scope.$watch(function() {
return unit_price * quantity;
}, function(newVal) {
$scope.total = newVal;
});
I agree with #pixelbits answer.
Just to add that as of angular 1.3 there is a new scope method $watchGroup:
An example http://plnkr.co/edit/2DvSmxUo5l8jAfBrSylU?p=preview
Solution:
$scope.$watchGroup(['unit_price', 'quantity'], function(val) {
$scope.total = val[0] * val[1];
});
Here's your fiddle working: http://jsfiddle.net/mikeeconroy/r9Gmn/1/
In your $scope.rows array on the controller you never defined the properties to be used in the RowCtrl's scope. Also you should make sure you use track by with ng-repeat so you don't get the dupes error.
var app = angular.module('myApp', []);
app.controller('RowCtrl', function ($scope) {
$scope.total = 0;
$scope.$watchCollection('[row.unit_price, row.quantity]', function(newValues) {
$scope.total = parseInt(newValues[0]) * parseInt(newValues[1]);
});
});
app.controller('MainCtrl', function ($scope) {
$scope.rows = [
{ unit_price: 10, quantity: 0 },
{ unit_price: 12, quantity: 0 },
{ unit_price: 15, quantity: 0 },
];
});
This should work fine (if implemented correctly), i.e. your logic is correct:
<div ng-controller="myCtrl">
Unit price:
<input type="number" ng-model="unit_price" />
<br />
Quantity:
<input type="number" ng-model="quantity" />
<hr />
Total: {{total}}
</div>
app.controller('myCtrl', function ($scope) {
$scope.unit_price = 0;
$scope.quantity = 0;
$scope.$watchCollection('[unit_price, quantity]', function(newValues) {
$scope.total = $scope.unit_price * $scope.quantity;
});
});
See, also, this short demo.

Resources