From 0bede63d33127d5a9ac0370307486ff50e492e9d Mon Sep 17 00:00:00 2001
From: Dmytro Prokhorov <diprokon@gmail.com>
Date: Thu, 5 May 2022 23:31:33 +0300
Subject: [PATCH] fix(material/datepicker): add ability to have numeric zero
 value in input (#24813)

* fix(material/datepicker): add ability to have numeric zero value in input

Shows valid formatted value for 'falsy' values (exp 0)
Custom DateAdapter (exp TimestampDateAdapter) can have valid numeric 0 value (for timestamp it is 1/1/1970), but datepicker input doesn't show formatted value

* fix(material/datepicker): add ability to have numeric zero value in input

Add tests

(cherry picked from commit 5f4d7e2ee70c4451ce3eaf6f6905db7d17d3a7ce)
---
 .../datepicker/datepicker-input-base.ts       |  5 ++--
 .../datepicker-input-harness-shared.spec.ts   | 27 ++++++++++++++++++-
 2 files changed, 28 insertions(+), 4 deletions(-)

diff --git a/src/material/datepicker/datepicker-input-base.ts b/src/material/datepicker/datepicker-input-base.ts
index e8065b7b1e71..ff4f8b910ad2 100644
--- a/src/material/datepicker/datepicker-input-base.ts
+++ b/src/material/datepicker/datepicker-input-base.ts
@@ -344,9 +344,8 @@ export abstract class MatDatepickerInputBase<S, D = ExtractDateTypeFromSelection
 
   /** Formats a value and sets it on the input element. */
   protected _formatValue(value: D | null) {
-    this._elementRef.nativeElement.value = value
-      ? this._dateAdapter.format(value, this._dateFormats.display.dateInput)
-      : '';
+    this._elementRef.nativeElement.value =
+      value != null ? this._dateAdapter.format(value, this._dateFormats.display.dateInput) : '';
   }
 
   /** Assigns a value to the model. */
diff --git a/src/material/datepicker/testing/datepicker-input-harness-shared.spec.ts b/src/material/datepicker/testing/datepicker-input-harness-shared.spec.ts
index 4105cdd525c2..0513cb32cb34 100644
--- a/src/material/datepicker/testing/datepicker-input-harness-shared.spec.ts
+++ b/src/material/datepicker/testing/datepicker-input-harness-shared.spec.ts
@@ -1,7 +1,7 @@
 import {HarnessLoader, parallel} from '@angular/cdk/testing';
 import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed';
 import {Component} from '@angular/core';
-import {MatNativeDateModule} from '@angular/material/core';
+import {DateAdapter, MatNativeDateModule} from '@angular/material/core';
 import {ComponentFixture, TestBed} from '@angular/core/testing';
 import {FormsModule} from '@angular/forms';
 import {MatDatepickerModule} from '@angular/material/datepicker';
@@ -86,6 +86,31 @@ export function runDatepickerInputHarnessTests(
     expect(await input.getValue()).toBe('1/1/2020');
   });
 
+  it('should set the input value based on date adapter validation and formatting', async () => {
+    const adapter = fixture.debugElement.injector.get(DateAdapter);
+    const input = await loader.getHarness(datepickerInputHarness.with({selector: '#basic'}));
+    const validValues: any[] = [new Date(0), '', 0, false];
+    const invalidValues: any[] = [null, undefined];
+    spyOn(adapter, 'format').and.returnValue('FORMATTED_VALUE');
+    spyOn(adapter, 'isValid').and.callFake(value => validValues.includes(value));
+    spyOn(adapter, 'deserialize').and.callFake(value =>
+      validValues.includes(value) ? value : null,
+    );
+    spyOn(adapter, 'getValidDateOrNull').and.callFake(value =>
+      adapter.isValid(value) ? value : null,
+    );
+
+    for (let value of validValues) {
+      fixture.componentInstance.date = value;
+      expect(await input.getValue()).toBe('FORMATTED_VALUE');
+    }
+
+    for (let value of invalidValues) {
+      fixture.componentInstance.date = value;
+      expect(await input.getValue()).toBe('');
+    }
+  });
+
   it('should get the input placeholder', async () => {
     const inputs = await loader.getAllHarnesses(datepickerInputHarness);
     expect(