44

I'm trying to build a simple calculator in Angular in which I can override the total if I want. I have this part working but when I then go back to enter in a number in fields one or two the total isn't updated in the field.

Here is my jsfiddle http://jsfiddle.net/YUza7/2/

The form

<div ng-app>
  <h2>Calculate</h2>

  <div ng-controller="TodoCtrl">
    <form>
        <li>Number 1: <input type="text" ng-model="one">  
        <li>Number 2: <input type="text" ng-model="two">
        <li>Total <input type="text" value="{{total()}}">       
        {{total()}}
    </form>
  </div>
</div>

The javascript

function TodoCtrl($scope) {
    $scope.total = function(){
        return $scope.one * $scope.two;
    };
}
1
  • As @Martin said, you need to bind the input to a writable value (so not a function) to be able to get it back from the $scope in the controller. Commented Oct 2, 2012 at 18:26

5 Answers 5

40

You can add ng-change directive to input fields. Have a look at the docs example.

Sign up to request clarification or add additional context in comments.

3 Comments

Found ng-change to be a better fit as it doesn't interfere with initial loaded elements
While a useful answer, it qualifies as a link-only answer. Would be great to have an example here on site, referring to the concrete question from the OP...
You should use $watcher in directive instead of ng-change with a "callback" in the view. Watch your data in your directive code and save the de-register function in a var to call it when scope event $destroy fire.
28

I'm guessing that when you enter a value into the totals field that value expression somehow gets overwritten.

However, you can take an alternative approach: Create a field for the total value and when either one or two changes update that field.

<li>Total <input type="text" ng-model="total">{{total}}</li>

And change the javascript:

function TodoCtrl($scope) {
    $scope.$watch('one * two', function (value) {
        $scope.total = value;
    });
}

Example fiddle here.

1 Comment

+1 input fields should always have an associated ng-model/$scope property. The "value" parameter shouldn't be used in Angular apps. See also stackoverflow.com/questions/10610282/…
5

I wrote a directive you can use to bind an ng-model to any expression you want. Whenever the expression changes the model is set to the new value.

 module.directive('boundModel', function() {
      return {
        require: 'ngModel',
        link: function(scope, elem, attrs, ngModel) {
          var boundModel$watcher = scope.$watch(attrs.boundModel, function(newValue, oldValue) {
            if(newValue != oldValue) {
              ngModel.$setViewValue(newValue);
              ngModel.$render();
            }
          });

          // When $destroy is fired stop watching the change.
          // If you don't, and you come back on your state
          // you'll have two watcher watching the same properties
          scope.$on('$destroy', function() {
              boundModel$watcher();
          });
        }
    });

You can use it in your templates like this:

 <li>Total<input type="text" ng-model="total" bound-model="one * two"></li>      

Comments

3

You just need to correct the format of your html

<form>
    <li>Number 1: <input type="text" ng-model="one"/> </li>
    <li>Number 2: <input type="text" ng-model="two"/> </li>
        <li>Total <input type="text" value="{{total()}}"/>  </li>      
    {{total()}}

</form>

http://jsfiddle.net/YUza7/105/

1 Comment

The problem with this is if I change the total, then go and change either Number 1 or Number 2 the total no longer works as I would've overridden the 'value'. Using ng-change doesn't have this problem
-3

Create a directive and put a watch on it.

app.directive("myApp", function(){
link:function(scope){

    function:getTotal(){
    ..do your maths here

    }
    scope.$watch('one', getTotals());
    scope.$watch('two', getTotals());
   }

})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.