Vue Single File Components, how to mount multiple? - vue.js

Having an index.js file like this:
new Vue({
el: '#app',
components: {
'hello': Hello,
'counter': Counter,
'goodbye': GoodBye
}
});
And an index.html file like this:
<div id="app">
<Counter />
<Goodbye />
<Hello />
</div>
Only the first item inside #app is rendered.
As is, Counter shows ok. If I jump Goodbye or Hello up, they will also render perfectly.
I obviously would like all of them to render. What am I doing wrong?

HTML Does not support closing tags with />, its bahaves as the tag is not closed.
This means your structure looks like the following to the browser (check you elements with javascript disabled):
<div id="app">
<Counter>
<Goodbye>
<Hello>
</Hello>
</Goodbye>
</Counter>
</div>
This will of course not work, we need to update index.html to:
<div id="app">
<Counter></Counter>
<Goodbye></Goodbye>
<Hello></Hello>
</div>

Related

Vuejs 3: Prevent compiling plain HTML-Tags

I'm trying to avoid Vue from compiling plain HTML-Tags inside root element. Here is a code example:
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.0.5/vue.global.js"></script>
<script type="application/javascript" src="my_component.js">
<script>const app = Vue.createApp({});</script>
<div id="app">
<my-component></my-component>
...
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
...
<span>1</span>
<span>2</span>
<span>3</span>
<span>4</span>
...
</div>
<script>app.mount("#app");</script>
</body>
Vue 3 compiles all of the elements (plain HTML-Elements to) within the root elements to search for Vue components, but this can be a load problem if the page is very large and doesn't have that many Vue components.
I was trying to do something like this:
<script>app.config.isCustomElement = tag => tag.startsWith('div') || tag.startsWith('span');</script>
but that doesn't ignors plain HTML-Tags as div and span.
Another option that i tired was:
...
<div id="app">
<my-component></my-component>
...
<div v-pre>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
...
<span>1</span>
<span>2</span>
<span>3</span>
<span>4</span>
...
</div>
</div>
...
This was also not so successful.
Can someone help me with this problem?
I had the same requirement a while ago. I first added an extra attribute on every Vue component like this
<my-component [load-vue]></my-component>
And then I initialized every component with the following script on the page. I'm not sure this works for you but it might give you an idea how to do it.
document.querySelectorAll("[load-vue]").forEach(el => {
new Vue({
el: el
});
});
Warning: This works in Vue 2, not sure in Vue 3

why is Vuejs disabling the ability of a media query to add and remove component

Given i have this
//mycompoent.js
Vue.component('main-nav',{
template:`
<div id="main-nav">
</div>
`
});
Vue.component('menu-nav',{
template:`
<div id="menu-nav">
</div>
`
});
new Vue({
}).$mount("#nav-app");
Then in my CSS I have the following
//style.css
#menu-nav{display:none;}
#media (max-width:840px){
#main-nav{display:none;}
#menu-nav{display:block;}
}
//index.html
<div id="nav-app">
<main-nav />
<menu-nav />
</div>
When I resize the browser less than 840px the menu-nav component never appears; I don't know what I have done wrong.
If you're testing this directly in the browser (without a compile step), you can't use the self-closing form <main-nav /> for components. Try the following:
<div id="nav-app">
<main-nav></main-nav>
<menu-nav></menu-nav>
</div>

Using components without npm inside existing web page

I'm new to Vue.js and also do most work in a conventional LAMP environment.
The vue components tried so far don't seem to work linked in. Can anyone please:
Provide a sample process to install vue components in a legacy LAMP environment
Provide a simple html template showing how to load a vue component
Thanks for any tips.
Since you are in a legacy context, you probably won't use npm/webpack/babel. In this case, you'll import every package you need via <script> tags.
Process:
Look for the component you need
Check their docs for the steps needed to import them.
Usually it is a <script> tag (and a CSS <link> style) followed by some steps to configure (but not always).
In some rare cases the lib doesn't provide instructions for usage via <script>, in this case you can try using <script src="https://unkpg.com/NODE-PACKAGE-NAME"> and then see if it is possible to use it directly.
Examples:
Declaring your own <custom-comp> component and registering it globally via Vue.component.
<script src="https://unpkg.com/vue"></script>
<div id="app">
<p>{{ message }}</p>
<custom-comp v-bind:myname="name"></custom-comp>
</div>
<template id="cc">
<p>I am the custom component. You handled me {{ myname }} via props. I already had {{ myown }}.</p>
</template>
<script>
Vue.component('custom-comp', {
template: '#cc',
props: ['myname'],
data() {
return {
myown: 'Eve'
}
}
});
new Vue({
el: '#app',
data: {
message: 'Hello, Vue.js',
name: 'Alice'
}
});
</script>
Using a third-party component that gives instructions on how to use without NPM. Example bootstrap-vue. How to use? Follow their instructions for each specific component. Demo of the Card Component below.
<script src="https://unpkg.com/vue"></script>
<!-- Add this to <head> -->
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css"/>
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.css"/>
<!-- Add this after vue.js -->
<script src="//unpkg.com/babel-polyfill#latest/dist/polyfill.min.js"></script>
<script src="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.js"></script>
<div id="app">
<div>
<b-card title="Card Title"
img-src="https://lorempixel.com/600/300/food/5/"
img-alt="Image"
img-top
tag="article"
style="max-width: 20rem;"
class="mb-2">
<p class="card-text">
Some quick example text to build on the card title.
</p>
<b-button href="#" variant="primary">Go somewhere</b-button>
</b-card>
</div>
</div>
<script>
new Vue({
el: '#app'
});
</script>
Finally, using a third-party component that doesn't show any specific instructon on how to use without NPM. In the demo below we see the vue2-datepicker. They don't give specific instructions on how to use via <script>, but by looking at their readme, we see their component typically exports a DatePicker variable. Use then use <script src="https://unpkg.com/vue2-datepicker"> to load the component and register it for use via Vue.component('date-picker', DatePicker.default);. The need for .default varies. For other components, Vue.component('comp-name', ComponentName); (instead of ComponentName.default) directly could work.
// After importing the <script> tag, you use this command to register the component
// so you can use. Sometimes the components auto-register and this is not needed
// (but generally when this happens, they tell in their docs). Sometimes you need
// to add `.default` as we do below. It's a matter of trying the possibilities out.
Vue.component('date-picker', DatePicker.default);
new Vue({
el: '#app',
data() {
return {
time1: '',
time2: '',
shortcuts: [
{
text: 'Today',
start: new Date(),
end: new Date()
}
]
}
}
})
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/vue2-datepicker"></script>
<div id="app">
<div>
<date-picker v-model="time1" :first-day-of-week="1" lang="en"></date-picker>
<date-picker v-model="time2" range :shortcuts="shortcuts" lang="en"></date-picker>
</div>
</div>

vue.js helloworld not working within existing bootstrap site

I want to replace my project's first piece of vanilla JS with vue.
I try to get the hello world example working.
It works as stated, but when I nest the element in another element (these may be the wrong terms) it does not work.
My source code:
<!-- this works -->
<div id="app">
<p>${ message }</p>
</div>
<!-- but this doesn't for some reason -->
<div class="container">
<div id="app">
Nested ${ message }
</div>
</div>
Full code example.
The class="container" is needed for bootstrap.
EDIT:
I took the generated html and edited it down to just the bare minimum to show it not working.
See the result.
Wrap the container with
<div id="app"></div>
It should work that way
this works fine, the problem in your template is that you have two elements with id="app" so vue instance is initialized with the first element with id="app", then the second (the nested one) is never initialized
<html>
<head>
<script src="https://unpkg.com/vue"></script>
</head>
<body>
<!-- but this doesn't for some reason -->
<div class="container">
<div id="app">
Nested ${ message }
</div>
</div>
<script>
new Vue({
delimiters:['${', '}'],
el: '#app',
data: {
message: 'Hello Vue.js!'
}
})
</script>
</body>
</html>
You have 2 #app id but one vue instance. If you need two #app you should make two Vue instance. Instance 1 for #app1 and instance 2 for #app2. You can save theme in variables if you need to interact within theme:
<div id="app1">
<p>${ message }</p>
</div>
<div class="container">
<div id="app2">
Nested ${ message }
</div>
</div>
<script>
var app1 = new Vue({
delimiters:['${', '}'],
el: '#app1',
data: {
message: 'Hello Vue.js!'
}
});
var app2 = new Vue({
delimiters:['${', '}'],
el: '#app2',
data: {
message: 'Hello Vue.js!'
}
})
</script>
if this answer helped you, consider to accept it.

Is it possible to render two adjacent VueJS components?

I have created two custom VueJS components and I would like to place them adjacent to one another like so:
<div id="app">
<x-component />
<y-component />
</div>
...
new Vue({
el: '#app',
components: {
'x-component': { template: '<div>component x</div>' },
'y-component': { template: '<div>component y</div>' }
}
});
When I do this, only the first component is rendered. Is this a bug in VueJS or am I doing something wrong? It seems like this should be possible.
When I change it as follows, it works:
<div id="app">
<div>
<x-component />
</div>
<div>
<y-component />
</div>
</div>
Reproductions below:
Not working:
https://jsfiddle.net/mquqonuq/1/
Working:
https://jsfiddle.net/mquqonuq/2/
I can't remember right now if it's an html spec issue but custom web elements need to be a two tag closed system, not a self closed single element.
Try:
<div id="app">
<x-component></x-component>
<y-component></y-component>
</div>
Which works.
EDIT:
if you look at google's web components primer it lists
3. Custom elements cannot be self-closing because HTML only allows a few elements to be self-closing. Always write a closing tag (<app-drawer></app-drawer>).