Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 83f7980

Browse files
authored
feat(ngModelOptions): add timeStripZeroSeconds and timeSecondsFormat
Closes #10721 Closes #16510 Closes #16584
1 parent c9a92fc commit 83f7980

File tree

3 files changed

+286
-13
lines changed

3 files changed

+286
-13
lines changed

src/ng/directive/input.js

+33-2
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,10 @@ var inputType = {
255255
* The timezone to be used to read/write the `Date` instance in the model can be defined using
256256
* {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
257257
*
258+
* The format of the displayed time can be adjusted with the
259+
* {@link ng.directive:ngModelOptions#ngModelOptions-arguments ngModelOptions} `timeSecondsFormat`
260+
* and `timeStripZeroSeconds`.
261+
*
258262
* @param {string} ngModel Assignable AngularJS expression to data-bind to.
259263
* @param {string=} name Property name of the form under which the control is published.
260264
* @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
@@ -356,7 +360,12 @@ var inputType = {
356360
* Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
357361
*
358362
* The timezone to be used to read/write the `Date` instance in the model can be defined using
359-
* {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
363+
* {@link ng.directive:ngModelOptions#ngModelOptions-arguments ngModelOptions}. By default,
364+
* this is the timezone of the browser.
365+
*
366+
* The format of the displayed time can be adjusted with the
367+
* {@link ng.directive:ngModelOptions#ngModelOptions-arguments ngModelOptions} `timeSecondsFormat`
368+
* and `timeStripZeroSeconds`.
360369
*
361370
* @param {string} ngModel Assignable AngularJS expression to data-bind to.
362371
* @param {string=} name Property name of the form under which the control is published.
@@ -1491,6 +1500,8 @@ function createDateInputType(type, regexp, parseDate, format) {
14911500
return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) {
14921501
badInputChecker(scope, element, attr, ctrl, type);
14931502
baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
1503+
1504+
var isTimeType = type === 'time' || type === 'datetimelocal';
14941505
var previousDate;
14951506
var previousTimezone;
14961507

@@ -1514,11 +1525,13 @@ function createDateInputType(type, regexp, parseDate, format) {
15141525
if (isValidDate(value)) {
15151526
previousDate = value;
15161527
var timezone = ctrl.$options.getOption('timezone');
1528+
15171529
if (timezone) {
15181530
previousTimezone = timezone;
15191531
previousDate = convertTimezoneToLocal(previousDate, timezone, true);
15201532
}
1521-
return $filter('date')(value, format, timezone);
1533+
1534+
return formatter(value, timezone);
15221535
} else {
15231536
previousDate = null;
15241537
previousTimezone = null;
@@ -1573,6 +1586,24 @@ function createDateInputType(type, regexp, parseDate, format) {
15731586
}
15741587
return parsedDate;
15751588
}
1589+
1590+
function formatter(value, timezone) {
1591+
var targetFormat = format;
1592+
1593+
if (isTimeType && isString(ctrl.$options.getOption('timeSecondsFormat'))) {
1594+
targetFormat = format
1595+
.replace('ss.sss', ctrl.$options.getOption('timeSecondsFormat'))
1596+
.replace(/:$/, '');
1597+
}
1598+
1599+
var formatted = $filter('date')(value, targetFormat, timezone);
1600+
1601+
if (isTimeType && ctrl.$options.getOption('timeStripZeroSeconds')) {
1602+
formatted = formatted.replace(/(?::00)?(?:\.000)?$/, '');
1603+
}
1604+
1605+
return formatted;
1606+
}
15761607
};
15771608
}
15781609

src/ng/directive/ngModelOptions.js

+85-7
Original file line numberDiff line numberDiff line change
@@ -406,12 +406,6 @@ defaultModelOptions = new ModelOptions({
406406
* </example>
407407
*
408408
*
409-
* ## Specifying timezones
410-
*
411-
* You can specify the timezone that date/time input directives expect by providing its name in the
412-
* `timezone` property.
413-
*
414-
*
415409
* ## Programmatically changing options
416410
*
417411
* The `ngModelOptions` expression is only evaluated once when the directive is linked; it is not
@@ -423,8 +417,70 @@ defaultModelOptions = new ModelOptions({
423417
* Default events, extra triggers, and catch-all debounce values}.
424418
*
425419
*
420+
* ## Specifying timezones
421+
*
422+
* You can specify the timezone that date/time input directives expect by providing its name in the
423+
* `timezone` property.
424+
*
425+
*
426+
* ## Formatting the value of `time` and `datetime-local`
427+
*
428+
* With the options `timeSecondsFormat` and `timeStripZeroSeconds` it is possible to adjust the value
429+
* that is displayed in the control. Note that browsers may apply their own formatting
430+
* in the user interface.
431+
*
432+
<example name="ngModelOptions-time-format" module="timeExample">
433+
<file name="index.html">
434+
<time-example></time-example>
435+
</file>
436+
<file name="script.js">
437+
angular.module('timeExample', [])
438+
.component('timeExample', {
439+
templateUrl: 'timeExample.html',
440+
controller: function() {
441+
this.time = new Date(1970, 0, 1, 14, 57, 0);
442+
443+
this.options = {
444+
timeSecondsFormat: 'ss',
445+
timeStripZeroSeconds: true
446+
};
447+
448+
this.optionChange = function() {
449+
this.timeForm.timeFormatted.$overrideModelOptions(this.options);
450+
this.time = new Date(this.time);
451+
};
452+
}
453+
});
454+
</file>
455+
<file name="timeExample.html">
456+
<form name="$ctrl.timeForm">
457+
<strong>Default</strong>:
458+
<input type="time" ng-model="$ctrl.time" step="any" /><br>
459+
<strong>With options</strong>:
460+
<input type="time" name="timeFormatted" ng-model="$ctrl.time" step="any" ng-model-options="$ctrl.options" />
461+
<br>
462+
463+
Options:<br>
464+
<code>timeSecondsFormat</code>:
465+
<input
466+
type="text"
467+
ng-model="$ctrl.options.timeSecondsFormat"
468+
ng-change="$ctrl.optionChange()">
469+
<br>
470+
<code>timeStripZeroSeconds</code>:
471+
<input
472+
type="checkbox"
473+
ng-model="$ctrl.options.timeStripZeroSeconds"
474+
ng-change="$ctrl.optionChange()">
475+
</form>
476+
</file>
477+
* </example>
478+
*
426479
* @param {Object} ngModelOptions options to apply to {@link ngModel} directives on this element and
427-
* and its descendents. Valid keys are:
480+
* and its descendents.
481+
*
482+
* **General options**:
483+
*
428484
* - `updateOn`: string specifying which event should the input be bound to. You can set several
429485
* events using an space delimited list. There is a special event called `default` that
430486
* matches the default events belonging to the control. These are the events that are bound to
@@ -457,6 +513,10 @@ defaultModelOptions = new ModelOptions({
457513
* not validate correctly instead of the default behavior of setting the model to undefined.
458514
* - `getterSetter`: boolean value which determines whether or not to treat functions bound to
459515
* `ngModel` as getters/setters.
516+
*
517+
*
518+
* **Input-type specific options**:
519+
*
460520
* - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for
461521
* `<input type="date" />`, `<input type="time" />`, ... . It understands UTC/GMT and the
462522
* continental US time zone abbreviations, but for general use, use a time zone offset, for
@@ -465,6 +525,24 @@ defaultModelOptions = new ModelOptions({
465525
* Note that changing the timezone will have no effect on the current date, and is only applied after
466526
* the next input / model change.
467527
*
528+
* - `timeSecondsFormat`: Defines if the `time` and `datetime-local` types should show seconds and
529+
* milliseconds. The option follows the format string of {@link date date filter}.
530+
* By default, the options is `undefined` which is equal to `'ss.sss'` (seconds and milliseconds).
531+
* The other options are `'ss'` (strips milliseconds), and `''` (empty string), which strips both
532+
* seconds and milliseconds.
533+
* Note that browsers that support `time` and `datetime-local` require the hour and minutes
534+
* part of the time string, and may show the value differently in the user interface.
535+
* {@link ngModelOptions#formatting-the-value-of-time-and-datetime-local- See the example}.
536+
*
537+
* - `timeStripZeroSeconds`: Defines if the `time` and `datetime-local` types should strip the
538+
* seconds and milliseconds from the formatted value if they are zero. This option is applied
539+
* after `timeSecondsFormat`.
540+
* This option can be used to make the formatting consistent over different browsers, as some
541+
* browsers with support for `time` will natively hide the milliseconds and
542+
* seconds if they are zero, but others won't, and browsers that don't implement these input
543+
* types will always show the full string.
544+
* {@link ngModelOptions#formatting-the-value-of-time-and-datetime-local- See the example}.
545+
*
468546
*/
469547
var ngModelOptionsDirective = function() {
470548
NgModelOptionsController.$inject = ['$attrs', '$scope'];

0 commit comments

Comments
 (0)