#173 Implement dynamic modals functionality

This commit is contained in:
Noel De Martin
2018-02-15 18:29:42 +01:00
parent b7fb128b5e
commit c36dfb3c39
8 changed files with 184 additions and 8 deletions

View File

@@ -113,7 +113,7 @@ this.$modal.show('dialog', {
title: 'Alert!',
text: 'You are too awesome',
buttons: [
{
{
title: 'Deal with it',
handler: () => { alert('Woot!') }
},
@@ -122,7 +122,7 @@ this.$modal.show('dialog', {
default: true, // Will be triggered by default if 'Enter' pressed.
handler: () => {} // Button click handler
},
{
{
title: 'Close'
}
]
@@ -133,6 +133,50 @@ this.$modal.show('dialog', {
<img src="https://user-images.githubusercontent.com/1577802/29165216-ec62552c-7db9-11e7-807e-ef341edcc94d.png">
</p>
### Dynamic Modals
In order to instantiate modals at runtime (for lazy-loading or decluttering templates), it is possible to create modals dynamically.
To start using this feature you must set `dynamic: true` in plugin configuration:
```js
Vue.use(VModal, { dynamic: true })
```
And include the `<modals-container/>` component it in your project:
```vue
<modals-container/>
```
Call it (the first argument is the component definition, the second are component properties, and the third modal parameters):
```javascript
this.$modal.show({
template: `
<div>
<h1>This is created inline</h1>
<p>{{ text }}</p>
</div>
`,
props: ['text']
}, {
text: 'This text is passed as a property'
})
```
It can also be used with `.vue` files:
```javascript
import MyComponent from './MyComponent.vue'
this.$modal.show(MyComponent, {
text: 'This text is passed as a property'
}, {
draggable: true
})
```
For more examples please take a look at [vue-js-modal.yev.io](http://vue-js-modal.yev.io).
### SSR

View File

@@ -7,6 +7,8 @@
<demo-focus-modal/>
<demo-size-modal/>
<modals-container />
<v-dialog
@before-opened="dialogEvent('before-open')"
@before-closed="dialogEvent('before-close')"
@@ -106,6 +108,22 @@
@click="showButtonsDialog">
Dialog: buttons
</button>
<br>
<button
class="btn"
@click="showDynamicRuntimeModal">
Dynamic: Runtime Modal
</button>
<button
class="btn"
@click="showDynamicComponentModal">
Dynamic: Component Modal
</button>
<button
class="btn"
@click="showDynamicComponentModalWithModalParams">
Dynamic: Component Modal with modal params
</button>
</div>
</div>
</template>
@@ -118,6 +136,7 @@ import DemoLoginModal from './components/DemoLoginModal.vue'
import DemoDogProfileModal from './components/DogProfileModal.vue'
import DemoConditionalModal from './components/ConditionalModal.vue'
import DemoSizeModal from './components/SizeModal.vue'
import CustomComponentModal from './components/CustomComponentModal.vue'
export default {
name: 'app',
@@ -203,6 +222,36 @@ export default {
})
},
showDynamicRuntimeModal () {
this.$modal.show({
template: `
<div>
<h1>This is created inline</h1>
<p>{{ text }}</p>
</div>
`,
props: ['text']
}, {
text: 'This text is passed as a property'
})
},
showDynamicComponentModal () {
this.$modal.show(CustomComponentModal, {
text: 'This text is passed as a property'
})
},
showDynamicComponentModalWithModalParams () {
this.$modal.show(CustomComponentModal, {
text: 'This text is passed as a property'
}, {
resizable: true,
adaptive: true,
draggable: true,
})
},
dialogEvent (eventName) {
console.log('Dialog event: ' + eventName)
}

View File

@@ -0,0 +1,12 @@
<template>
<div>
<h1>This is a custom component</h1>
<p>{{ text }}</p>
</div>
</template>
<script>
export default {
props: ['text']
}
</script>

View File

@@ -3,7 +3,8 @@ import App from './App.vue'
import VueJsModal from 'plugin'
Vue.use(VueJsModal, {
dialog: true
dialog: true,
dynamic: true,
})
new Vue({

View File

@@ -24,6 +24,7 @@
"build:ssr-no-css": "webpack --config ./build/webpack.ssr-no-css.config.js --progress --hide-modules",
"lint": "eslint --ext .js,.vue src test/unit/specs",
"unit": "./node_modules/karma/bin/karma start test/unit/karma.conf.js",
"watch": "webpack --config ./build/webpack.client.config.js --progress --hide-modules --watch",
"build": "npm run build:client && npm run build:ssr && npm run build:ssr-no-css",
"test:types": "tsc -p types/test"
},

50
src/ModalsContainer.vue Normal file
View File

@@ -0,0 +1,50 @@
<template>
<div id="#modals-container">
<modal
v-for="modal in modals"
:key="modal.id"
:name="modal.name"
v-bind="modal.config"
@closed="remove(modal.id)"
>
<component :is="modal.component" v-bind="modal.params"></component>
</modal>
</div>
</template>
<script>
export default {
data () {
return {
uid: 0,
modals: []
}
},
created () {
this.$modal._setDynamicContainer(this)
},
methods: {
add (modal, params, config) {
let id = this.uid++
let name = '_dynamic-modal-' + id
this.modals.push({
id: id,
name: name,
component: modal,
params: params || {},
config: config || {}
})
this.$nextTick(() => {
this.$modal.show(name)
})
},
remove (id) {
for (let i in this.modals) {
if (this.modals[i].id === id) {
this.modals.splice(i, 1)
return
}
}
}
}
}
</script>

View File

@@ -1,5 +1,6 @@
import Modal from './Modal.vue'
import Dialog from './Dialog.vue'
import ModalsContainer from './ModalsContainer.vue'
const defaultComponentName = 'modal'
@@ -14,14 +15,26 @@ const Plugin = {
this.installed = true
this.event = new Vue()
this.dynamicContainer = null
/**
* Plugin API
*/
Vue.prototype.$modal = {
show (name, params) {
Plugin.event.$emit('toggle', name, true, params)
_setDynamicContainer (dynamicContainer) {
Plugin.dynamicContainer = dynamicContainer
},
show (modal, paramsOrProps, params) {
if (typeof modal === 'string') {
Plugin.event.$emit('toggle', modal, true, paramsOrProps)
} else {
if (Plugin.dynamicContainer === null) {
console.warn('[vue-js-modal] In order to render dynamic modals, a <modals-container> component must be present on the page')
} else {
Plugin.dynamicContainer.add(modal, paramsOrProps, params)
}
}
},
hide (name, params) {
Plugin.event.$emit('toggle', name, false, params)
},
@@ -41,6 +54,12 @@ const Plugin = {
if (options.dialog) {
Vue.component('v-dialog', Dialog)
}
/**
* Registration of <ModalsContainer/> component
*/
if (options.dynamic) {
Vue.component('modals-container', ModalsContainer)
}
}
}

4
types/index.d.ts vendored
View File

@@ -1,4 +1,4 @@
import Vue, { PluginObject } from "vue";
import Vue, { PluginObject, ComponentOptions } from "vue";
declare const VueJSModal: PluginObject<VueJSModalOptions>;
export default VueJSModal;
@@ -9,7 +9,7 @@ export declare interface VueJSModalOptions {
}
declare interface VModal {
show(name: string, params?: object): void;
show(modal: string | typeof Vue | ComponentOptions<Vue>, paramsOrProps?: object, params?: object): void;
hide(name: string, params?: object): void;
toggle(name: string, params?: object): void;
}