Model update is not propagated dynamically - javascript

I want to sum up 2 values and display the result in the 3rd input:
HTML
<div ng-app="myApp">
<div ng-controller="MainCtrl as mainCtrl">
Main {{mainCtrl.foo}} <br/>
<input type="text" ng-model="mainCtrl.foo"/>
<input type="text" ng-model="mainCtrl.foo2"/>
<input type="text" ng-model="mainCtrl.foo3"/>
<br/>
</div>
</div>
JS
var myApp = angular.module('myApp', []);
var my = {};
my.MainCtrl = function() {
this.foo = '1';
this.foo2 = '2'
this.foo3 = this.sumUp();
}
my.MainCtrl.prototype.sumUp = function() {
return this.foo + this.foo2;
}
// register all controllers
myApp.controller('MainCtrl', my.MainCtrl);
My problem is that the 3rd input is set only when the document is loaded but it is not dynamically changing while typing values in first two inputs.
Fiddle:
http://jsfiddle.net/K64wb/

Use parameter ng-change for input-fields 1 and 2.
Solution for U ;) ng-change="mainCtrl.foo3=mainCtrl.sumUp()"
Example:
<div ng-controller="MainCtrl as mainCtrl">
Main {{mainCtrl.foo}} <br/>
<input type="text" ng-change="mainCtrl.foo3=mainCtrl.sumUp()" ng-model="mainCtrl.foo"/>
<input type="text" ng-change="mainCtrl.foo3=mainCtrl.sumUp()" ng-model="mainCtrl.foo2"/>
<input type="text" ng-model="mainCtrl.foo3"/>
<br/>
</div>

When your view loads, it only fires the controller function once. So it assigns foo and foo2, and then computes foo3, and then it's done. this.sumUp is never called again.
You can add ng-change="mainCtrl.foo3=mainCtrl.sumUp()" to the input boxes like Mularski suggests. This causes the sumUp function to run and be assigned to foo3 every time the input value changes. I think that looks kind of messy, though. And if you decided to add more input boxes to add up, you have to remember to put ng-change on all of them.
Another way to do it is to assign the sumUp function itself to foo3 like this
this.foo3 = this.sumUp;
instead of assigning the result of sumUp like you are doing (this.foo3 = this.sumUp();). Then in your view, assign foo3() to the ng-value of the textbox:
<input type="text" ng-value="mainCtrl.foo3()"/>
(you can't assign it to ng-model because the function isn't writeable).
Now you're telling the textbox to always show the result of that function, and it will fire whenever any of its dependencies change (i.e. foo and foo2).
Here's a Fiddle.

Related

Why binding to null not work when value of number input illegal in AngularJs

See example here: https://jsfiddle.net/codefalling/u2mn764x/1/
<div ng-app>
<div ng-controller="TodoCtrl">
<input type="number" ng-model="value" size="30" >
<input type="button" ng-click="change()" class="btn-primary" value="TEST" >
</div>
</div>
function TodoCtrl($scope) {
$scope.change = function() {
$scope.value = null
}
}
When I type 10 into number input, click button, it turn to be empty.
However when I type a standalone e or . into number input, then click button, nothing happend. But $scope.value = 123 stills works.
So, Why view didn't get update(empty) in this situation?
Additional, is there any other way to empty it?
To clear out the HTML 5 number controls, you can check the state of the control and if it is invalid then override its value to blank. I have updated your fiddle with the below code https://jsfiddle.net/u2mn764x/3/
<div ng-app>
<div ng-controller="TodoCtrl">
<input type="number" ng-model="value" size="30" id='mynumber'>
<input type="button" ng-click="change()" class="btn-primary" value="TEST" >
</div>
</div>
function TodoCtrl($scope) {
$scope.change = function() {
if (!document.getElementById('mynumber').validity.valid)
{
$scope.value = null
document.getElementById('mynumber').value='';
}
}
}
For short, because e and . is not the complete legal numeric value. According to Foalting point number in W3 spec:
if the value started by ., it must be followed by one or more "0—9";
if the value started by e, it must be followed by an optional + or -, and one or more "0-9"
As the HTML check is not passed, it will not trigger the JS, as I imagine. If you continue to input .1 or e45, it works.
As soon as you type 10 inside Number Input,Angular will bind 10 and it will be like $scope.value = 10, but when you fire click event,you are changing the value to null like $scope.value = null,so send the value of model through the event and bind it to your variable.
<div ng-app>
<div ng-controller="TodoCtrl">
<input type="number" ng-model="value" size="30" >
<input type="button" ng-click="change($event,value)" class="btn-primary" value="TEST" >
</div>
</div>
And the javascript code :
function TodoCtrl($scope) {
$scope.change = function($event,val) {
$scope.value = val;
}
}
Thanks to comment of #zeroflagL.I found the answer.
Model did not have a value when input is illegal. So $scope.value = null or $scope.value = '' won't work because they are illegal value,too.
Model value and view value are both undefined, so angular did not update view.
We can use DOM API to empty illegal input manually. Or set modal to a value, force dirty check then set it to null again:
$scope.value = 0
$scope.$apply();
$scope.value = null
See https://jsfiddle.net/codefalling/xhcz3Lbj/

optimizing the code by passing the targeted element in AngularJS

I tried to implement the below functionality. There are 2 text boxes. When we type on box 1 the box 2 will also have the value of box 1 and vice versa.
using the same ng-model will do this, but I need to learn how to use elements(references) and identify them in a controller to do this
<body ng-app="myApp" ng-controller="myControl">
Name 1 : <input type="text" ng-model="name1" ng-change="change1()" />
Name 2 : <input type="text" ng-model="name2" ng-change="change2()" >
</body>
var app = angular.module('myApp', []);
app.controller('myControl',function($scope,$http){
$scope.change1 = function(){
$scope.name2= $scope.name1;
}
$scope.change2 = function(){
$scope.name1= $scope.name2;
}
});
Fiddle of the code
How can I use one function instead of using the two functions change1 and change2( I think if I pass a reference it can be done. But i could not find a way to do that) ?
Just have a look at this code you call same function on ng-change and it works fine
<body ng-app="myApp" data-ng-controller="MainCtrl" id="div1">
Name 1 : <input type="text" ng-model="name1" ng-change="change1(name1)" />
Name 2 : <input type="text" ng-model="name2" ng-change="change1(name2)" />
<script>
var app = angular.module('myApp', []);
app.controller('MainCtrl', function($scope){
$scope.change1 = function(val){
$scope.name2= val;
$scope.name1=val;
}
});
</script>
</body>
By making the the ng-model value structure like object, then Javascript prototypal will do the trick, While you are assigning name1 object to name2 they both will follow the same object, as update in any of the value array will update other. Thats the reason why we don't want such feature then we uses cloning of object, In jQuery its .clone() & in angular its known as angular.copy which creates a new deep copy of the object which will not follow this rule.
Markup
Name 1 : <input type="text" ng-model="name1.value"/>
Name 2 : <input type="text" ng-model="name2.value"/>
Code
var app = angular.module('myApp', []);
app.controller('myControl',function($scope,$http){
$scope.name1= {};
$scope.name2= {};
$scope.name1= $scope.name2; //will update two object according no need of ng-change
});
Forked Fiddle

How to get the value in angularJS from the input box

How can I get the value of name2?
function DemoController($scope) {
$scope.name1 = 'LISA';
//How can I get the value of name2?
console.log($scope.name2) //this does not work
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="" ng-controller="DemoController">
{{ name1 }}
<input type="text" placeholder="Lisa" ng-model="name2">
</div>
This happens because your not initialize the name2 inside the controller. so there is no property called name2 in the scope at the moment of console.log . and name2 property will create on the scope right after your first change on the input. so thats why its getting undefined.
here is the Demo Plunker, check the console.
$scope.$watch('name2', function(newVal, oldVal) {
console.log("new value : " + newVal);
console.log("old value : " + oldVal);
});
i have added a $watch on name2 property (and this $watch function will execute when changing the value of name2), note that its undefined first and it will take the value of input right after you type something in the textbox.
try this
<div ng-app="" ng-controller="DemoController">
{{ name2 }}
<input type="text" placeholder="Lisa" ng-model="name2">
</div>
First, your controller is running before $scope.name2 even existed yet. You should have the console report the changes at some point AFTER. Remove that line from your code. (console.log...)
Whenever the text in name2 changes, $scope.name2 will be set to that value. You can see the effect if you ADD the following to the controller:
$scope.saveChanges = function () {
alert($scope.name2);
}
And to the HTML:
<button ng-click="saveChanges()">See Value</button>
try to follow me on this one.
On the first execution of the script, the variable (or property - doesn't really matter for this topic) is not declared.
Once the interpreter reaches the console.log function, it tries to call name2's value, But as we said - it is not defined.
In order to log the data you're binding, you should implement some logic that executes console.log only after a change or maybe even using $scope.apply. (I believe that $scope.apply is too far for you right now and you should ignore it).
Bottom line is - Your variable is not defined for the first iteration, therefore you're getting this result.
You must submit form to get Values or you use Watch Function
function DemoController($scope) {
$scope.name1 = 'LISA';
$scope.submitName = function () {
console.log($scope.name2)
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="" ng-controller="DemoController">
{{ name1 }}
<input type="text" placeholder="Lisa" ng-model="name2">
<button ng-click="submitName()">click </button>
</div>
name 2 will change as you type in the input box. You can see this by adding
{{name2}}
to your html
the controller will not see the change in name2 unless you watch for it, you can do this using $watch, add this to your controller
$scope.$watch('name2', function() {
console.log($scope.name2);
});
Put your ng model in watch for getting the updates
function DemoController($scope) {
$scope.name1 = 'LISA';
//this will work
$scope.$watch(function(val){
if(val){
console.log($scope.name2);
}
});
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="" ng-controller="DemoController">
{{ name1 }}
<input type="text" placeholder="Lisa" ng-model="name2">
</div>

ng-model doesn't change value when field contains user input

I'm still fairly new to angular.js. This seems like it should be very simple, but I'm stumped.
I have an input field:
<input type="text" placeholder="Search" ng-model="search.txt">
And I have a button that calls this function in my controller on ng-click:
$scope.clearSearch = function() {
$scope.search = {txt:"qqqqq"};
}
Clicking the button behaves as expected - the input value on the page becomes "qqqqq". So the data binding seems correct.
However, if I type anything into the field first and then press the button, the input value does not change on the page - the input field keeps the value I typed. Why is that?
What I'm really trying to do is clear the field, I'm just using "qqqqq" for illustration - setting the value to null has the same behavior.
It works:
Script:
angular.module('myapp',[])
.controller('myctrl',function($scope){
$scope.search = {text:'some input'};
$scope.clearSearch = function () {
$scope.search={text:null};
}
});
Markup:
<div ng-app="myapp" ng-controller="myctrl">
<input type="text" ng-model="search.text"/>
<button ng-click="clearSearch()">clear</button>
</div>
In plunker

Keyup function into form element

I have a script I am using to copy a field into another input field using keyup blur paste. This script works, however I need to modify it to also go into two different form elements which are named data-cost="" and debt="", instead of the <div id="viewer">
This is the script as I have it now :
$(function () {
$('#account_balance1').on('keyup blur paste', function() {
var self = this;
setTimeout(function() {
var str = $(self).val();
$("#viewer").text(str.replace(/^\$/, ''));
}, 0);
});
$("#viewer").text($('#Website').val().replace(/^\$/, ''));
});
This is the html :
<!--This where I get the value from -->
<input type="text" class="balance" id="account_balance1" name="cardb" value=""/>
<!--the first 2 elements are where I need the values to go -->
<input data-cost="" debt="" value="" type="checkbox" name="f_2[]"/>
if you need the two attributes (data-cost and debt) to be each set to your value you need:
$("input[data-cost][debt]").attr('data-cost',str.replace(/^\$/, ''));
$("input[data-cost][debt]").attr('debt',str.replace(/^\$/, ''));
Just use that selector then
$("input[data-cost][data-debt]")
I think you're maybe having a fundamental misunderstanding of what the data attributes are for? You're aware that they will not be posted with the form? I think what you're looking for is the data function which will allow you to set the data attributes http://api.jquery.com/data/.
Perhaps you want data-cost and data-debt?
So if your input looks like this:
<input data-cost="" data-debt="" value="" type="checkbox" name="f_2[]" id="checkboxId" />
Then you can set the values in your javascript like this:
var value1="some value";
var value2="another value";
$('#checkboxId').data('cost', value1);
$('#checkboxId').data('debt', value2);
I don't believe having an attribute named simply "debt" as you have it above is valid.
I'd do it this way (setTimeout was useless) :
$(function () {
$('#account_balance1').on('keyup blur paste', function () {
var self = this;
var nextCheckbox = $(self).next("input[type='checkbox']");
var str = $(self).val();
$("#viewer").text(str.replace(/^\$/, ''));
nextCheckbox.data({
cost: str,
debt: str
});
/*
You won't be able to see changes if you inspect element,
so just check in console
*/
console.log(nextCheckbox.data());
});
});
And your html markup must be slightly modified :
<!--This where I get the value from -->
<input type="text" class="balance" id="account_balance1" name="cardb" value="" />
<!--the first 2 elements are where I need the values to go -->
<input data-cost="" data-debt="" value="" type="checkbox" name="f_2[]" />
<!--I added the viewer to check if everything works properly -->
<div id="viewer"></div>

Categories

Resources