Is it possible to render two adjacent VueJS components? - vue.js

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>).

Related

Vue v-if v-if-else time complexity

I'm doing a project vue and I wanted to know if vue v-if v-else-if time complexity is O(n) or O(1)
I'm using a component in vue like a switch case (takes input and returns html) something like
<div v-if="type === 'A'">
<!-- HTML Data -->
</div>
<div v-else-if="type === 'B'">
<!-- HTML Data -->
</div>
<div v-else-if="type === 'C'">
<!-- HTML Data -->
</div>
<div v-else>
<!-- HTML Data -->
</div>
but with a lot more cases.
Is that the recommended way to do something like this? or should I make a lot of small component and load them dynamically? which is O(1)
And the reason I have this component is that it takes in a string input and returns a custom icon for a data that can be changed, so they have to be loaded dynamically
I think it's better to create a type/value map and a computed property:
new Vue({
el:"#app",
data(){
return{
type: 'A',
types: {A:'A',B:'B',C:'C'}
}
},
computed:{
typeVal(){
return this.types[this.type];
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
{{typeVal}}
</div>

Vue Custom directive not working with template tag

I'm facing issue with the below directive, it is working with any tag except the template tag
Vue.directive('count',{
bind(el,b,v){
console.log(b.value);
},
inserted(el,b,v){
console.log(b.value);
},
update(el,b,v){
console.log(b.value);
}
});
new Vue({
el: "#app" ,
data:{
value:0
}
})
<div id="app">
<button #click="value+=1">
inc value
</button>
<template v-count="value">
</template>
<!-- <div v-count="value">
</div> -->
</div>
If the comment on the div is removed, the directive logs the value, but with the template tag directive's hooks are not triggered
Here jsfiddle for the issue
Thanks
The template tag doesn't actually mount anything on its own, so it has no place in the DOM and doesn't bind. In your case, an easy solution is to just put v-count="value" on the button tag. If there is a more specialized need for this directive and you're just giving us placeholder code, putting it on a SPAN or DIV will make more sense than a template anyway.

Vue Single File Components, how to mount multiple?

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>

Vue.js - Render issue

I'm trying to create a component, that can show/hide on click, similar to an accordion.
I have the following error and I don't know why:
[Vue warn]: Property or method "is_open" is not defined on the
instance but referenced during render. Make sure to declare reactive
data properties in the data option. (found in root instance)
<div id="app">
<div is="m-panel" v-show="is_open"></div>
<div is="m-panel" v-show="is_open"></div>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="comp_a.js" ></script>
<!--<script src="app.js" ></script>-->
</html>
Vue.component('m-panel', {
data: function() {
return {
is_open: true
}
},
template: '<p>Lorem Ipsum</p>'
})
new Vue({
el:'#app',
})
Your code seems a little confused, your is_open is in your component but you are trying to access it in the parent. You just need to make sure this logic is contained inside your component. The easiest way is to simply place an event on the relevant element in your component template:
<template>
<div>
<!-- Toggle when button is clicked-->
<button #click="is_open=!is_open">
Open Me!
</button>
<span v-show="is_open">
I'm Open!
</span>
</div>
</template>
Here's the JSFiddle: https://jsfiddle.net/ytw22k3w/
Because u used is_open property in '#app instance' but u didnt declare in it,u decladed in 'm-panel component' which has no relation with it.Try something like this can avoid it.
new Vue({
el:'#app',
data:{
is_open:''
}
})

Vue.js: initialize the data object with data from the page or from v-text directive

So I'm just starting to play with Vue.js and I would like to know if there is a nice way to initialize the data object with html tags content from the page.
Basically I have a page that displays information and I would like to turn it into a tiny Vue application to avoid having a separated edit page.
So I added the form with 2 way binding which submits the values via ajax.
The thing is I really want to avoid Flash Of Uncompiled Content, but then I feel like I have to duplicate all my data, once in the html tag, once in the data object.
<div id="app">
<span v-text="prop1">This is filled by the backend</span>
<input v-model="prop1" type="text" v-cloak />
</div>
<script>
new Vue({
el: "#app",
data: {prop1: "This is filled by the backend..again"} // << Can I avoid this?
});
</script>
Could I tell Vue to get the data from the html tags since it's already there?
Thanks!
You are looking for props
Your html element would look something like
<custom-element dataToPass="dataFromHtml"></custom-element>.
Then you can access it in your vue instance via this.dataToPass.
Have a read through the documentation, there is a difference if you pass a string or an expression (from another vue instance for example).
In your example:
<div id="app">
<span prop1="{ backendVariable}" v-text="prop1"></span>
<input v-model="prop1" type="text" v-cloak />
</div>
<script>
new Vue({
el: "#app",
props: ['prop1']
});
</script>
```