In Greet.vue
<template>
<h2> Hello {{ name }} </h2>
</template>
<script>
export default {
name: "Greet",
props:['name']
};
</script>
In App.vue
<template>
<Greet name="bruce"/>
<Greet name="leo" />
<Greet name="diana" />
</template>
<script>
import Greet from './components/Greet.vue'
export default {
name: 'App',
components: {
Greet,
}
}
</script>
First I encountered this problem. Then I follow it by.
"vetur.validation.template": false,
"vetur.validation.script": false,
"vetur.validation.style": false,
Now there is no error. But now there is only one Hello displayed in the browser. I should expect 3.
This occurs when the vetur extension cannot determine the version of Vue as it cannot resolve package.json.
The docs at https://vuejs.github.io/vetur/ state that if Vetur cannot find package.json and determine the version of Vue, it assumes 2.5. This is what generates the wrong error. Vue3 can have more than one element.
It is expecting to find this at the project root - ie where you open your editor. Try opening you editor so that package.json sits exactly on the first level. You do not need to adjust Vetur settings.
App.vue
<template>
<div>
<Greet name="bruce"/>
<Greet name="leo" />
<Greet name="diana" />
<div>
</template>
<script>
import Greet from './components/Greet.vue'
export default {
name: 'App',
components: {
Greet,
}
}
</script>
The above will solve template root requires exactly one element, while these vetur configurations only disable some code checks.
"vetur.validation.template": false,
"vetur.validation.script": false,
"vetur.validation.style": false,
I created a Vue custom directive for the first time. But the directive is not initialized. I tried a new project and the codepen too. I really don't know the problem!
This is my Vue component:
<template>
<div id="app">
<div my-test>Some text...</div>
</div>
</template>
<script>
export default {
name: "App",
directives: {
"my-test": function(el) {
el.style.backgroundColor = "red";
console.log("This is my first directive!");
}
}
};
</script>
The sandbox:
https://codesandbox.io/s/angry-khorana-uuhd0?file=/src/App.vue
Thanks
To ensure compliance with naming standards (have a - dash in the name) and to avoid conflicts, by default, all directives registered by Vue are automatically prefixed with v-.
So change the markup to <div v-my-test>...</div>. See it working.
I have a textarea component that include html tag and I want to get html in edit mode in this component. I use Laravel to generate html.
<template>
<div>
<textarea
:value="content"
:name="name"
:id="id">
<slot></slot>
</textarea>
</div>
</template>
In blade page I used to this component:
<my-component>
<p class="textbox">hello world</p>
</my-component>
when I put this component in page show me tag <slot></slot> in textarea. What should I do? Do you have any solution for my need?
thanks
<textarea> components are treated as static by the Vue renderer, thus after they are put into the DOM, they don't change at all (so that's why if you inspect the DOM you'll see <slot></slot> inside your <textarea>).
But even it if they did change, that wouldn't help much. Just because HTML elements inside <textarea>s don't become their value. You have to set the value property of the TextArea element to make it work.
Anyway, don't despair. It is doable, all you need to overcome the issues above is to bring a small helper component into play.
There are many possible ways to achieve this, two shown below. They differ basically in how you would want your original component's template to be.
Solution: change <textarea> into <textarea-slot> component
Your component's template would now become:
<template>
<div>
<textarea-slot
v-model="myContent"
:name="name"
:id="id">
<slot></slot>
</textarea-slot>
</div>
</template>
As you can see, nothing but replacing <textarea> with <textarea-slot> changed. This is enough to overcome the static treatment Vue gives to <textarea>. The full implementation of <textarea-slot> is in the demo below.
Alternative solution: keep <textarea> but get <slot>'s HTML via <vnode-to-html> component
The solution is to create a helper component (named vnode-to-html below) that would convert your slot's VNodes into HTML strings. You could then set such HTML strings as the value of your <textarea>. Your component's template would now become:
<template>
<div>
<vnode-to-html :vnode="$slots.default" #html="valForMyTextArea = $event" />
<textarea
:value="valForMyTextArea"
:name="name"
:id="id">
</textarea>
</div>
</template>
In both alternatives...
The usage of the my-component stays the same:
<my-component>
<p class="textbox">hello world</p>
</my-component>
Full working demo:
Vue.component('my-component', {
props: ["content", "name", "id"],
template: `
<div>
<textarea-slot
v-model="myContent"
:name="name"
:id="id">
<slot></slot>
</textarea-slot>
<vnode-to-html :vnode="$slots.default" #html="valueForMyTextArea = $event" />
<textarea
:value="valueForMyTextArea"
:name="name"
:id="id">
</textarea>
</div>
`,
data() { return {valueForMyTextArea: '', myContent: null} }
});
Vue.component('textarea-slot', {
props: ["value", "name", "id"],
render: function(createElement) {
return createElement("textarea",
{attrs: {id: this.$props.id, name: this.$props.name}, on: {...this.$listeners, input: (e) => this.$emit('input', e.target.value)}, domProps: {"value": this.$props.value}},
[createElement("template", {ref: "slotHtmlRef"}, this.$slots.default)]
);
},
data() { return {defaultSlotHtml: null} },
mounted() {
this.$emit('input', [...this.$refs.slotHtmlRef.childNodes].map(n => n.outerHTML).join('\n'))
}
});
Vue.component('vnode-to-html', {
props: ['vnode'],
render(createElement) {
return createElement("template", [this.vnode]);
},
mounted() {
this.$emit('html', [...this.$el.childNodes].map(n => n.outerHTML).join('\n'));
}
});
new Vue({
el: '#app'
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<my-component>
<p class="textbox">hell
o world1</p>
<p class="textbox">hello world2</p>
</my-component>
</div>
Breakdown:
Vue parses the <slot>s into VNodes and makes them available in the this.$slots.SLOTNAME property. The default slot, naturally, goes in this.$slots.default.
So, in runtime, you have available to you what has been passed via <slot> (as VNodes in this.$slots.default). The challenge now becomes how to convert those VNodes to HTML String? This is a complicated, still open, issue, which may get a different solution in the future, but, even if it ever does, it will most likely take a while.
Both solutions above (template-slot and vnode-to-html) use Vue's render function to render the VNodes to the DOM, then picks up the rendered HTML.
Since the supplied slots may have arbitrary HTML, we render the VNodes into an HTML Template Element, which doesn't execute any <script> tags.
The difference between the two solutions is just how they "handle back" the HTML generated from the render function.
The vnode-to-html returns as an event that should be picked up by the parent (my-component) which uses the passed value to set a data property that will be set as :value of the textarea.
The textarea-slot declares itself a <textarea>, to the parent doesn't have to. It is a cleaner solution, but requires more care because you have to specify which properties you want to pass down to the <textarea> created inside textarea-slot.
Wrapping up and off-the-shelf alternatives
However possible, it is important to know that Vue, when parsing the declared <template> into <slot>s, will strip some formatting information, like whitespaces between top-level components. Similarly, it strips <script> tags (because they are unsafe). These are caveats inherent to any solutions using <slot>s (presented here or not). So be aware.
Typical rich text editors for Vue, work around this problem altogether by using v-model (or value) attributes to pass the code into the components.
Well known examples include:
vue-ace-editor: Demo/codepen here.
Vue Prism Editor: Demo here.
vue-monaco (the code editor that powers VS Code): demo here.
vue-codemirror: Demo here. This is by far the most starred on github.
They all have very good documentation in their websites (linked above), so it would be of little use for me to repeat them here, but just as an example, see how codemirror uses the value prop to pass the code:
<codemirror ref="myCm"
:value="code"
:options="cmOptions"
#ready="onCmReady"
#focus="onCmFocus"
#input="onCmCodeChange">
</codemirror>
So that's how they do it. Of course, if <slot>s - with its caveats - fit your use case, they can be used as well.
The short answer is NOT POSSIBLE
Your slot is put inside an textarea tag. Textare tag is only able to display the text content on its box.
So in the case you want a kind of "HTML edit mode", you may looking for an WYSIWYG editor, I recommend you can use CKEditor for VueJS, the editor even will allow you to direct edit HTML code
https://ckeditor.com/docs/ckeditor5/latest/builds/guides/integration/frameworks/vuejs.html
Your HTML
<div id="app">
<ckeditor :editor="editor" v-model="editorData" :config="editorConfig"></ckeditor>
</div>
Your Component
const app = new Vue( {
el: '#app',
data: {
editor: ClassicEditor,
editorData: '<p>Editable Content HTML</p>',
editorConfig: {
// The configuration of the editor.
}
}
} );
In your case if you want to write your own content editor you can use div with attribute contenteditable="true" rather than textarea. After this you can write your text decoration methods ...
The generated html with laravel store in myhtml and use it in vue component.
Example: I also uploaded to codesandbox [Simple Vue Editor]
<template>
<div>
<button #click="getEditorCotent">Get Content</button>
<button #click="setBold">Bold</button>
<button #click="setItalic">Italic</button>
<button #click="setUnderline">Underline</button>
<button #click="setContent">Clear</button>
<div class="myeditor" ref="myeditor" contenteditable v-html="myhtml" #input="onInput"></div>
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: String
},
data: () => {
return {
myhtml:
"<h1>Simple editor</h1><p style='color:red'>in vue</p><p>Hello world</p>" // from laravel server via axios call
};
},
methods: {
onInput(e) {
// handle user input
// e.target.innerHTML
},
getEditorCotent() {
console.log(this.$refs.myeditor.innerHTML);
},
setBold() {
document.execCommand("bold");
},
setItalic() {
document.execCommand("italic");
},
setUnderline() {
document.execCommand("underline");
},
setContent() {
// that way set your html content
this.myhtml = "<b>You cleared the editor content</b>";
}
// PS. Good luck!
}
};
</script>
<style scoped>
.myeditor {
/* text-align: left; */
border: 2px solid gray;
padding: 5px;
margin: 20px;
width: 100%;
min-height: 50px;
}
</style>
I have really basic Vue app (on Rails):
hello_vue.js:
import Vue from 'vue/dist/vue.esm'
import TurbolinksAdapter from 'vue-turbolinks'
Vue.use(TurbolinksAdapter)
import CollectionSet from '../collection_set.vue'
document.addEventListener('turbolinks:load', () => {
const app = new Vue({
el: '#app',
components: { CollectionSet }
})
})
collection_set.vue:
<script>
import Collectable from './collectable.vue'
export default {
components: { Collectable }
}
</script>
<template>
<p>test</p>
<collectable />
</template>
collectable.vue:
<script>
export default {
name: 'collectable'
}
</script>
<template>
<p>test 2</p>
</template>
my webpage:
<div id="app"><collection-set /></div>
With above example I don't see anything, but when I remove <collectable /> from collection_set.vue, I see test. I don't have any errors.
Why collectable is not being rendered?
Change the template code of collection_set.vue to
<template>
<div>
<p>test</p>
<collectable />
</div>
</template>
the reason for error is that Component template should contain exactly one root element
Here we were trying to craete two root elements p and collectable
Now that I wrapped it within a parent div container, it works just fine.
Please try and let me know if it helps.
One suggestion is that always check into console of browser devtools to check what could be the issue. In this case, the console gave the exact error, also the code compilation failed with same error.
In Vue, each component must have only ONE root element, meaning you need to have a tag like <p> or <div> and inside it all your template.
I have been playing with the Vue tutorial Here and I have added a simple Jquery .html function. However it is not working. I have added the jQuery plugin, and there are no errors in the console. I have my "App" component defined like this:
<template>
<div id="app">
<div id="mainMenu"> Hello </div>
</div>
</template>
<script>
import * as start from './assets/scripts/start.js'
export default {
name: 'app',
created: start.loadMainNavigation()
}
</script>
and my loadMainNavigation function like this:
function loadMainNavigation() {
$('#mainMenu').html("ASERFDASRF");
console.log("In load Nav");
}
I can see the "In load Nav" in the console. No errors, but the DIV still has the original "Hello" - What am I doing wrong?
The reason the content doesn't change is that, at the time you are executing your function, the component has not yet been rendered to the DOM. The DOM is not rendered until the mounted event.
Beyond that, however, you need to be careful when you are integrating jQuery and Vue, or avoid it altogether. The idiomatic Vue way to do this would be something like this.
console.clear()
new Vue({
el: "#app",
data:{
message: "Hello"
},
created(){
this.message = "ASERFDASRF"
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.js"></script>
<div id="app">
<div id="mainMenu"> {{message}} </div>
</div>
There are a few times when you might mix jQuery and Vue (when you want to use a jQuery plugin for which there is no Vue counterpart, for example) but typically, there is almost always a way to do what you want without jQuery.