diff --git a/core/src/components/input/usage/vue.md b/core/src/components/input/usage/vue.md
index 9be8fc34976..87766566954 100644
--- a/core/src/components/input/usage/vue.md
+++ b/core/src/components/input/usage/vue.md
@@ -1,45 +1,72 @@
```html
-
+
-
+
-
+
-
+
-
+
-
+
-
+
Default Label
-
+
Floating Label
-
+
Fixed Label
-
+
Stacked Label
-
+
+
+
+
+
+
+
+
+
+
+
+
```
\ No newline at end of file
diff --git a/vue/src/components/inputs.ts b/vue/src/components/inputs.ts
index 2dcdb7ac25c..eec71ea5969 100644
--- a/vue/src/components/inputs.ts
+++ b/vue/src/components/inputs.ts
@@ -1,57 +1,81 @@
-import Vue from 'vue';
+import Vue, { CreateElement, RenderContext } from 'vue';
+
+interface EventHandler {
+ [key: string]: (e: Event) => void;
+}
+
+// Events to register handlers for
+const events: string[] = ['ionChange', 'ionInput', 'ionBlur', 'ionFocus', 'ionCancel', 'ionSelect'];
+
+// Arguments to be passed to the factory function
+const inputComponentsToBeCreated = [
+ ['IonCheckboxVue', 'ion-checkbox', 'ionChange', 'checked'],
+ ['IonDatetimeVue', 'ion-datetime'],
+ ['IonInputVue', 'ion-input', 'ionInput'],
+ ['IonRadioVue', 'ion-radio', 'ionSelect'],
+ ['IonRangeVue', 'ion-range'],
+ ['IonSearchbarVue', 'ion-searchbar', 'ionInput'],
+ ['IonSelectVue', 'ion-select'],
+ ['IonTextareaVue', 'ion-textarea'],
+ ['IonToggleVue', 'ion-toggle', 'ionChange', 'checked'],
+];
+
+// Factory function for creation of input components
+export function createInputComponents() {
+ inputComponentsToBeCreated.map(args => (createInputComponent as any)(...args));
+}
/**
* Create a wrapped input component that captures typical ionic input events
* and emits core ones so v-model works.
- * @param {} name the vue name of the component
- * @param {*} coreTag the actual tag to render (such as ion-datetime)
+ * @param name the vue name of the component
+ * @param coreTag the actual tag to render (such as ion-datetime)
+ * @param modelEvent to be used for v-model
+ * @param valueProperty to be used for v-model
*/
-export function createInputComponent(name: string, coreTag: string, modelEvent = 'ionChange', valueProperty = 'value') {
- return Vue.component(name, {
+function createInputComponent(name: string, coreTag: string, modelEvent = 'ionChange', valueProperty = 'value') {
+ Vue.component(name, {
+ name,
+ functional: true,
model: {
event: modelEvent,
- prop: valueProperty
+ prop: valueProperty,
},
- render(createElement: any) {
- // Vue types have a bug accessing member properties:
- // https://github.com/vuejs/vue/issues/8721
- const cmp: any = this;
-
- return createElement(coreTag, {
- 'attrs': cmp.attrs,
- 'on': {
- 'ionChange': cmp.handleChange,
- 'ionInput': cmp.handleInput,
- 'ionBlur': cmp.handleBlur,
- 'ionFocus': cmp.handleFocus
- }
- }, this.$slots.default);
+ render(h: CreateElement, { data, listeners, slots }: RenderContext) {
+ return h(coreTag, {
+ ...data,
+ on: buildEventHandlers(listeners, modelEvent, valueProperty),
+ }, slots().default);
},
- methods: {
- handleChange($event: any) {
- if (modelEvent === 'ionChange') {
- // Vue expects the value to be sent as the argument for v-model, not the
- // actual event object
- this.$emit('ionChange', $event.target[valueProperty]);
- } else {
- this.$emit('ionChange', $event);
- }
- },
- handleInput($event: any) {
- if (modelEvent === 'ionInput') {
- // Vue expects the value to be sent as the argument for v-model, not the
- // actual event object
- this.$emit('ionInput', $event.target[valueProperty]);
- } else {
- this.$emit('ionInput', $event);
- }
- },
- handleBlur($event: any) {
- this.$emit('ionBlur', $event);
- },
- handleFocus($event: any) {
- this.$emit('ionFocus', $event);
- }
+ });
+}
+
+function buildEventHandlers(listeners: RenderContext['listeners'], modelEvent: string, valueProperty: string) {
+ const handlers: EventHandler = {};
+
+ // Loop through all the events
+ events.map((eventName: string) => {
+ if (!listeners[eventName]) {
+ return;
}
+
+ // Normalize listeners coming from context as Function | Function[]
+ const callbacks: Function[] = Array.isArray(listeners[eventName])
+ ? listeners[eventName] as Function[]
+ : [listeners[eventName] as Function];
+
+ // Assign handlers
+ handlers[eventName] = (e: Event) => {
+ callbacks.map((f: Function) => {
+ if (e) {
+ f(modelEvent === eventName
+ ? (e.target as any)[valueProperty]
+ : e
+ );
+ }
+ });
+ };
});
+
+ return handlers;
}
diff --git a/vue/src/ionic.ts b/vue/src/ionic.ts
index d83929d3aba..24a2dce0ea7 100644
--- a/vue/src/ionic.ts
+++ b/vue/src/ionic.ts
@@ -13,7 +13,7 @@ import { appInitialize } from './app-initialize';
import { VueDelegate } from './controllers/vue-delegate';
import IonTabs from './components/navigation/ion-tabs';
import IonPage from './components/navigation/ion-page';
-import { createInputComponent } from './components/inputs';
+import { createInputComponents } from './components/inputs';
export interface Controllers {
actionSheetController: ActionSheetController;
@@ -98,15 +98,7 @@ export const install: PluginFunction = (_Vue, config) => {
Vue.component('IonTabs', IonTabs);
Vue.component('IonPage', IonPage);
- createInputComponent('IonCheckboxVue', 'ion-checkbox', 'ionChange', 'checked');
- createInputComponent('IonDatetimeVue', 'ion-datetime');
- createInputComponent('IonInputVue', 'ion-input', 'ionInput');
- createInputComponent('IonRadioVue', 'ion-radio');
- createInputComponent('IonRangeVue', 'ion-range');
- createInputComponent('IonSearchbarVue', 'ion-searchbar', 'ionInput');
- createInputComponent('IonSelectVue', 'ion-select');
- createInputComponent('IonTextareaVue', 'ion-textarea');
- createInputComponent('IonToggleVue', 'ion-toggle', 'ionChange', 'checked');
+ createInputComponents();
appInitialize(config);