VueJS test-utils can't find element inside child component - vue.js

I'm trying to use findComponent with find method to find a child component's element and set it's value. But every time I run test, it gives me Cannot call setValue on an empty DOMWrapper. error.
Test file
import { mount } from '#vue/test-utils';
import Create from './Create.vue';
// import State from '#/components/State.vue';
describe('it tests Create component', () => {
test('it emits create event and resets the form when form is valid and create button is clicked', async () => {
const div = document.createElement('div');
div.id = 'root';
document.body.append(div);
const expectedNameValue = 'TODO_NAME';
const expectedStateValue = 'Pending';
const wrapper = mount(Create, {
attachTo: '#root',
});
await wrapper.find(`input`).setValue(expectedNameValue);
await wrapper.findComponent({ ref: 'state-component' }).find('select').setValue(expectedStateValue);
await wrapper.find(`form`).trigger('submit');
expect(wrapper.emitted().create).toBeTruthy();
expect(wrapper.emitted().create[0]).toEqual([expectedNameValue]);
expect(wrapper.emitted().create[1]).toEqual(['Pending']);
expect(wrapper.find(`input[name='name']`).element.value).toEqual('');
expect(wrapper.find(`input[name='state']`).element.value).toEqual('Pending');
});
});
Create component
<template>
<form #submit.prevent="createTodo" class="flex gap-2 w-full">
<input class="flex-1 shadow rounded-md p-2 focus:ring-2 focus:ring-blue-900 focus:outline-none" type="text" placeholder="Todo Name" name="name" required/>
<State ref="state-component"/>
<button type="submit" class="rounded-md shadow text-white bg-blue-700 py-2 px-6">Create</button>
</form>
</template>
<script>
import State from '#/components/State.vue';
export default {
components: { State },
emits: ['create'],
methods: {
createTodo(event) {
const elems = event.target.elements;
const todo = { name: elems.name.value, state: elems.state.value };
this.$emit('create', todo);
elems.name.value = '';
elems.state.value = 'Pending';
}
}
}
</script>
<style scoped>
</style>
State component
<template>
<select id="state-select" class="rounded-md bg-green-200 text-white" name="state">
<option
v-for="(state, index) in states"
:selected="isSelected(state)"
:key="index"
>
{{ state }}
</option>
</select>
</template>
<script>
export default {
props: ["todo", "index"],
data() {
return {
name: "",
state: "",
states: ["Pending", "In Progress", "Done"],
};
},
created() {
if(!this.todo) return true;
this.state = this.todo.state;
this.name = this.todo.name;
},
methods: {
isSelected(equivalent){
return equivalent === this.state;
}
}
};
</script>
<style scoped></style>
I'm fairly new to VueJS so I'm open to all tips and tricks, thanks.

Some issues to fix:
You don't need to attach the component to the document, so remove that:
// ❌
// const div = document.createElement('div');
// div.id = 'root';
// document.body.append(div);
// const wrapper = mount(Create, { attachTo: '#root' });
// ✅
const wrapper = mount(Create);
The template ref to the State component would be the component's root element, so no need to find() the <select>:
// ❌
// await wrapper.findComponent({ ref: 'state-component' }).find('select').setValue(expectedStateValue);
^^^^^^^^^^^^^^^
// ✅
await wrapper.findComponent({ ref: 'state-component' }).setValue(expectedStateValue);
The emitted() object key is the event name, and the value is an array of of arrays, containing emitted data. You can verify the first create-event data contains another object with toMatchObject(object):
// ❌
// expect(wrapper.emitted().create[0]).toEqual([expectedNameValue]);
// expect(wrapper.emitted().create[1]).toEqual(['Pending']);
// ✅
expect(wrapper.emitted().create[0][0]).toMatchObject({ name: expectedNameValue, state: 'Pending' });
The last assertion tries to find input[name='state'], but that's actually a <select>, not an <input>:
// ❌
// expect(wrapper.find(`input[name='state']`).element.value).toEqual('Pending')
^^^^^
// ✅
expect(wrapper.find(`select[name='state']`).element.value).toEqual('Pending')
demo

Related

Can't get events from emits in my composable

I'm trying to generate a confirmation modal when calling my composable, my component instance is mounting well, but I can't access the emits via the : onCancel
The goal is to call the dialer every time I need to interact with a confirmation
useModalConfirm.ts
function confirm(props: ModalConfirmProps) {
const container = document.createElement('div');
document.body.appendChild(container);
const component = createVNode(ModalConfirm, {
...props,
// not working here :(
onCancel: () => {
console.log('canceled')
}
});
render(component, container);
return component.component;
}
ModalConfirm.vue
<script lang="ts" setup>
import {NButton} from "naive-ui";
const emits = defineEmits(["onConfirm", "onCancel"]);
export type ModalConfirmProps = {
title: string;
message: string;
confirmButtonText: string,
cancelButtonText: string,
};
const props = defineProps<ModalConfirmProps>();
const confirm = () => {
emits("onConfirm");
};
const cancel = () => {
emits("onCancel");
};
</script>
<template>
<div class="ModalConfirm">
<div class="ModalConfirmContent">
{{ props.title }}
{{ props.message }}
<NButton #click="cancel" type="error">{{ props.cancelButtonText }}</NButton>
<NButton #click="confirm" type="success">{{ props.confirmButtonText }}</NButton>
</div>
</div>
</template>
any ideas ?

How to use composition API with custom field in Vee Validate 4 correctly

After reading documentation of Vee Validate 4 about using composition api with custom inputs, do I understand correctly that hook useField a have to call only inside input component(in my example is VInput.vue)? Is any way that i can use hook functionality in parent component? The VInput is used for another functionality that don't need validation so it will be extra functionality add useForm for global component in out project
For example I have List.vue
<template>
<form class="shadow-lg p-3 mb-5 bg-white rounded" #submit.prevent="submitPostForm">
<VFormGroup label="Title" :error="titleError">
<VInput v-model="postTitle" type="text" name="title" />
</VFormGroup>
<VFormGroup label="Body" :error="bodyError">
<VInput v-model="postBody" type="text" name="body" />
</VFormGroup>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</template>
<script>
import { ref, onMounted } from 'vue';
import { Form, useForm, useField } from 'vee-validate';
import * as Yup from 'yup';
export default {
components: { Form },
setup() {
const schema = Yup.object().shape({
title: Yup.string().required(),
body: Yup.string().min(6).required(),
});
//hooks
const { handleSubmit } = useForm({ validationSchema: schema });
// No need to define rules for fields because of schema
const { value: postTitle, errorMessage: titleError } = useField('title');
const { value: postBody, errorMessage: bodyError } = useField('body');
//methods
const submitPostForm = handleSubmit(() => {
addPost({ title: postTitle, body: postBody });
});
return { schema, postTitle, postBody, titleError, bodyError, submitPostForm };
},
};
</script>
The problem that input error I have to show only in VFormGroup so how I can manage this form?
I am not sure if understood your question correctly.
But in your case you only have 1 issue, you destructure errorMessage and value twice in one file, which isn't working.
you could change your useField's like this:
const { errorMessage: titleError, value: titleValue } = useField('title', Yup.string().required());
const { errorMessage: bodyError, value: bodyValue } = useField('body', Yup.string().required().min(8));
In your template you then want to use titleError and bodyError in your VFormGroup.
In your VInput you want to use titleValue and bodyValue for v-model
because you initialise your title and body in your setup() I guess that those do not have any predefiend values. If that would be the case you might want to take a look at the Options for useField() where you can have as a thridParam as an Object with e.g. initialValue as key which then would be your post.value.title. But for your use case I wouldn't recommend this.
to answer the Code question from the comments:
<template>
<form class="shadow-lg p-3 mb-5 bg-white rounded" #submit="handleSubmit">
<VFormGroup label="Title" :error="titleError">
<VInput v-model="titleValue" type="text" name="title" />
</VFormGroup>
<VFormGroup label="Body" :error="bodyError">
<VInput v-model="bodyValue" type="text" name="body" />
</VFormGroup>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</template>
<script>
import { ref } from 'vue';
import { Form, useForm, useField } from 'vee-validate';
import * as Yup from 'yup';
export default {
components: { Form },
setup() {
const title = ref('');
const body = ref('');
//hooks
const { handleSubmit } = useForm();
// No need to define rules for fields because of schema
const { errorMessage: titleError, value: titleValue } = useField('title', Yup.string().required());
const { errorMessage: bodyError, value: bodyValue } = useField('body', Yup.string().required().min(8));
return { titleError, bodyError, titleValue, bodyValue, handleSubmit };
},
};
</script>

Vue composition API is not reactive inside v-for?

I am using Vue 2 and Vuetify (not Vue 3) to create a form builder website. I was going perfectly well until I found out that something is wrong. So here's the case. I rendered text fields (inputs) from a reactive array using the following code.
<template>
// ... some other unrelated code
<template v-if="answer.type !== 1">
<v-col
v-for="(_, i) in answer.options"
:key="`#question-${answer.id}-${i}`"
cols="12"
>
<div class="flex flex-row justify-between items-center">
<TextField
v-model="answer.options[i]"
class="ml-4"
label="Option"
underlined
hideLabel
/>
<v-btn #click="deleteOption(i)" icon>
<v-icon>mdi-close</v-icon>
</v-btn>
</div>
</v-col>
<v-col>
<TextButton #click="addOption()" text="+ ADD OPTION" />
</v-col>
</template>
// ... some other unrelated code
</template>
<script>
import { reactive, ref, watch } from '#vue/composition-api'
import useInquiry from '#/composables/useInquiry'
import TextButton from '#/components/clickables/TextButton.vue'
import TextField from '#/components/inputs/TextField.vue'
export default {
components: { TextField, TextButton },
setup() {
const { answer, addOption, deleteOption } = useInquiry()
return { answer, addOption, deleteOption }
}
}
</script>
Here's my useInquiry composable logic
import { reactive, watch, se } from '#vue/composition-api'
import ID from '#/helpers/id'
export default () => {
const answer = reactive({
id: ID(), // this literally just generates an ID
type: 2,
options: ['', '']
})
const addOption = () => {
answer.options.push('')
}
const deleteOption = at => {
const temp = answer.options.filter((_, i) => i !== at)
answer.options = []
answer.options = temp
};
return { answer, addOption, deleteOption }
}
And finally, here's my TextField.vue
<template>
<v-text-field
v-model="inputValue"
:label="label"
:single-line="hideLabel"
:type="password ? 'password' : 'text'"
:outlined="!underlined"
:dense="!large"
hide-details="auto"
/>
</template>
<script>
import { ref, watch } from '#vue/composition-api'
export default {
model: {
props: 'value',
event: 'change'
},
props: {
label: String,
value: String,
password: Boolean,
underlined: Boolean,
large: Boolean,
hideLabel: Boolean
},
setup(props, context) {
const inputValue = ref(props.value)
watch(inputValue, (currInput, prevInput) => {
context.emit('change', currInput)
})
return { inputValue }
}
}
</script>
The problem is, everytime the delete button is clicked, the deleted input is always the last one on the array, even though I didn't click on last one. I tried to log my reactive array by watching it using Vue's composition watch method. Apparently, the data is correctly updated. The problem is the v-model looks un-synced and the last input is always the one that gets deleted.
Looks good to me ....except the TextField.vue
Problem is in TextField.vue. What you actually doing inside setup of TextField.vue is this (Vue 2 API):
data() {
return {
inputValue: this.value
}
}
...this is one time initialization of inputValue data member with value of value prop. So when one of the options is removed and components are reused (because that's what Vue does all the time - especially when index is used in :key) inputValue is not updated to a new value of value prop...
You don't need inputValue or model option at all, just remove it and use this template:
<v-text-field
:value="value"
#input="$emit('input', $event)"
:label="label"
:single-line="hideLabel"
:type="password ? 'password' : 'text'"
:outlined="!underlined"
:dense="!large"
hide-details="auto"
/>
NOTE that in my example I'm using $event.target.value instead of just $event because I'm working with native <input> element and not Vuetify's custom component input...
working example...
const {
reactive,
ref,
watch
} = VueCompositionAPI
Vue.use(VueCompositionAPI)
const BrokenInput = {
model: {
props: 'value',
event: 'change'
},
props: {
value: String,
},
setup(props, context) {
const inputValue = ref(props.value)
watch(inputValue, (currInput, prevInput) => {
context.emit('change', currInput)
})
return {
inputValue
}
},
template: `<input type="text" v-model="inputValue" />`
}
const FixedInput = {
props: {
value: String,
},
template: `<input type="text" :value="value" #input="$emit('input', $event.target.value)"/>`
}
const useInquiry = () => {
const answer = reactive({
id: 1,
type: 2,
options: ['1', '2', '3', '4', '5']
})
const addOption = () => {
answer.options.push('')
}
const deleteOption = at => {
const temp = answer.options.filter((_, i) => i !== at)
answer.options = temp
};
return {
answer,
addOption,
deleteOption
}
}
const app = new Vue({
components: { 'broken-input': BrokenInput, 'fixed-input': FixedInput },
setup() {
return useInquiry()
},
})
app.$mount('#app')
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/#vue/composition-api#1.0.0-beta.18"></script>
<div id="app">
<table>
<tr>
<th>Option</th>
<th>Broken input</th>
<th>Model</th>
<th>Fixed input</th>
<th></th>
<tr>
<tr v-for="(_, i) in answer.options" :key="'#question-'+ answer.id + '-' + i">
<td>Option {{ i }}:</td>
<td>
<broken-input v-model="answer.options[i]" />
</td>
<td>
{{ answer.options[i] }}
</td>
<td>
<fixed-input v-model="answer.options[i]" />
</td>
<td><button #click="deleteOption(i)">Remove option</button></td>
</tr>
</table>
<button #click="addOption()">Add option</button>
</div>

Vue 3 how to get information about $children

This my old code with VUE 2 in Tabs component:
created() {
this.tabs = this.$children;
}
Tabs:
<Tabs>
<Tab title="tab title">
....
</Tab>
<Tab title="tab title">
....
</Tab>
</Tabs>
VUE 3:
How can I get some information about childrens in Tabs component, using composition API? Get length, iterate over them, and create tabs header, ...etc? Any ideas? (using composition API)
This is my Vue 3 component now. I used provide to get information in child Tab component.
<template>
<div class="tabs">
<div class="tabs-header">
<div
v-for="(tab, index) in tabs"
:key="index"
#click="selectTab(index)"
:class="{'tab-selected': index === selectedIndex}"
class="tab"
>
{{ tab.props.title }}
</div>
</div>
<slot></slot>
</div>
</template>
<script lang="ts">
import {defineComponent, reactive, provide, onMounted, onBeforeMount, toRefs, VNode} from "vue";
interface TabProps {
title: string;
}
export default defineComponent({
name: "Tabs",
setup(_, {slots}) {
const state = reactive({
selectedIndex: 0,
tabs: [] as VNode<TabProps>[],
count: 0
});
provide("TabsProvider", state);
const selectTab = (i: number) => {
state.selectedIndex = i;
};
onBeforeMount(() => {
if (slots.default) {
state.tabs = slots.default().filter((child) => child.type.name === "Tab");
}
});
onMounted(() => {
selectTab(0);
});
return {...toRefs(state), selectTab};
}
});
</script>
Tab component:
<script lang="ts">
export default defineComponent({
name: "Tab",
setup() {
const index = ref(0);
const isActive = ref(false);
const tabs = inject("TabsProvider");
watch(
() => tabs.selectedIndex,
() => {
isActive.value = index.value === tabs.selectedIndex;
}
);
onBeforeMount(() => {
index.value = tabs.count;
tabs.count++;
isActive.value = index.value === tabs.selectedIndex;
});
return {index, isActive};
}
});
</script>
<template>
<div class="tab" v-show="isActive">
<slot></slot>
</div>
</template>
Oh guys, I solved it:
this.$slots.default().filter(child => child.type.name === 'Tab')
To someone wanting whole code:
Tabs.vue
<template>
<div>
<div class="tabs">
<ul>
<li v-for="tab in tabs" :class="{ 'is-active': tab.isActive }">
<a :href="tab.href" #click="selectTab(tab)">{{ tab.name }}</a>
</li>
</ul>
</div>
<div class="tabs-details">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
name: "Tabs",
data() {
return {tabs: [] };
},
created() {
},
methods: {
selectTab(selectedTab) {
this.tabs.forEach(tab => {
tab.isActive = (tab.name == selectedTab.name);
});
}
}
}
</script>
<style scoped>
</style>
Tab.vue
<template>
<div v-show="isActive"><slot></slot></div>
</template>
<script>
export default {
name: "Tab",
props: {
name: { required: true },
selected: { default: false}
},
data() {
return {
isActive: false
};
},
computed: {
href() {
return '#' + this.name.toLowerCase().replace(/ /g, '-');
}
},
mounted() {
this.isActive = this.selected;
},
created() {
this.$parent.tabs.push(this);
},
}
</script>
<style scoped>
</style>
App.js
<template>
<Tabs>
<Tab :selected="true"
:name="'a'">
aa
</Tab>
<Tab :name="'b'">
bb
</Tab>
<Tab :name="'c'">
cc
</Tab>
</Tabs>
<template/>
If you copy pasted same code as me
then just add to the "tab" component a created method which adds itself to the tabs array of its parent
created() {
this.$parent.tabs.push(this);
},
My solution for scanning children elements (after much sifting through vue code) is this.
export function findChildren(parent, matcher) {
const found = [];
const root = parent.$.subTree;
walk(root, child => {
if (!matcher || matcher.test(child.$options.name)) {
found.push(child);
}
});
return found;
}
function walk(vnode, cb) {
if (!vnode) return;
if (vnode.component) {
const proxy = vnode.component.proxy;
if (proxy) cb(vnode.component.proxy);
walk(vnode.component.subTree, cb);
} else if (vnode.shapeFlag & 16) {
const vnodes = vnode.children;
for (let i = 0; i < vnodes.length; i++) {
walk(vnodes[i], cb);
}
}
}
This will return the child Components. My use for this is I have some generic dialog handling code that searches for child form element components to consult their validity state.
const found = findChildren(this, /^(OSelect|OInput|OInputitems)$/);
const invalid = found.filter(input => !input.checkHtml5Validity());
I made a small improvement to Ingrid Oberbüchler's component as it was not working with hot-reload/dynamic tabs.
in Tab.vue:
onBeforeMount(() => {
// ...
})
onBeforeUnmount(() => {
tabs.count--
})
In Tabs.vue:
const selectTab = // ...
// ...
watch(
() => state.count,
() => {
if (slots.default) {
state.tabs = slots.default().filter((child) => child.type.name === "Tab")
}
}
)
I had the same problem, and after doing so much research and asking myself why they had removed $children, I discovered that they created a better and more elegant alternative.
It's about Dynamic Components. (<component: is =" currentTabComponent "> </component>).
The information I found here:
https://v3.vuejs.org/guide/component-basics.html#dynamic-components
I hope this is useful for you, greetings to all !!
I found this updated Vue3 tutorial Building a Reusable Tabs Component with Vue Slots very helpful with explanations that connected with me.
It uses ref, provide and inject to replace this.tabs = this.$children; with which I was having the same problem.
I had been following the earlier version of the tutorial for building a tabs component (Vue2) that I originally found Creating Your Own Reusable Vue Tabs Component.
With script setup syntax, you can use useSlots: https://vuejs.org/api/sfc-script-setup.html#useslots-useattrs
<script setup>
import { useSlots, ref, computed } from 'vue';
const props = defineProps({
perPage: {
type: Number,
required: true,
},
});
const slots = useSlots();
const amountToShow = ref(props.perPage);
const totalChildrenCount = computed(() => slots.default()[0].children.length);
const childrenToShow = computed(() => slots.default()[0].children.slice(0, amountToShow.value));
</script>
<template>
<component
:is="child"
v-for="(child, index) in childrenToShow"
:key="`show-more-${child.key}-${index}`"
></component>
</template>
A per Vue documentation, supposing you have a default slot under Tabs component, you could have access to the slot´s children directly in the template like so:
// Tabs component
<template>
<div v-if="$slots && $slots.default && $slots.default()[0]" class="tabs-container">
<button
v-for="(tab, index) in getTabs($slots.default()[0].children)"
:key="index"
:class="{ active: modelValue === index }"
#click="$emit('update:model-value', index)"
>
<span>
{{ tab.props.title }}
</span>
</button>
</div>
<slot></slot>
</template>
<script setup>
defineProps({ modelValue: Number })
defineEmits(['update:model-value'])
const getTabs = tabs => {
if (Array.isArray(tabs)) {
return tabs.filter(tab => tab.type.name === 'Tab')
} else {
return []
}
</script>
<style>
...
</style>
And the Tab component could be something like:
// Tab component
<template>
<div v-show="active">
<slot></slot>
</div>
</template>
<script>
export default { name: 'Tab' }
</script>
<script setup>
defineProps({
active: Boolean,
title: String
})
</script>
The implementation should look similar to the following (considering an array of objects, one for each section, with a title and a component):
...
<tabs v-model="active">
<tab
v-for="(section, index) in sections"
:key="index"
:title="section.title"
:active="index === active"
>
<component
:is="section.component"
></component>
</app-tab>
</app-tabs>
...
<script setup>
import { ref } from 'vue'
const active = ref(0)
</script>
Another way is to make use of useSlots as explained in Vue´s documentation (link above).
Based on the answer of #Urkle:
/**
* walks a node down
* #param vnode
* #param cb
*/
export function walk(vnode, cb) {
if (!vnode) return;
if (vnode.component) {
const proxy = vnode.component.proxy;
if (proxy) cb(vnode.component.proxy);
walk(vnode.component.subTree, cb);
} else if (vnode.shapeFlag & 16) {
const vnodes = vnode.children;
for (let i = 0; i < vnodes.length; i++) {
walk(vnodes[i], cb);
}
}
}
Instead of
this.$root.$children.forEach(component => {})
write
walk(this.$root, component => {})
Many thanks #Urkle
In 3.x, the $children property is removed and no longer supported. Instead, if you need to access a child component instance, they recommend using $refs. as a array
https://v3-migration.vuejs.org/breaking-changes/children.html#_2-x-syntax

Vue: pass instantiated component to slot

I'm writing a component that renders a text. When a word starts with '#' it's a user's reference (like in twitter), and I must create a tooltip with the user's info.
This is how I instantiate the user's info component (this works fine, I'm using it in other places of the app):
const AvatarCtor = Vue.extend(AvatarTooltip);
let avatarComponent = new AvatarCtor({
propsData: {
user: user
}
});
This is the TooltipWrapper component:
<template>
<el-tooltip>
<slot name="content" slot="content"></slot>
<span v-html="text"></span>
</el-tooltip>
</template>
<script>
import {Tooltip} from 'element-ui';
export default {
name: "TooltipWrapper",
components: {
'el-tooltip': Tooltip
},
props: {
text: String
}
}
</script>
And this is how I wire it up all together:
const TooltipCtor = Vue.extend(TooltipWrapper);
const tooltip = new TooltipCtor({
propsData: {
text: "whatever"
}
});
tooltip.$slots.content = [avatarComponent];
tooltip.$mount(link);
This doesn't work. But if I set some random text in the content slot, it works fine:
tooltip.$slots.content = ['some text'];
So my problem is that I don't know how to pass a component to the slot. What am I doing wrong?
this.$slots is VNodes, but you assign with one component instance.
Below is one approach (mount the component to one element then reference its vnode) to reach the goal.
Vue.config.productionTip = false
const parentComponent = Vue.component('parent', {
template: `<div>
<div>
<slot name="content"></slot>
<span v-html="text"></span>
</div>
</div>`,
props: {
text: {
type: String,
default: ''
},
}
})
const childComponent = Vue.component('child', {
template: `<div>
<button #click="printSomething()">#<span>{{user}}</span></button>
<h4>You Already # {{this.clickCount}} times!!!</h4>
</div>`,
props: {
user: {
type: String,
default: ''
},
},
data(){
return {
clickCount: 1
}
},
methods: {
printSomething: function () {
console.log(`already #${this.user} ${this.clickCount} times` )
this.clickCount ++
}
}
})
const TooltipCtor = Vue.extend(parentComponent)
const tooltip = new TooltipCtor({
propsData: {
text: "whatever"
}
})
const SlotContainer = Vue.extend(childComponent)
const slotInstance = new SlotContainer({
propsData: {
user: "one user"
}
})
slotInstance.$mount('#slot')
tooltip.$slots.content = slotInstance._vnode
tooltip.$mount('#link')
<script src="https://unpkg.com/vue#2.5.16/dist/vue.js"></script>
<div id="link">
</div>
<div style="display:none"><div id="slot"></div></div>