使用Angularjs和ng-model将毫米转换为英尺和英寸,反之亦然



我想将长度从毫米转换为英尺和英寸,反之亦然。用户可以输入mm或ft&in。情况是,我总是想把数据保存在mm数据库,但使用角看到它在两种格式。

我已经创造了一个解决方案。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。但我真的很期待看到一个聪明的解决方案。

将输出格式化到视图中最好使用过滤器。

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,然后使用它的$parser和$formatters来拦截模型和视图之间的通信来实现的。

恰好

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

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

对于这个例子,我定义了如下的变量
    $scope.inches = 0;
    $scope.mm = 0;

那么我们就在两个变量上创建一个表。重申一下,只要mm变量发生变化,这个函数就会被调用,这样可以确保保持mminches之间的关系。

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

你也可以创建一个自定义过滤器,如下所示…如果您只需要以格式化的方式显示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' }}

我对Christoph Hegemann的回答做了一个改进。

该指令只使用一个属性,该属性指向一个作用域对象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

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

假设我在模型中存储了25英寸。调用show函数时,val为25。它将它除以12,然后返回,结果显示在文本框中。当您输入4时,store函数将被调用,val为4。它将其乘以12并返回48,该值存储在模型中。

最新更新