mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-26 08:13:34 +08:00
feat(searchbar): ionChange will only emit from user committed changes (#26026)
This commit is contained in:
@ -4,8 +4,7 @@ import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { ValueAccessor } from './value-accessor';
|
||||
|
||||
@Directive({
|
||||
/* tslint:disable-next-line:directive-selector */
|
||||
selector: 'ion-searchbar',
|
||||
selector: 'ion-input:not([type=number]),ion-textarea,ion-searchbar',
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
@ -19,28 +18,6 @@ export class TextValueAccessorDirective extends ValueAccessor {
|
||||
super(injector, el);
|
||||
}
|
||||
|
||||
@HostListener('ionChange', ['$event.target'])
|
||||
_handleInputEvent(el: any): void {
|
||||
this.handleValueChange(el, el.value);
|
||||
}
|
||||
}
|
||||
|
||||
@Directive({
|
||||
selector: 'ion-input:not([type=number]),ion-textarea',
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: InputValueAccessorDirective,
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
})
|
||||
// TODO rename this value accessor to `TextValueAccessorDirective` when search-bar is updated
|
||||
export class InputValueAccessorDirective extends ValueAccessor {
|
||||
constructor(injector: Injector, el: ElementRef) {
|
||||
super(injector, el);
|
||||
}
|
||||
|
||||
@HostListener('ionInput', ['$event.target'])
|
||||
_handleInputEvent(el: any): void {
|
||||
this.handleValueChange(el, el.value);
|
||||
|
@ -1518,11 +1518,17 @@ export class IonRow {
|
||||
import type { SearchbarChangeEventDetail as ISearchbarSearchbarChangeEventDetail } from '@ionic/core';
|
||||
export declare interface IonSearchbar extends Components.IonSearchbar {
|
||||
/**
|
||||
* Emitted when a keyboard input occurred.
|
||||
* Emitted when the `value` of the `ion-searchbar` element has changed.
|
||||
*/
|
||||
ionInput: EventEmitter<CustomEvent<KeyboardEvent>>;
|
||||
ionInput: EventEmitter<CustomEvent<KeyboardEvent | null>>;
|
||||
/**
|
||||
* Emitted when the value has changed.
|
||||
* The `ionChange` event is fired for `<ion-searchbar>` elements when the user
|
||||
modifies the element's value. Unlike the `ionInput` event, the `ionChange`
|
||||
event is not necessarily fired for each alteration to an element's value.
|
||||
|
||||
The `ionChange` event is fired when the element loses focus after its value
|
||||
has been modified. This includes modifications made when clicking the clear
|
||||
or cancel buttons.
|
||||
*/
|
||||
ionChange: EventEmitter<CustomEvent<ISearchbarSearchbarChangeEventDetail>>;
|
||||
/**
|
||||
|
@ -3,10 +3,7 @@ export { BooleanValueAccessorDirective as BooleanValueAccessor } from './directi
|
||||
export { NumericValueAccessorDirective as NumericValueAccessor } from './directives/control-value-accessors/numeric-value-accessor';
|
||||
export { RadioValueAccessorDirective as RadioValueAccessor } from './directives/control-value-accessors/radio-value-accessor';
|
||||
export { SelectValueAccessorDirective as SelectValueAccessor } from './directives/control-value-accessors/select-value-accessor';
|
||||
export {
|
||||
TextValueAccessorDirective as TextValueAccessor,
|
||||
InputValueAccessorDirective as InputValueAccessor,
|
||||
} from './directives/control-value-accessors/text-value-accessor';
|
||||
export { TextValueAccessorDirective as TextValueAccessor } from './directives/control-value-accessors/text-value-accessor';
|
||||
export { IonTabs } from './directives/navigation/ion-tabs';
|
||||
export { IonBackButtonDelegateDirective as IonBackButtonDelegate } from './directives/navigation/ion-back-button';
|
||||
export { NavDelegate } from './directives/navigation/nav-delegate';
|
||||
|
@ -9,7 +9,6 @@ import {
|
||||
RadioValueAccessorDirective,
|
||||
SelectValueAccessorDirective,
|
||||
TextValueAccessorDirective,
|
||||
InputValueAccessorDirective,
|
||||
} from './directives/control-value-accessors';
|
||||
import { IonBackButtonDelegateDirective } from './directives/navigation/ion-back-button';
|
||||
import { IonRouterOutlet } from './directives/navigation/ion-router-outlet';
|
||||
@ -41,7 +40,6 @@ const DECLARATIONS = [
|
||||
RadioValueAccessorDirective,
|
||||
SelectValueAccessorDirective,
|
||||
TextValueAccessorDirective,
|
||||
InputValueAccessorDirective,
|
||||
|
||||
// navigation
|
||||
IonTabs,
|
||||
|
18
angular/test/base/e2e/src/searchbar.spec.ts
Normal file
18
angular/test/base/e2e/src/searchbar.spec.ts
Normal file
@ -0,0 +1,18 @@
|
||||
describe('Searchbar', () => {
|
||||
beforeEach(() => cy.visit('/searchbar'));
|
||||
|
||||
it('should become valid', () => {
|
||||
cy.get('#status').should('have.text', 'INVALID');
|
||||
|
||||
cy.get('ion-searchbar').type('hello');
|
||||
|
||||
cy.get('#status').should('have.text', 'VALID');
|
||||
});
|
||||
|
||||
it('should update the form control value when typing', () => {
|
||||
cy.get('#value').contains(`"searchbar": ""`);
|
||||
cy.get('ion-searchbar').type('hello');
|
||||
|
||||
cy.get('#value').contains(`"searchbar": "hello"`);
|
||||
});
|
||||
});
|
@ -26,6 +26,7 @@ const routes: Routes = [
|
||||
{ path: 'alerts', component: AlertComponent },
|
||||
{ path: 'inputs', component: InputsComponent },
|
||||
{ path: 'textarea', loadChildren: () => import('./textarea/textarea.module').then(m => m.TextareaModule) },
|
||||
{ path: 'searchbar', loadChildren: () => import('./searchbar/searchbar.module').then(m => m.SearchbarModule) },
|
||||
{ path: 'form', component: FormComponent },
|
||||
{ path: 'modals', component: ModalComponent },
|
||||
{ path: 'modal-inline', loadChildren: () => import('./modal-inline').then(m => m.ModalInlineModule) },
|
||||
|
@ -0,0 +1,16 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
import { RouterModule } from "@angular/router";
|
||||
import { SearchbarComponent } from "./searchbar.component";
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forChild([
|
||||
{
|
||||
path: '',
|
||||
component: SearchbarComponent
|
||||
}
|
||||
])
|
||||
],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class SearchbarRoutingModule { }
|
16
angular/test/base/src/app/searchbar/searchbar.component.html
Normal file
16
angular/test/base/src/app/searchbar/searchbar.component.html
Normal file
@ -0,0 +1,16 @@
|
||||
<ion-content>
|
||||
<form [formGroup]="form">
|
||||
<ion-list>
|
||||
<ion-item>
|
||||
<ion-label>Searchbar</ion-label>
|
||||
<ion-searchbar formControlName="searchbar"></ion-searchbar>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
</form>
|
||||
<p>
|
||||
Form status: <span id="status">{{ form.status }}</span>
|
||||
</p>
|
||||
<p>
|
||||
Form value: <span id="value">{{ form.value | json }}</span>
|
||||
</p>
|
||||
</ion-content>
|
16
angular/test/base/src/app/searchbar/searchbar.component.ts
Normal file
16
angular/test/base/src/app/searchbar/searchbar.component.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { FormBuilder, Validators } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'app-searchbar',
|
||||
templateUrl: 'searchbar.component.html',
|
||||
})
|
||||
export class SearchbarComponent {
|
||||
|
||||
form = this.fb.group({
|
||||
searchbar: ['', Validators.required]
|
||||
})
|
||||
|
||||
constructor(private fb: FormBuilder) { }
|
||||
|
||||
}
|
21
angular/test/base/src/app/searchbar/searchbar.module.ts
Normal file
21
angular/test/base/src/app/searchbar/searchbar.module.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { NgModule } from "@angular/core";
|
||||
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
|
||||
import { IonicModule } from "@ionic/angular";
|
||||
|
||||
import { SearchbarRoutingModule } from "./searchbar-routing.module";
|
||||
import { SearchbarComponent } from "./searchbar.component";
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
IonicModule,
|
||||
SearchbarRoutingModule
|
||||
],
|
||||
declarations: [
|
||||
SearchbarComponent
|
||||
]
|
||||
})
|
||||
export class SearchbarModule { }
|
Reference in New Issue
Block a user