AngularJs - директива по модификации форматирования ввода
Я хочу сделать следующее:
У меня есть объект даты в моей модели контроллера, и я хочу, чтобы пользователь мог его изменить.
Пользователю должны быть предоставлены два поля ввода.
Первое поле ввода должно изменить дату, а другое - время.
Оба поля ввода должны работать с той же моделью даты.
<input ng-model="model.date" date-format="YYYY-MM-DD">
<input ng-model="model.date" date-format="HH:mm:SS">
Я не нашел литературы об этой привязке.
Обычно директива ng-model заботится о значении поля ввода.
Теперь я хочу переписать это значение с помощью собственного форматирования.
Кроме того, если пользователь меняет ввод, изменения должны быть проанализированы и помещены обратно в объект даты.
Поскольку манипуляция с датами в vanilla js выглядит странно, я использовал moment.js для форматирования и анализа дат и строк.
Мой текущий подход выглядит следующим образом:
app.directive('dateFormat', function() {
return {
restrict: 'A',
link: function(scope, el, at) {
var format = at.dateFormat;
scope.$watch(at.ngModel, function(date) {
var result = moment(date).format(format);
el.val(result);
});
}
};
});
Однако это сломается, как только я хочу изменить входное значение в браузере.
Я получаю несколько NaN: NaN...
Мои вопросы:
- Как я могу моделировать это?
- Является ли этот подход действительным с философией angular или я делаю что-то странное здесь?
- Могу ли я использовать ng-model и мою директиву формата даты вместе?
- Есть ли более простой способ сделать это?
Ответы
Ответ 1
Фильтр - это то, что вы ищете:
//In your controller
$scope.modelDate = $filter('date')(dateToFormat, "YYYY-MM-DD");
//In your view
<input ng-model="modelDate" type="text">
При этом то, что вы пытаетесь сделать, не слишком "выключено", потому что всякий раз, когда пользователь записывает на вход, форматирование прерывается. Вам нужно использовать ngModel, который имеет специальный способ работы с директивами (API) и может быть просмотрен непосредственно в качестве четвертого аргумента в процессе компоновки.
Итак, для вашего кода это будет примерно так:
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModelController) {
ngModelController.$parsers.push(function(data) {
//View -> Model
return data;
});
ngModelController.$formatters.push(function(data) {
//Model -> View
return $filter('date')(data, "YYYY-MM-DD");
});
}
}
Дополнительная информация здесь
Ответ 2
У меня была та же проблема, и после некоторых исследований и тестирования я придумал следующее решение. Он выполняет требуемое форматирование и проверку на "размытие" не во время каждого нажатия клавиши. Посмотрите на теги комментариев для информации на каждом шаге. Для выполнения валидации дат вам понадобится moment.js.
myApp.directive('validDate', function ($filter, $window, $parse, $timeout) {
return {
require: '?ngModel',
restrict: 'A',
compile: function () {
var moment = $window.moment;
var getter, setter;
return function (scope, element, attrs, ngModel) {
//Declaring the getter and setter
getter = $parse(attrs.ngModel);
setter = getter.assign;
//Set the initial value to the View and the Model
ngModel.$formatters.unshift(function (modelValue) {
if (!modelValue) return "";
var retVal = $filter('date')(modelValue, "MM/dd/yyyy");
setter(scope, retVal);
console.log('Set initial View/Model value from: ' + modelValue + ' to ' + retVal);
return retVal;
});
// If the ngModel directive is used, then set the initial value and keep it in sync
if (ngModel) {
element.on('blur', function (event) {
var date = moment($filter('date')(element.val(), "MM/dd/yyyy"));
// if the date entered is a valid date then save the value
if (date && moment(element.val(), "MM/DD/YYYY").isValid() && date <= moment() && date >= moment("01/01/1900")) {
element.css('background', 'white');
element[0].value = $filter('date')(date.toDate(), "MM/dd/yyyy");
console.log('change value to ' + element.val());
var newValue = element.val();
scope.$apply(function () {
setter(scope, newValue);
});
} else { //show an error and clear the value
console.log('INCORRECT VALUE ENTERED');
element.css('background', 'pink');
element[0].value = "";
scope.$apply(function () {
setter(scope, '');
});
}
});
}
};
}
}; });
И директива может использоваться в представлении, как показано ниже:
<input type="text" ng-model="member.BirthDate" required valid-date />