How to achieve Functional binding with ng-model (With plnkr) - javascript

I have a dob column and values comes in this is in yyyy-mm-dd format say 2013-01-01 and I need to show it in input box as 1 Jan. I can achieve this by writing a function and then return exact value from that function. But function could not be called from input box using ng-model where as it can be called using ng-bind in spans. I can understand that function calling in input box will break two way binding. But what other approach I can use for this.
http://plnkr.co/edit/pZDpypsxM1OA2JwFhjjp?p=preview
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
<script type="text/javascript" >
var app = angular.module('app', []);
app.controller('AppCtrl', function ($scope) {
$scope.dob = "2013-01-01";
$scope.getDateOfBirth = function(dob){
var months = ["Jan","Feb","Mar","Apr","May","June","July","Aug","Sep","Oct","Nov","Dec"]
var split = dob.split("-");
return parseInt(split[2])+" "+months[parseInt(split[2])-1];
}
});
</script>
<span ng-app="app" ng-controller="AppCtrl" ng-bind="getDateOfBirth(dob)"></span>
<input type="text" ng-model="getDateOfBirth(dob)"/>

You can use ng-init to assign the value returned by the function and assign it to a model:
<input ng-init="myDOB = getDateOfBirth(dob);" type="text" ng-model="myDOB">
DEMO

You can use ng-init to set the value and ng-change to keep the value updated
http://plnkr.co/edit/q1hg0R?p=preview

For dates, phone numbers, etc., you can use ui-mask. Hope this helps someone!

Related

How to detect input field value change in ng-repeat

I will have N number of input fields and every field will have a value CHANGE without getting in or out of focus. How can I detect value change of every input field.
I only found one question related and using that I tried following but it is not working. can Any one help further
for (var i=0;i<$scope.customers.product.length;i++)
{
//i m trying to get unique ids and bining input fields for change
$('#total-i').on('input', function() {
alert($(this).val()); // get the current value of the input field.
});
}
//there will be multiple of input fields having unique ids
<input id="total-{{$index}}" value={{cust.price*cust.quantity}}"/>
It should be easy and possible with ng-change provided you have ng-model associated to input.
<input id="total-{{$index}}" value={{cust.price*cust.quantity}}" ng-model="total" ng-change="updatemethod()"/>
total and updatemethod() should be part of controller $scope.
I'd create an object to associate with the ng-model and then watch it. Since you didn't provide a Codepen of fiddle instance to meddle with, I'm not sure this works, check it out.
//for each index
$.each(modelObject, function(key, value) {
//set a watcher
var watchString = "modelObject[" +key + "]";
$scope.$watch(watchString, function (newValue, oldValue) {
$scope.update(modelObject[key]);
});
});
The question you linked in your question is not about Angular (it uses jQuery). Where is the Angular way to do it (considering you are showing inputs with ng-repeat):
<div ng-repeat="i in items">
<input ng-model="i" ng-change="update(i)"/>
</div>
With this code, whenever you will update i (eg: when you will change the input value), the update(i) method will be triggered.
Here is a tiny example of what I'm explaining:
function MyCtrl($scope) {
$scope.items = ['1', '2', '3', '4', '5'];
$scope.update = function(item) {
alert(item + ' has been changed!');
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app ng-controller="MyCtrl">
<div ng-repeat="i in items">
<input type="text" ng-model="i" ng-change="update(i)" />
</div>
</div>

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>

Model update is not propagated dynamically

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.

How to concatenate a JS variable in an HTML script?

Can I do something like this?
var counter = SomeJSFunctionThatReturnsAvalue();
<tr><td> <input type="file" name="file-upload"+"_counter" id="file-upload" /></tr></td>
Can I do that? I need to append an underscore and an incremented number to the name.
Also, an off-topic question - that function above returns the value of an input type, for example:
<input type="hidden" name="hidden-input-type" value="2" />
Is the value "2" a number that I can use for math operations? If not, how can I make it one?
Here you go fella.
<head>
<script>
function test($count) {
document.getElementById("test1").setAttribute("name","file-upload_" + $count);
}
</script>
</head>
<body>
<p>some content</p>
<input id="test1" type="file" name="file-upload" id="file-upload" value="2"/>
<p>some other content</p>
<script>test(1);</script>
</body>
Your SomeJSFunctionThatReturnsAvalue(); would pass it to test() function.
to get the value of "2" from your second question for use in a math function, just do:
var value = document.getElementById("test1").getAttribute("value");
document.write(parseInt(value, 10) + 3);
which returns 5.
To append the return value of your function to the name of the input tag, you can assign it to the name attribute of the input.
var counter = SomeJSFunctionThatReturnsAvalue();
var fileUpload = document.getElementById('file-upload');
fileUpload.name = fileUpload.name + "_" + counter;
You can get the type of a variable by using "typeof"
typeof myValue; // "string"
You can change this to an integer by using the parseInt() function.
var intValue = parseInt(myValue, 10);
You can change the name using .setAttribute("name", theNameUwantToChangeTo);:
function changeName(number){
var ele = document.getElementById("file-upload");
ele.setAttribute("name", b.getAttribute("name")+ "_" + number);
}
changeName(number);
To get the value, just .value:
function getV(){
return document.getElementById("file-upload").value;
}
var number = getV();
In case it does not return int, use parseInt()
function getV(){
return parseInt(document.getElementById("file-upload").value);
}
var number = getV();
Maybe you would benefit from looking into Angular.js or Ember.js if you are trying to do things like this. They can do data binding so that you can make readable and dynamic code just like what you are trying to create in your question.
If not that^ then this:
I saw you mentioned in a comment that you are dynamically creating the list. That is where you should be assigning the correct name with the counter (assuming there's no desire for counter to change dynamically. If there is a dynamic change then tell us what events are doing the change) Could you show us the code that is doing that please?

Categories

Resources