Vikas
Vikas

Reputation: 749

How to bind input value to $scope object in angular js?

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.

Upvotes: 1

Views: 1917

Answers (3)

Aluan Haddad
Aluan Haddad

Reputation: 31803

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'

Upvotes: 1

Pengyy
Pengyy

Reputation: 38161

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>

Upvotes: 1

Parth Acharya
Parth Acharya

Reputation: 545

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>

Upvotes: 0

Related Questions