I am trying to insert a custom JavaScript (a sketcher) into a Vue component but no luck so far. When I try inserting javascript directly into a template like this:
<template>
<div id="sketcher">
var sketcher = new ChemDoodle.SketcherCanvas('sketcher', 400, 300);
</div>
</template>
I get an error: "Templates should only be responsible for mapping the state to the UI. Avoid placing tags with side-effects in your templates, such as , as they will not be parsed."
My another attempt is to create a component in a different .js file and import it into a Vue component.
sketcher.js:
export default ({
mounted(){
return new ChemDoodle.SketcherCanvas('sketcher', 400, 300)
}
})
Home.vue
<template>
<div id="sketcher">
<app-sketcher></app-sketcher>
</div>
</template>
<script>
import sketcher from './sketcher';
export default {
components: {
"app-sketcher": sketcher
}
}
</script>
but I get this error: "Failed to mount component: template or render function not defined". I would highly appreciate any suggestions on how to fix this or to propose other options of embedding javascript into a Vue component.
Your first error message is self-explanatory: you cannot put a <script> tag in the <template> of a single-file Vue component.
In your second example, you aren't defining a template for the app-sketcher component when you register it in your Home.vue file. Your sketcher.js file exports just the definition for a mounted hook and nothing else.
You can make a Sketcher.vue file:
<template>
<div id="sketcher"></div>
</template>
<script>
export default {
mounted() {
return new ChemDoodle.SketcherCanvas('sketcher', 400, 300)
}
}
</script>
And then use import it and use it in your Home.vue file like so:
<template>
<app-sketcher/>
</template>
<script>
import AppSketcher from './Sketcher';
export default {
components: { AppSketcher }
}
</script>
Related
I am new to Nuxt, and am attempting to turn the Vue plugin vue3-markdown-it into a Nuxt 3 plugin, but am receiving the following error:
[Vue warn]: Failed to resolve component: Markdown If this is a native custom element, make sure to exclude it from component resolution via compilerOptions.isCustomElement.
What am I doing incorrectly?
Nuxt 3 Plugin Documentation
// md-plugin.client.ts
import Markdown from 'vue3-markdown-it'
export default defineNuxtPlugin(nuxtApp => {
nuxtApp.vueApp.use(Markdown)
})
// index.vue
<template>
<main>
<ClientOnly>
<Markdown :source="content" />
</ClientOnly>
</main>
</template>
<script lang="ts" setup>
const { find } = useStrapi4()
const {
data: {
attributes: { content },
},
} = await find('homepage')
</script>
I had a similar problem on different plugin. I solved the problem by using component instead of plugin.
Create a new file under the components folder (Markdown.vue).
Add Markdown codes in this file:
<template>
<Markdown :source="content" />
</template>
<script lang="ts" setup>
import { defineProps } from "vue";
import Markdown from 'vue3-markdown-it';
defineProps({
content: { type: any }
});
</script>
You can customize this code.
Delete plugin file (md-plugin.client.ts)
Now <Markdown :source="content" /> will see our generated Markdown component. It worked me.
I have created the basic Vue component which is as follow.
<template>
<div class="example">
/* here render the component or HTML passed by pluing */
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
name: 'Example',
});
</script>
Now I need to create a plugin that will render any HTML or Component passed to the Example.I know the basic syntax of plugins and how to use them in the Vue but don't know how to do this task since I am a newbie to Vue.
export default {
install(vue, opts){
/* how to take the component or HTML and pass to `Example` Component */
}
}
I need to implement these in vue2.
You can use a slot to render an arbitrary HTML inside any of your components.
Your Example Component:
<template>
<div class="example">
<slot />
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
name: 'Example',
});
</script>
Then use it like this:
<template>
<example>
<div>Render me inside the slot</div>
</example>
</template>
And it will result in the following rendered HTML:
<div class="example">
<div>Render me inside the slot</div>
</div>
Then in you plugin you can use your Example component and pass any html you want to it
Update: this how your plugin might look like. Just create a global component inside of it
import Vue from 'vue'
const ExamplePlugin = {
install(Vue){
Vue.component('Example', {
name: 'Example',
template: '<div class="example"><slot /></div>'
})
}
}
Then you can Vue.use(ExamplePlugin) and Example component will be available globally in your application
Problem: I am trying to programmatically register a component to be used in a slot in my Vue/Nuxt site. The component name is included in the data of the parent index.vue file, in this instance the component is named Projects. I am including it in a v-for template as the various objects in the 'modules' data array are iterated over. I had assumed this would be possible/easy from the dynamic component documentation and example however I have not managed to get it working in my case.
What I expect to happen: I expected the component to be registered and 'slotted' into the Module component correctly.
What actually happens: While I can see on the rendered view that the component is 'there', it is not in the correct place (i.e. slotted into the Module component). I also get a vue/no-unused-components error saying: The "Projects" component has been registered but not used.
I have read the documentation about component registration in modular systems but these seem to be for more complex cases than what I am trying to achieve. Any advice would be really helpful as I am totally stuck!
index.vue
<template>
<div>
<template v-for="module in modules">
<Module
:title="module.title"
:to="module.link"
/>
<component v-bind:is="module.slot" />
</Module>
</template>
</div>
</template>
<script>
import Module from '~/components/module/Module.vue'
import Projects from '~/components/module/slots/Projects.vue'
export default {
components: {
Module,
Projects
},
data () {
return {
modules: [
{
title: 'Work',
slot: 'Projects'
},
{
...
}
]
}
}
}
</script>
Edit: As a side note, I get the same error when registering the component with import like so:
components: {
Module,
'Projects': () => import('#/components/module/slots/Projects')
}
Module.vue
<template>
<div>
<h2>
{{ title }}
</h2>
<slot />
</div>
</template>
<script>
export default {
props: {
title: {
type: String,
default: ''
}
}
}
</script>
Projects.vue
<template>
<div>
<h3>Projects</h3>
</div>
</template>
<script>
export default {
name: 'Projects'
}
</script>
You use the self closure tag in your Module component.
This prevents your Projects component to be rendered within the slot.
Just replace:
<Module
:title="module.title"
:to="module.link"
/>
with:
<Module
:title="module.title"
:to="module.link"
>
and it should work.
I have a CRUD that enables me to write Vue.js component's code in the textarea like:
<template>
<div><p class='name-wrapper'>{{ model.name }}</p></div>
</template>
<script>
module.exports = {
name: 'NameWrapper',
props: ['model']
}
</script>
<style lang='sass'>
.name-wrapper
color: red
</style>
Then in other component, I fetch this data and want to register it as a dynamic/async, custom component like:
<template>
<component :is='dynamicName' :model='{name: "Alex"}'></component>
</template>
<script>
import httpVueLoader from 'http-vue-loader'
import Vue from 'vue'
export default {
name: 'DynamicComponent',
props: ['dynamicName', 'componentDefinitionFromTextareaAsString'],
beforeCreate: {
// I know that as a second parameter it should be an url to the file, but I can't provide it, but I would like to pass the contents of the file instead there:
httpVueLoader.register(Vue, this.$options.propsData.componentDefinitionFromTextareaAsString)
// I was trying also:
Vue.component(this.$options.propsData.dynamicName, this.$options.propsData.componentDefinitionFromTextareaAsString)
}
}
</script>
As far as I know, httpVueLoader needs the url to the .vue file instead - is there a way to pass there the code itself of the component?
I am aware that passing and evaluating <script></script> tag contents can cause security issues, but I really need to do it that way.
I've read also about Vue.js compile function, but that works only for templates, not the code of the component (so the script tags again).
Is it even possible to achieve such functionality in Vue.js?
It should be possible to use a data: URI with http-vue-loader, like this:
const vueText = `
<template>
<div class="hello">Hello {{who}}</div>
</template>
<script>
module.exports = {
data: function() {
return {
who: 'world'
}
}
}
<\/script>
<style>
.hello {
background-color: #ffe;
}
</style>
`
const MyComponent = httpVueLoader('data:text/plain,' + encodeURIComponent(vueText))
new Vue({
el: '#app',
components: {
MyComponent
}
})
<script src="https://unpkg.com/vue#2.6.10/dist/vue.js"></script>
<script src="https://unpkg.com/http-vue-loader#1.4.1/src/httpVueLoader.js"></script>
<div id="app">
<my-component></my-component>
</div>
If that doesn't work for some reason (maybe because one of your target browsers doesn't support it) then you could get it working by patching httpRequest. See https://www.npmjs.com/package/http-vue-loader#httpvueloaderhttprequest-url-. The documentation focuses on patching httpRequest to use axios but you could patch it to just resolve the promise to the relevant text.
Using single file architecture I'm trying to pass data (an object) from a parent component to a child:
App.vue
<template>
<div id="app">
<app-header app-content={{app_content}}></app-header>
</div>
</template>
<script>
import appHeader from './components/appHeader'
import {content} from './content/content.js'
export default {
components: {
appHeader
},
data: () => {
return {
app_content: content
}
}
}
</script>
appHeader.vue
<template>
<header id="header">
<h1>{{ app_content }}</h1>
</header>
</template>
<script>
export default {
data: () => {
return {
// nothing
}
},
props: ['app_content'],
created: () => {
console.log(app_content) // undefined
}
}
</script>
Seems to be such a trivial task and probably the solution is quite simple. Thanks for any advice :)
You're almost there.
In order to send the app_content variable from App.vue to the child component you have to pass it as an attribute in the template like so:
<app-header :app-content="app_content"></app-header>
Now, in order to get the :app-component property inside appHeader.vue you will have to rename your prop from app_component to appComponent (this is Vue's convention of passing properties).
Finally, to print it inside child's template just change to: {{ appContent }}