Привязка данных для преобразования мм в футы и дюймы или наоборот с использованием Angularjs и ng-модели
Я хочу конвертировать длины от мм до футов и дюймов или наоборот. Пользователь может вводить либо в мм, либо в футах и дюймах. В этом случае я всегда хочу сохранить данные в мм в базу данных, но использую угловой, чтобы увидеть их в обоих форматах.
Я уже создал решение для этого. 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
нужно разделить на два метода, чтобы связать футы и дюймы по отдельности. Но я действительно с нетерпением жду разумного решения.
3 ответа
Форматирование вывода на представление лучше всего выполнять с помощью фильтров.
JS:
app.filter('inchFilter', function() {
return function(input) {
return Math.floor(input * 0.0393701);
};
});
HTML:
<input name="mm" type="text" value="{{lengthmm | inchFilter}}">
Редактировать:
Для более полного и мощного решения я расширил вантуз директивой, чтобы теперь разрешить двустороннюю привязку и к неметрическим полям.
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, а затем с помощью его $ синтаксических анализаторов и $formatters для перехвата связи между моделью и представлением.
Вот улучшение, которое я внес в ответ Кристофа Хегемана.
Директива использует только один атрибут, который указывает на объект области 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 get вызывается с val
из 25. Он делит его на 12 и возвращает его, который отображается в текстовом поле. Когда вы вводите 4
, функция магазина get вызывается с val
из 4. Он умножает его на 12 и возвращает 48, что сохраняется в модели.
Одним из вариантов является создание $watch
на миллиметровой переменной, а затем обновите модель в дюймах. Это, вероятно, лучший вариант, чем ng-change, потому что $watch
будет срабатывать каждый раз, когда переменная изменяется в области видимости, а не только при изменении ввода в текстовое поле.
Я создал пример для вас. Хотя вы заявляете, что хотите использовать только одну переменную, я считаю, что использование второй переменной - действительно лучший подход. В качестве альтернативы вы можете использовать объект или массив для поддержки одной переменной при сохранении двух значений.
Для этого примера я определил переменные следующим образом
$scope.inches = 0;
$scope.mm = 0;
Затем мы просто создаем часы для обеих переменных. Повторим, эта функция вызывается каждый раз, когда происходит изменение mm
переменная, которая позволяет гарантировать, что отношения между mm
а также inches
поддерживается
$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' }}