From eea25d091d7eb319d6ec1de8b793881d3a10949b Mon Sep 17 00:00:00 2001
From: Sean Perkins
Date: Tue, 5 Apr 2022 12:44:45 -0400
Subject: [PATCH] fix(angular): item styling when control has value (#24932)
Resolves #23809
---
.../control-value-accessors/value-accessor.ts | 21 ++++++++-------
angular/test/test-app/e2e/src/modal.spec.ts | 27 ++++++++++++++++++-
.../modal-example.component.html | 10 +++++++
.../modal-example/modal-example.component.ts | 5 ++++
4 files changed, 52 insertions(+), 11 deletions(-)
diff --git a/angular/src/directives/control-value-accessors/value-accessor.ts b/angular/src/directives/control-value-accessors/value-accessor.ts
index daa4a72685..615d736828 100644
--- a/angular/src/directives/control-value-accessors/value-accessor.ts
+++ b/angular/src/directives/control-value-accessors/value-accessor.ts
@@ -110,13 +110,17 @@ export class ValueAccessor implements ControlValueAccessor, AfterViewInit, OnDes
export const setIonicClasses = (element: ElementRef): void => {
raf(() => {
- const input = element.nativeElement as HTMLElement;
+ const input = element.nativeElement as HTMLInputElement;
+ const hasValue = input.value != null && input.value.toString().length > 0;
const classes = getClasses(input);
setClasses(input, classes);
-
const item = input.closest('ion-item');
if (item) {
- setClasses(item, classes);
+ if (hasValue) {
+ setClasses(item, [...classes, 'item-has-value']);
+ } else {
+ setClasses(item, classes);
+ }
}
});
};
@@ -127,7 +131,7 @@ const getClasses = (element: HTMLElement) => {
for (let i = 0; i < classList.length; i++) {
const item = classList.item(i);
if (item !== null && startsWith(item, 'ng-')) {
- classes.push(`ion-${item.substr(3)}`);
+ classes.push(`ion-${item.substring(3)}`);
}
}
return classes;
@@ -135,13 +139,10 @@ const getClasses = (element: HTMLElement) => {
const setClasses = (element: HTMLElement, classes: string[]) => {
const classList = element.classList;
- ['ion-valid', 'ion-invalid', 'ion-touched', 'ion-untouched', 'ion-dirty', 'ion-pristine'].forEach((c) =>
- classList.remove(c)
- );
-
- classes.forEach((c) => classList.add(c));
+ classList.remove('ion-valid', 'ion-invalid', 'ion-touched', 'ion-untouched', 'ion-dirty', 'ion-pristine');
+ classList.add(...classes);
};
const startsWith = (input: string, search: string): boolean => {
- return input.substr(0, search.length) === search;
+ return input.substring(0, search.length) === search;
};
diff --git a/angular/test/test-app/e2e/src/modal.spec.ts b/angular/test/test-app/e2e/src/modal.spec.ts
index b2854cc05c..cb937fcca6 100644
--- a/angular/test/test-app/e2e/src/modal.spec.ts
+++ b/angular/test/test-app/e2e/src/modal.spec.ts
@@ -43,7 +43,6 @@ describe('Modals', () => {
});
-
describe('Modals: Inline', () => {
beforeEach(() => {
cy.visit('/modal-inline');
@@ -77,3 +76,29 @@ describe('Modals: Inline', () => {
cy.get('ion-modal').children('.ion-page').should('not.exist');
})
});
+
+describe('when in a modal', () => {
+
+ beforeEach(() => {
+ cy.visit('/modals');
+ cy.get('#action-button').click();
+ cy.get('#close-modal').click();
+ cy.get('#action-button').click();
+ });
+
+ it('should render ion-item item-has-value class when control value is set', () => {
+ cy.get('[formControlName="select"]').invoke('attr', 'value', 0);
+ cy.get('#inputWithFloatingLabel').should('have.class', 'item-has-value');
+ });
+
+ it('should not render ion-item item-has-value class when control value is undefined', () => {
+ cy.get('[formControlName="select"]').invoke('attr', 'value', undefined);
+ cy.get('#inputWithFloatingLabel').should('not.have.class', 'item-has-value');
+ });
+
+ it('should not render ion-item item-has-value class when control value is null', () => {
+ cy.get('[formControlName="select"]').invoke('attr', 'value', null);
+ cy.get('#inputWithFloatingLabel').should('not.have.class', 'item-has-value');
+ });
+
+});
diff --git a/angular/test/test-app/src/app/modal-example/modal-example.component.html b/angular/test/test-app/src/app/modal-example/modal-example.component.html
index 6562262ede..513f7ad889 100644
--- a/angular/test/test-app/src/app/modal-example/modal-example.component.html
+++ b/angular/test/test-app/src/app/modal-example/modal-example.component.html
@@ -22,4 +22,14 @@
Push page
Pop page
+
+
diff --git a/angular/test/test-app/src/app/modal-example/modal-example.component.ts b/angular/test/test-app/src/app/modal-example/modal-example.component.ts
index 363e0db61e..a9640244c8 100644
--- a/angular/test/test-app/src/app/modal-example/modal-example.component.ts
+++ b/angular/test/test-app/src/app/modal-example/modal-example.component.ts
@@ -1,4 +1,5 @@
import { Component, Input, NgZone, OnInit, Optional } from '@angular/core';
+import { FormControl, FormGroup } from '@angular/forms';
import { ModalController, NavParams, IonNav, ViewWillLeave, ViewDidEnter, ViewDidLeave } from '@ionic/angular';
@Component({
@@ -9,6 +10,10 @@ export class ModalExampleComponent implements OnInit, ViewWillLeave, ViewDidEnte
@Input() value: string;
+ form = new FormGroup({
+ select: new FormControl([])
+ });
+
valueFromParams: string;
onInit = 0;
willEnter = 0;