There is very handly directive at to format date in ng-model with HTML input here.
angular.module('app', []).controller('Ctrl', function($scope){
$scope.firstDate = new Date();
$scope.secondDate = "2014-02-20";
}).directive('date', function (dateFilter) {
return {
require:'ngModel',
link:function (scope, elm, attrs, ctrl) {
var dateFormat = attrs['date'] || 'yyyy-MM-dd';
ctrl.$formatters.unshift(function (modelValue) {
return dateFilter(modelValue, dateFormat);
});
}
};
});
I tried to use same for my project,but the problem is that is fails to work when javascript file is minified. It logs an error [$injector:unpr] ...../$injector/unpr?p0=eProvider%20%3C-%20e%20%3C-%20dateDirective.
I tried to minify using this
Please guide me on how to minify this directive.
It happens because you don't use injection a.e $inject.
.controller('Ctrl', ['$scope',function($scope){/* ... */}]);
.directive('date', ['dateFilter', function (dateFilter) {/* ... */}]);
So your directive (and controller) will look like:
angular.module('app', []).controller('Ctrl', ['$scope',function($scope){
$scope.firstDate = new Date();
$scope.secondDate = "2014-02-20";
}]).directive('date', ['dateFilter', function (dateFilter) {
return {
require:'ngModel',
link:function (scope, elm, attrs, ctrl) {
var dateFormat = attrs['date'] || 'yyyy-MM-dd';
ctrl.$formatters.unshift(function (modelValue) {
return dateFilter(modelValue, dateFormat);
});
}
};
}]);
Related
I'm trying to convert a string date so that it works on a html input with the type set to 'date'.
So, I have the following angular app:
(function() {
var app = angular.module('test', []);
app.controller('MainCtrl', function($scope) {
$scope.load = function() {
$scope.message='2017-12-23T00:00:00Z';
};
});
app.directive('convertDate', function() {
return {
restrict: 'A',
scope: {
ngModel: '='
},
link: function (scope) {
console.log(scope);
console.log(scope.ngModel);
if (scope.ngModel) scope.ngModel = new Date(scope.ngModel);
}
};
});
})();
Then my html is as follows:
<div ng-controller='MainCtrl'>
<input type="date" convert-date ng-model="message">
<button ng-click="load()">load</button>
</div>
When I click on the load button I get the following error:
Error: [ngModel:datefmt] http://errors.angularjs.org/1.6.4/ngModel/datefmt?p0=2017-12-23T00%3A00%3A00Z
I understand the error is because it's a string and I need a date, which its the reason for my directive.
But even with the directive I still get the error.
What am I missing?
Thanks
Colin
You can change your directive to following:
angular.module('app').directive('convertDate', function() {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ctrl) {
if (!ctrl) return;
ctrl.$parsers.push(function(date) {
if (angular.isDate(date))
return new Date(date);
})
}
}
})
take a look at this working plunkr without error
https://plnkr.co/edit/8aSR1dlsRfDMrM7GfQQa?p=preview
It is because you are using same variable in ng-model for converting. So it encounters an error before your directive converts it.
According to me, you should convert it first and then assign to the ng-model variable in your controller.
Like this,
(function() {
var app = angular.module('test', []);
app.controller('MainCtrl', function($scope) {
$scope.load = function() {
var dateString = '2017-12-23T00:00:00Z';
$scope.message=new Date(dateString);
};
});
})();
No need to use directive
How do I use $broadcast to update custom validation in other directives which already have isolated scope?
I want to be able create separate validation rules used on a single input field.So in the future I can change the validation of a field by simply changing the directive reference.
Check the plunkr
edit: I am using angular 1.2.8
The element the directive is on has isolated scope.
Validation Directive 1
(function () {
'use strict';
angular
.module('app')
.directive('dateOneValidation', dateOneValidation);
function dateOneValidation() {
var directive = {
require: 'ngModel', // note: this has to stay
restrict: 'A',
link: link
};
return directive;
function link(scope, element, attrs, ctrl) {
scope.$on('updateDateOneValidation', function(e, date){
ctrl.$parsers.unshift(function (viewValue) {
var form = scope.form;
var dateOne = moment(form.dateOne.$viewValue, "DD/MM/YYYY", true);
var today = moment();
var dateOneBeforeOrOnToday = dateOne.isSame(today, 'day') || dateOne.isBefore(today, 'day');
dateOneBeforeOrOnToday ? form.dateOne.$setValidity('dateOneBeforeOrOnToday', true):
form.dateOne.$setValidity('dateOneBeforeOrOnToday', false);
return viewValue
});
});
}
}
})();
Validation Directive 2
(function () {
'use strict';
angular
.module('app')
.directive('dateTwoValidation', dateTwoValidation);
function dateTwoValidation() {
var directive = {
require: 'ngModel', // note: this has to stay
restrict: 'A',
link: link
};
return directive;
function link(scope, element, attrs, ctrl) {
scope.$on('updateDateTwoValidation', function(e, date){
ctrl.$parsers.unshift(function (viewValue) {
var form = scope.form;
var dateOne = moment(form.dateOne.$viewValue, "DD/MM/YYYY", true);
var dateTwo = moment(viewValue, "DD/MM/YYYY", true);
var dateTwoAfterDateOne = dateTwo.isSame(dateOne, 'day') || dateTwo.isAfter(dateOne, 'day');
dateTwoAfterDateOne ? form.dateTwo.$setValidity('dateTwoAfterDateOne', true):
form.dateTwo.$setValidity('dateTwoAfterDateOne', false);
return viewValue
});
});
}
}
})();
(function () {
'use strict';
angular
.module('app')
.directive('stepOne', stepOne);
function stepOne() {
parentController.$inject = ['$scope'];
function parentController($scope) {
var vm = this;
vm.dateOne = '01/01/2000'
vm.dateTwo = '01/01/1900'
vm.validateStepOne = validateStepOne;
function validateStepOne() {
$scope.$broadcast('updateDateOneValidation');
$scope.$broadcast('updateDateTwoValidation');
}
}
var directive = {
restrict: 'EA',
require: '^form',
templateUrl: 'src/app/form/step1.html',
scope: {
},
controller: parentController,
controllerAs: 'vm'
};
return directive;
}
})();
(function () {
'use strict';
angular
.module('app')
.directive('dateOneValidation', dateOneValidation);
function dateOneValidation() {
var directive = {
require: 'ngModel', // note: this has to stay
restrict: 'A',
link: link
};
return directive;
function link(scope, element, attrs, ctrl) {
var form = scope.form;
var today = moment();
scope.$watch(attrs.ngModel, function () {
validator()
});
scope.$on('updateDateOneValidation', function () {
validator();
});
function validator() {
var dateOne = moment(form.dateOne.$viewValue, "DD/MM/YYYY", true);
var dateOneBeforeOrOnToday = dateOne.isSame(today, 'day') || dateOne.isBefore(today, 'day');
dateOneBeforeOrOnToday ? form.dateOne.$setValidity('dateOneBeforeOrOnToday', true) :
form.dateOne.$setValidity('dateOneBeforeOrOnToday', false);
}
}
}
})();
(function () {
'use strict';
angular
.module('app')
.directive('dateTwoValidation', dateTwoValidation);
function dateTwoValidation() {
var directive = {
require: 'ngModel', // note: this has to stay
restrict: 'A',
link: link
};
return directive;
function link(scope, element, attrs, ctrl) {
var form = scope.form;
scope.$watch(attrs.ngModel, function () {
validator();
});
scope.$on('updateDateTwoValidation', function (e, date) {
validator();
});
function validator() {
var dateOne = moment(form.dateOne.$viewValue, "DD/MM/YYYY", true);
var dateTwo = moment(form.dateTwo.$viewValue, "DD/MM/YYYY", true);
var dateTwoAfterDateOne = dateTwo.isSame(dateOne, 'day') || dateTwo.isAfter(dateOne, 'day');
dateTwoAfterDateOne ? form.dateTwo.$setValidity('dateTwoAfterDateOne', true) :
form.dateTwo.$setValidity('dateTwoAfterDateOne', false);
};
};
}
})()
Alternatively You can use a higher shared scope with a form object and pass it to your directives. Something like the following:
topLevelScope - ngForm
directive1(topLevelScope.ngForm)
topLevelScope.ngForm.$setValidity('input1', true)
directive2(topLevelScope.ngForm)
topLevelScope.ngForm.$setValidity('input2', true)
directive3(topLevelScope.ngForm)
topLevelScope.ngForm.$setValidity('input3', true)
My 2 cents.
I am newer in angularjs. I am just trying to update the input txt value using custom Directive. But i cant. Here i have showed my code What i did wrong this code. Some one help me and explain how it is working.
var myApp = angular.module('myApp',[]);
//myApp.directive('myDirective', function() {});
//myApp.factory('myService', function() {});
myApp.controller('MyCtrl',MyCtrl);
function MyCtrl($scope) {
$scope.name = 'Superhero';
$scope.myTime = '10:59';
}
myApp.directive('myDirective', function () {
return {
restrict: 'A',
require: '?ngModel',
link: function (scope, element, attrs, ngModel) {
scope.$watch(attrs.ngModel, function (v) {
console.log('value changed, new value is: ' + v);
ngModel.$setViewValue('11')
//scope.ngModel = '11'
});
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-controller="MyCtrl">
Hello, {{name}}!
<input type="text" my-directive ng-model="myTime" name="customTime">
</div>
You should register your MyCtrl controller in your myApp module like below.
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl',MyCtrl);
function MyCtrl($scope) {
$scope.name = 'Superhero';
$scope.myTime = '10:59';
}
If you need to update the text field value to some desired value, once you're done with the update in the watcher using $setViewValue(), you need to call $render() as well on NgModelController.
link: function (scope, element, attrs, ngModel) {
scope.$watch(attrs.ngModel, function (v) {
console.log('value changed, new value is: ' + v);
ngModel.$setViewValue('11');
ngModel.$render();
});
}
Here's a Pen to check this change.
Html code:
<div class="test">{{name}}</div>
Angular code:
var app = angular.module('angularjs-starter', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
});
app.directive('test', function(){
return {
restrict: 'C',
link: function(scope, elm, attrs){
var content = elm.html();
alert(content);
}
}
});
It will alert a string {{name}}. How to alert the rendered string World?
Live demo: http://plnkr.co/edit/Mov0AlkdE9B8yKiBjpnp?p=preview
You need to use $interpolate service to do this
app.directive('test', function($interpolate){
return {
restrict: 'C',
link: function(scope, elm, attrs){
var content = elm.html();
alert($interpolate(content)(scope))
}
}
});
Demo: Fiddle
I've defined a directive like so:
angular.module('MyModule', [])
.directive('datePicker', function($filter) {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ctrl) {
ctrl.$formatters.unshift(function(modelValue) {
console.log('formatting',modelValue,scope,elem,attrs,ctrl);
return $filter('date')(modelValue, 'MM/dd/yyyy');
});
ctrl.$parsers.unshift(function(viewValue) {
console.log('parsing',viewValue);
var date = new Date(viewValue);
return isNaN(date) ? '' : date;
});
}
}
});
Which I apply to an element like so:
<input type="text" date-picker="MM/dd/yyyy" ng-model="clientForm.birthDate" />
My directive gets triggered whenever I add the date-picker attribute to an element, but I want to know how to access the attribute's value (MM/dd/yyyy) inside my directive JS so that I can remove that constant beside $filter. I'm not sure if any of the variables I have access to provide this.
Just pull it directly from the attrs:
return $filter('date')(modelValue, attrs.datePicker);
BTW, if the only filter you're using is date, then you can inject that directly:
.directive('datePicker', function (dateFilter) {
// Keep all your code, just update this line:
return dateFilter(modelValue, attrs.datePicker || 'MM/dd/yyyy');
// etc.
}
You can access it from attrs argument of link function.
Demo: http://plnkr.co/edit/DBs4jX9alyCZXt3LaLnF?p=preview
angModule.directive('moDateInput', function ($window) {
return {
require:'^ngModel',
restrict:'A',
link:function (scope, elm, attrs, ctrl) {
var moment = $window.moment;
var dateFormat = attrs.moMediumDate;
attrs.$observe('moDateInput', function (newValue) {
if (dateFormat == newValue || !ctrl.$modelValue) return;
dateFormat = newValue;
ctrl.$modelValue = new Date(ctrl.$setViewValue);
});
ctrl.$formatters.unshift(function (modelValue) {
scope = scope;
if (!dateFormat || !modelValue) return "";
var retVal = moment(modelValue).format(dateFormat);
return retVal;
});
ctrl.$parsers.unshift(function (viewValue) {
scope = scope;
var date = moment(viewValue, dateFormat);
return (date && date.isValid() && date.year() > 1950 ) ? date.toDate() : "";
});
}
};
});