数据绑定使用Angularjs和ng-model将mm转换为英尺和英寸,反之亦然

时间:2014-08-01 12:34:22

标签: javascript angularjs angularjs-directive angular-ngmodel

我想将长度从mm转换为英尺和英寸,反之亦然。用户可以输入mm或ft& in。案例是我总是希望将数据保存为mm到数据库,但使用angular来以两种格式查看它。

我已经为它创建了一个解决方案。 http://plnkr.co/edit/thgx8vjsjxwfx6cLVVn1?p=preview 但它每次都使用ng-change来转换值。

我想知道一些角度专家是否更喜欢做类似的事情。请注意,我只打算保存单个值$scope.lengthmm

var app = angular.module('plunker', []);

    app.controller('MainCtrl', function($scope) {
 // $scope.lengthtodb = 0;

  $scope.mmToFtIn =function(){

    toInch = $scope.lengthmm * 0.0393701;
    toFt = toInch/12;
    OutputFT = Math.floor(toFt);
    OutputInch = (toFt - Math.floor(toFt))*12;
    $scope.lengthft = OutputFT;
    $scope.lengthin = OutputInch;


    $scope.Result1 = OutputFT + "ft" + OutputInch + "Inches";


  };

   $scope.FtInTomm =function(){

    tomm = (($scope.lengthft *12)+  $scope.lengthin)*25.4;
    $scope.lengthmm = tomm;

     $scope.Result2 = tomm;


  };

});

此外,由于会有很多字段使用相同的逻辑,因此方法mmToFTIn需要分成两种方法来分别绑定ft和inch。但我真的很期待看到一个聪明的解决方案。

3 个答案:

答案 0 :(得分:2)

将输出格式化为视图最好使用滤镜。

JS:

app.filter('inchFilter', function() {
  return function(input) {
    return Math.floor(input * 0.0393701);
  };
});

HTML:

<input name="mm" type="text" value="{{lengthmm | inchFilter}}">

编辑:

对于更完整和更强大的解决方案,我使用指令扩展了plunker,现在允许在非度量字段上进行双向绑定。

app.directive('enhancedInput', function($parse){
  return {
    restrict: 'A',
    require: 'ngModel',
    link : function(scope, element, attr, ngModelCtrl){
      ngModelCtrl.$parsers.unshift(scope.$eval(attr.fromMm));
      ngModelCtrl.$formatters.unshift(scope.$eval(attr.toMm));
    }
  };
});

这是通过首先“要求”ngModelController,然后使用其$ parsers和$ formatters来拦截模型和视图之间的通信来实现的。

plunker

答案 1 :(得分:0)

一种选择是在毫米变量上创建$watch,然后更新英寸模型。这可能是比ng-change更好的选择,因为$watch会在范围内更改变量时触发,而不仅仅是当文本框的输入发生变化时。

我为你创建了an example。虽然你声明你只想使用一个变量,但我相信以这种方式使用第二个变量确实是更好的方法。或者,您可以使用对象或数组来维护单个变量,同时存储两个值。

对于这个例子,我将变量定义如下

    $scope.inches = 0;
    $scope.mm = 0;

然后我们只为两个变量创建一个监视器。重申一下,只要mm变量发生变化,就会调用此函数,以便确保mminches之间的关系得以维持。

    $scope.$watch('mm', function(newVal, oldVal) {
      $scope.inches = newVal / 25.4;
    });

您还可以create a custom filter如下...如果您只需要以格式化方式显示mm(而不是将其用于计算或其他方式),这甚至可能是更好的解决方案

angular.module('myFilters', []).filter('mmToInches', function() {
  return (function (input) {
    return (input / 25.4);
  });
});

然后再做...

Inches Filter : {{ mm | mmToInches }}

您可以向单个过滤器的过滤器添加参数,可以进行两次转换。

angular.module('myFilters', []).filter('convert', function() {
  return (function (input, type) {
    if (type == 'mm2inch')
    {
      return (input / 25.4);
    } else if (type == 'inch2mm') {
      return (input * 25.4);
    }
  });
});

Inches Filter : {{ mm | convert:'mm2inch' }}
MM Filter : {{ inches | convert:'inch2mm' }}

答案 2 :(得分:0)

以下是我对Christoph Hegemann's answer所做的改进。

该指令仅使用一个属性,该属性指向范围对象inchesShowFeet(您可以随意调用它)。

<input type="text" ng-model="data.beamLength" 
       ng-enhanced-input="inchesShowFeet" 
       ng-model-options="{ debounce: 500 }" />

正如他所提到的,指令本身使用ng-model属性的解析器

app.directive('ngEnhancedInput', function($parse){
  return {
    restrict: 'A',
    require: 'ngModel',
    link : function(scope, element, attr, ngModelCtrl){
      ngModelCtrl.$parsers.unshift(scope.$eval(attr.ngEnhancedInput).store);
      ngModelCtrl.$formatters.unshift(scope.$eval(attr.ngEnhancedInput).show);
    }
  };
});

通常在控制器中设置的对象具有show和store功能。这个名字很有趣,但它是我能想到的最好的。一个将值返回到文本框中的 show ,另一个将值返回到模型中的 store

$scope.inchesShowFeet = {
    show: function(val){ return val / 12; },
    store: function(val){ return val * 12; }
};

所以,我说我的模型中存有25英寸。 show 函数被调用,其val为25.它将它除以12并返回它,它将显示在文本框中。当您输入4时,商店功能会被调用val为4.它将它乘以12并返回48,这将得到&#39;存储在模型中。