I have an form input which is for a MySQL date field. Ex: 2015-01-31
.
I want to allow the user to input this using 3 different form inputs. One for the year, one for the month, and one for the day.
Obviously ng-model isn't going to work right out of the box, because I'm trying to bind just one part of the date string to each input. I'm pretty sure the way to do it is bye creating three "temporary" scope vars/models
$scope.year;
$scope.month;
$scope.day;
...and then somehow combine/binding them to the actual value.
//If only it were this easy!
$scope.date = $scope.year + "-" + $scope.month + "-" + $scope.day;
The line above of course won't work because the values aren't two-way-bound. If the form were only for saving new data, I could could get away with that by just combining the inputs on submit. But I need it to handle/show existing data also. And it's going to get super ugly if I can't figure out a way to wrangle Angular's binding magic to do what I want.
I found this question which I think is trying to do the same thing, but they solve it with a custom directive, which is something I'm hoping to avoid. I know this may be a more maintainable/portable/modular way to do it, but I'm new to Angular and a bit intimidated by that. Also, the inputs are using the lovely angular-selectize directive, which adds an additional layer of complexity to that approach.
A directive is probably best, but these examples look overly complex. Anyway if you are hoping to avoid a directive, just use $scope.$watch
and re-build your date string each time one of the important variables are updated.
Something like this might be in your controller:
$scope.year = '';
$scope.month = '';
$scope.day = '';
// this might be able to be refactored
$scope.$watch('year', buildDate);
$scope.$watch('month', buildDate);
$scope.$watch('day', buildDate);
function buildDate() {
$scope.date = $scope.year + "-" + $scope.month + "-" + $scope.day;
}
As a side note, this is probably what my directive logic would look like too.
Edit: Code cleanup and fiddle
Cleaner example - I prefer this because it groups all the date-related items with an object, which also makes watching for changes easier.
$scope.date = {
year: '',
month: '',
day: ''
};
// use watch collection to watch properties on the main 'date' object
$scope.$watchCollection('date', buildDate);
function buildDate(date) {
$scope.dateString = date.year + "-" + date.month + "-" + date.day;
}
Fiddle
here's an interesting demo that uses custom directives that are a lot less intimidating than the ones you linked to. You should be able to apply them to your inputs without too much conflict with other stuff:
http://plnkr.co/edit/3a8xnCfJFJrBlDRTUBG7?p=preview
The trick is setting the parser and formatter for a model using the directive. This lets you intercept changes to the model and interact with the rest of your scope:
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.date = new Date();
});
app.directive('datePartInput', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, elem, attrs, ngModel) {
var part = attrs.part;
var modelToUser, userToModel
console.log('part:', part);
if (part == 'year') {
modelToUser = function(date) {
return date.getFullYear();
}
userToModel = function(year) {
ngModel.$modelValue.setYear(year);
return ngModel.$modelValue
}
}
else if (part == 'month') {
modelToUser = function(date) {
return date.getMonth();
}
userToModel = function(month) {
ngModel.$modelValue.setMonth(month);
return ngModel.$modelValue;
}
}
else if (part == 'day') {
modelToUser = function(date) {
return date.getUTCDate();
};
userToModel = function(day) {
ngModel.$modelValue.setUTCDate(day);
return ngModel.$modelValue;
};
}
ngModel.$formatters.push(modelToUser);
ngModel.$parsers.push(userToModel);
}
}
})
And the template:
<body ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
{{date | date}}
<input date-part-input part="year" ng-model="date">
<input date-part-input part="month" ng-model="date">
<input date-part-input part="day" ng-model="date">
</body>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With