fix(vue): ionChange events now propagate correctly (#22872)

resolves #22870
This commit is contained in:
Liam DeBeasi
2021-02-04 11:00:46 -05:00
committed by GitHub
parent 487349f02a
commit ff0f1da9f1
6 changed files with 53 additions and 30 deletions

View File

@ -2,8 +2,17 @@ import { App, Plugin } from 'vue';
import { IonicConfig, setupConfig } from '@ionic/core';
import { applyPolyfills, defineCustomElements } from '@ionic/core/loader';
const ael = (el: any, eventName: string, cb: any, opts: any) => el.addEventListener(eventName.toLowerCase(), cb, opts);
const rel = (el: any, eventName: string, cb: any, opts: any) => el.removeEventListener(eventName.toLowerCase(), cb, opts);
/**
* We need to make sure that the web component fires an event
* that will not conflict with the user's @ionChange binding,
* otherwise the binding's callback will fire before any
* v-model values have been updated.
*/
const transformEventName = (eventName: string) => {
return eventName === 'ionChange' ? 'v-ionchange' : eventName.toLowerCase();
}
const ael = (el: any, eventName: string, cb: any, opts: any) => el.addEventListener(transformEventName(eventName), cb, opts);
const rel = (el: any, eventName: string, cb: any, opts: any) => el.removeEventListener(transformEventName(eventName), cb, opts);
export const IonicVue: Plugin = {
@ -17,7 +26,7 @@ export const IonicVue: Plugin = {
await applyPolyfills();
await defineCustomElements(window, {
exclude: ['ion-tabs'],
ce: (eventName: string, opts: any) => new CustomEvent(eventName.toLowerCase(), opts),
ce: (eventName: string, opts: any) => new CustomEvent(transformEventName(eventName), opts),
ael,
rel
} as any);

View File

@ -97,7 +97,8 @@ export const IonCheckbox = /*@__PURE__*/ defineContainer<JSX.IonCheckbox>('ion-c
],
{
"modelProp": "checked",
"modelUpdateEvent": "ionChange"
"modelUpdateEvent": "v-ionChange",
"externalModelUpdateEvent": "ionChange"
});
@ -180,7 +181,8 @@ export const IonDatetime = /*@__PURE__*/ defineContainer<JSX.IonDatetime>('ion-d
],
{
"modelProp": "value",
"modelUpdateEvent": "ionChange"
"modelUpdateEvent": "v-ionChange",
"externalModelUpdateEvent": "ionChange"
});
@ -294,7 +296,8 @@ export const IonInput = /*@__PURE__*/ defineContainer<JSX.IonInput>('ion-input',
],
{
"modelProp": "value",
"modelUpdateEvent": "ionChange"
"modelUpdateEvent": "v-ionChange",
"externalModelUpdateEvent": "ionChange"
});
@ -445,7 +448,8 @@ export const IonRadio = /*@__PURE__*/ defineContainer<JSX.IonRadio>('ion-radio',
],
{
"modelProp": "value",
"modelUpdateEvent": "ionChange"
"modelUpdateEvent": "v-ionChange",
"externalModelUpdateEvent": "ionChange"
});
@ -457,7 +461,8 @@ export const IonRadioGroup = /*@__PURE__*/ defineContainer<JSX.IonRadioGroup>('i
],
{
"modelProp": "value",
"modelUpdateEvent": "ionChange"
"modelUpdateEvent": "v-ionChange",
"externalModelUpdateEvent": "ionChange"
});
@ -481,7 +486,8 @@ export const IonRange = /*@__PURE__*/ defineContainer<JSX.IonRange>('ion-range',
],
{
"modelProp": "value",
"modelUpdateEvent": "ionChange"
"modelUpdateEvent": "v-ionChange",
"externalModelUpdateEvent": "ionChange"
});
@ -551,7 +557,8 @@ export const IonSearchbar = /*@__PURE__*/ defineContainer<JSX.IonSearchbar>('ion
],
{
"modelProp": "value",
"modelUpdateEvent": "ionChange"
"modelUpdateEvent": "v-ionChange",
"externalModelUpdateEvent": "ionChange"
});
@ -567,7 +574,8 @@ export const IonSegment = /*@__PURE__*/ defineContainer<JSX.IonSegment>('ion-seg
],
{
"modelProp": "value",
"modelUpdateEvent": "ionChange"
"modelUpdateEvent": "v-ionChange",
"externalModelUpdateEvent": "ionChange"
});
@ -579,7 +587,8 @@ export const IonSegmentButton = /*@__PURE__*/ defineContainer<JSX.IonSegmentButt
],
{
"modelProp": "value",
"modelUpdateEvent": "ionChange"
"modelUpdateEvent": "v-ionChange",
"externalModelUpdateEvent": "ionChange"
});
@ -603,7 +612,8 @@ export const IonSelect = /*@__PURE__*/ defineContainer<JSX.IonSelect>('ion-selec
],
{
"modelProp": "value",
"modelUpdateEvent": "ionChange"
"modelUpdateEvent": "v-ionChange",
"externalModelUpdateEvent": "ionChange"
});
@ -695,7 +705,8 @@ export const IonTextarea = /*@__PURE__*/ defineContainer<JSX.IonTextarea>('ion-t
],
{
"modelProp": "value",
"modelUpdateEvent": "ionChange"
"modelUpdateEvent": "v-ionChange",
"externalModelUpdateEvent": "ionChange"
});
@ -722,7 +733,8 @@ export const IonToggle = /*@__PURE__*/ defineContainer<JSX.IonToggle>('ion-toggl
],
{
"modelProp": "checked",
"modelUpdateEvent": "ionChange"
"modelUpdateEvent": "v-ionChange",
"externalModelUpdateEvent": "ionChange"
});

View File

@ -17,6 +17,7 @@ interface NavManager<T = any> {
interface ComponentOptions {
modelProp?: string;
modelUpdateEvent?: string;
externalModelUpdateEvent?: string;
}
const getComponentClasses = (classes: unknown) => {
@ -40,7 +41,7 @@ const getElementClasses = (ref: Ref<HTMLElement | undefined>, componentClasses:
* integrations.
*/
export const defineContainer = <Props>(name: string, componentProps: string[] = [], componentOptions: ComponentOptions = {}) => {
const { modelProp, modelUpdateEvent } = componentOptions;
const { modelProp, modelUpdateEvent, externalModelUpdateEvent } = componentOptions;
/**
* Create a Vue component wrapper around a Web Component.
@ -66,8 +67,7 @@ export const defineContainer = <Props>(name: string, componentProps: string[] =
* native web component, but the v-model will
* not have been updated yet.
*/
emit(modelUpdateEvent, e);
e.stopImmediatePropagation();
emit(externalModelUpdateEvent, e);
});
}
};
@ -112,7 +112,7 @@ export const defineContainer = <Props>(name: string, componentProps: string[] =
ref: containerRef,
class: getElementClasses(containerRef, classes),
onClick: handleClick,
onVnodeBeforeMount: (modelUpdateEvent) ? onVnodeBeforeMount : undefined
onVnodeBeforeMount: (modelUpdateEvent && externalModelUpdateEvent) ? onVnodeBeforeMount : undefined
};
if (modelProp) {
@ -130,7 +130,7 @@ export const defineContainer = <Props>(name: string, componentProps: string[] =
Container.props = [...componentProps, ROUTER_LINK_VALUE];
if (modelProp) {
Container.props.push(MODEL_VALUE);
Container.emits = [UPDATE_VALUE_EVENT, modelUpdateEvent];
Container.emits = [UPDATE_VALUE_EVENT, externalModelUpdateEvent];
}
return Container;