Greg P
Greg P

Reputation: 802

AngularJS currency filter on input field

I have the following input field

 <input type="text" class="form-control pull-right" ng-model="ceremony.CeremonyFee | number:2">

it is showing up correctly but has been disabled. The error I am receiving is "[ngModel:nonassign] Expression 'ceremony.CeremonyFee | number:2' is non-assignable". I understand why it is in error, but do not know how to get this to work on an input field. Thanks.

Upvotes: 0

Views: 2082

Answers (4)

Greg P
Greg P

Reputation: 802

I found and used the solution found on this page.

http://jsfiddle.net/k7Lq0rns/1/

    'use strict';
    angular.module('induction').$inject = ['$scope'];
    angular.module('induction').directive('format',['$filter', function ($filter) {
      return {
        require: '?ngModel',
        link: function (scope, elem, attrs, ctrl) {
            if (!ctrl) return;

            ctrl.$formatters.unshift(function (a) {
                return $filter(attrs.format)(ctrl.$modelValue)
            });

            elem.bind('blur', function(event) {
                var plainNumber = elem.val().replace(/[^\d|\-+|\.+]/g, '');
                elem.val($filter(attrs.format)(plainNumber));
            });
        }
  };
}]);

relatively easy to apply it.

Upvotes: 0

Chris Hermut
Chris Hermut

Reputation: 1758

As an error states you have got an 'non-assignable' expression in your ng-model attribute.

You should use only ceremony.CeremonyFee.

| is used on ng-repeat to indicate what expression should be used as filter.

If you want to have that <input> populated with initial data in your controller/link you should give it an initial value ex.

$scope.ceremony = {
    CeremonyFee: 'My first ceremony'
}

And every time your <input> element data will be changed CeremonyFee will be updated as well.

Upvotes: 0

Hitmands
Hitmands

Reputation: 14179

UPDATE:

really I don't understand what you need, but, if you want just that users can insert only two digits you should use a simple html attributes, have a look on min, max, step...

Follows a pure js solution, but I don't suggest something like that!

angular.module('test', []).controller('TestCtrl', function($scope) {
  var vm = $scope;
  var testValue = 0;
  Object.defineProperty(vm, 'testValue', {
    get: function() { return testValue; },
    set: function(val) {
      val = Number(val);
      
      if(angular.isNumber(val) && (val < 100 && val > 0)) {
        console.log(val);
        testValue = val;
      }
    } 
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<section ng-app="test">
  <div ng-controller="TestCtrl">
    <input style="display:block; width: 100%; padding: 1em .5em;" type="number" ng-model="testValue" />
  </div>
</section>


the ng-model directive requires a viewmodel assignable (or bindable) property, so, you cannot add a pipe...

angular.module('test', [])
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app="test" ng-init="testValue = 0">
  <label ng-bind="testValue | currency"></label>
  <input style="display:block;" ng-model="testValue" type="number"/>
</div>

Upvotes: 0

input with ng-model is for inputting data, number filter is for displaying data. As filter values are not bindable, they are not compatible, as you can see. You have to decide what you want to do with that input.

Do you want it to be an input? User can input his own number and you only needs to validate? Use i.e. pattern attribute:

<input type="text" ng-model="ceremony.CeremonyFee" pattern="[0-9]+(.[0-9]{,2})?">

Do you want it to be an output? User does not need to input his own value? Do not use ng-model, use value instead:

<input type="text" value="{{ceremony.CeremonyFee | number:2}}" readonly>

Upvotes: 2

Related Questions