1

I'm new to Angular JS and I want to bind the input value to $scope object, just like we use ng-bind and ng-model for input fields to bind their values to DOM (the value changes as we type something in the input).

Can't I do the same? I mean just like displaying live text entered into input should be stored to $scope.foo.bar and hence it is printed in the console?

Here's what I'm trying:

<script type="text/javascript">
    var app = angular.module("testApp", []);
    app.service("stringService", function(){
        this.myFunction = function(word){
            return word.toUpperCase();
        };
    });
    app.controller("control", function($scope, $location, stringService, $http){
        $scope.age=24;
        $scope.foo = {bar: "hello"};
        console.log($scope.foo.bar);
        $scope.isNumber = angular.isNumber($scope.foo.bar);
    });

</script>

<div ng-app="testApp">
    <div ng-controller="control" ng-init="obj=[{name:'vikas'}, {name: 'vijay'}, {name: 'vinay'}]; mySwitch=true">
        <form name="testForm">
            <input type="text" name="bar" ng-model="foo.bar" required>
        </form>
        <div>{{isNumber}}</div>
    </div>
</div>

I can see the initial value (hello) in the console and false in DOM. But it doesn't update.

Vikas
  • 720
  • 1
  • 9
  • 30

3 Answers3

1

this line $scope.isNumber = angular.isNumber($scope.foo.bar); will only run once which is at angular initialize the page.

you can change isNumber to function in order to call multiple times.

$scope.isNumber = function() {
  return angular.isNumber($scope.foo.bar);
}

call it at template:

<div>{{isNumber()}}</div>    

var app = angular.module("testApp", []);
app.service("stringService", function() {
  this.myFunction = function(word) {
    return word.toUpperCase();
  };
});
app.controller("control", function($scope, $location, stringService, $http) {
  $scope.age = 24;
  $scope.foo = {
    bar: 1
  };
  console.log($scope.foo.bar);
  $scope.isNumber = function() {
    console.log(Number.isFinite($scope.foo.bar));
    console.log(typeof($scope.foo.bar));
    return angular.isNumber($scope.foo.bar);
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<div ng-app="testApp">
  <div ng-controller="control" ng-init="obj=[{name:'vikas'}, {name: 'vijay'}, {name: 'vinay'}]; mySwitch=true">
    <form name="testForm">
      <input type="text" name="bar" ng-model="foo.bar" required>
    </form>
    <div>{{isNumber()}}</div>
  </div>
</div>
Pengyy
  • 37,383
  • 15
  • 83
  • 73
  • "this line `$scope.isNumber = angular.isNumber($scope.foo.bar);` will only run once". `isNumber()` would also fire only once? Do I need to use `ng-change` like Parth suggested? – Vikas Jun 03 '17 at 01:54
  • @VikasKumar no, if you bind function in template, it will be fired every time in angular's digest cycle. – Pengyy Jun 03 '17 at 01:59
  • Just tried. It doesn't. Just shows output for initial value. – Vikas Jun 03 '17 at 02:13
  • Further it is showing false for every possible value, even for a string :O – Vikas Jun 03 '17 at 02:16
  • Okay. The function fires every time I change it. But it returns false even for a number after I change initial value? – Vikas Jun 03 '17 at 02:20
  • Maybe because I've already assigned `bar: 'sdf'` ? It appends this string with next input? Do I need to empty this key first? – Vikas Jun 03 '17 at 02:21
  • @VikasKumar no, that won't help. when you assign `input` with type `text`, it will turn to string when value changed. – Pengyy Jun 03 '17 at 02:22
  • Oh. So I need `parseInt()` ? – Vikas Jun 03 '17 at 02:23
  • @VikasKumar why not just assign `input` to `number` type and save the check part? – Pengyy Jun 03 '17 at 02:25
  • You're right but I'm new to it and just want to learn things :) Secondly I did parseInt but it returned `true` for everything now. Which is maybe `isNumber` returns `true` even for `NaN`. What say? – Vikas Jun 03 '17 at 02:27
  • @VikasKumar see here https://docs.angularjs.org/api/ng/function/angular.isNumber actually it is. – Pengyy Jun 03 '17 at 02:28
  • @VikasKumar also https://stackoverflow.com/questions/17351831/why-is-angular-isnumber-not-working-as-expected will clear your confusion. :-) – Pengyy Jun 03 '17 at 02:31
  • @VikasKumar it should be `Number.isFinite()` :-) – Pengyy Jun 03 '17 at 02:33
  • Oh. It's JS function that's why it showed error. Thanks a lot. I got what I needed. I just did `isFinite(24)` and worked. – Vikas Jun 03 '17 at 02:34
1

while @Pengyy's is quite correct in saying that you need to databind to a function, that is only part of the problem...

The problem is NaN, a perplexing numeric value that is not a number, but has type 'number' and some quicks having to do with bindings to string valued attributes like <input>'s value in html.

// the constant NaN
console.info(NaN);
// the type of the constant NaN
console.info(typeof NaN);
// NaN is not equal to NaN 
console.info(NaN === NaN);
// Number.isNaN checks for NaN
console.info(Number.isNaN(NaN));
// Number.isNaN returns false for any value unless typeof value === 'number'
console.info(Number.isNaN({
  a: []
}));

surprisingly, Angular's angular.isNumber function does not help us deal with these oddities. As stated in the documentation it

Determines if a reference is a Number. This includes the "special" numbers NaN, +Infinity and -Infinity. If you wish to exclude these then you can use the native `isFinite' method.

Ref: https://docs.angularjs.org/api/ng/function/angular.isNumber

To make matters worse, it also ignores all values for which typeof value !== 'number'

Finally, the last hurdle to overcome is that an HTML input's value is always a string! This means we need to convert it to number.

Therefore, the function needs to look like

$scope.isNumber = function(n) {
  // must convert to number because `Number.isNaN` does not coerce
  return isFinite(n) && !Number.isNaN(Number(n));
}

And the binding like

<div>{{isNumber(foo.bar)}}</div>

Here is an example

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<script type="text/javascript">
  (function() {
    "use strict";

    var app = angular
      .module("testApp", [])
      .controller({
        MyController
      });

    MyController.$inject = ['$scope'];

    function MyController($scope) {
      $scope.foo = {
        bar: "hello"
      };
      console.log($scope.foo.bar);
      $scope.isNumber = function(n) {
        console.info(typeof n);
        return isFinite(n) && angular.isNumber(Number(n));
      }
    }
  }());
</script>

<div ng-app="testApp">
  <div ng-controller="MyController">
    <form name="testForm">
      <input type="type" name="bar" ng-model="foo.bar" required>
    </form>
    <div>{{isNumber(foo.bar)}}</div>
  </div>
</div>

Notice how the raw type of the input is always 'string'

Aluan Haddad
  • 29,886
  • 8
  • 72
  • 84
0

Value must be updating but you do not have anything to communicate, You need a watcher or a function that fires the console log and checks for number.

Change your controller to :-

 app.controller("control", function($scope, $location, stringService, $http){
            $scope.age=24;
            $scope.foo = {bar: "hello"};
            console.log($scope.foo.bar);
            $scope.isNumber = angular.isNumber($scope.foo.bar);
            $scope.check = function() {
                $scope.isNumber =  angular.isNumber($scope.foo.bar);
                console.log($scope.foo.bar);
                console.log($scope.isNumber);
            }
        });

And in Html

<input type="type" name="bar" ng-model="foo.bar" ng-change="check()" required>
Parth Acharya
  • 545
  • 3
  • 13