Creating first view in Vue.js - vue.js

I'm creating first view in Vuejs like this:
<template>
<p>Welcome to MyWebsite</p>
<p>These terms and conditions outline the rules and regulations for the use of MySite Website.</p> <br />
<span style="text-transform: capitalize;"> MySite</span> is located at:<br />
<address>Adresss , City<br />State - 00000, USA<br />
</address>
</template>
But I always get
Welcome to MyWebsite These terms and conditions outline
the rules and regulations for the use of MySite Website.
MySite is located
at: Adresss , CityState - 00000, USA
Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them
instead.
why it recommend me to use v-if? I don't understand what should I do there? Regards

Component template should contain exactly one root element.
<template>
<div><!-- ONLY ONE DIRECT CHILD IN THE TEMPLATE -->
<p>Welcome to MyWebsite</p>
<p>These terms and conditions outline the rules and regulations for the use of MySite Website.</p> <br />
<span style="text-transform: capitalize;"> MySite</span> is located at:<br />
<address>Adresss , City<br />State - 00000, USA<br /></address>
</div>
</template>

For similar reasons to why React can only render a single root node Vue.js requires the first thing in the <template> to be the opening of a containing element inside of which the rest of the template will be written. Vue.js is guessing this is what you want, but it's better to make it explicit. Thus, to fix it:
<template>
<div>
<p>Welcome to MyWebsite</p>
<p>These terms and conditions outline the rules and regulations for the use of MySite Website.</p> <br />
<span style="text-transform: capitalize;"> MySite</span> is located at:<br />
<address>Adresss , City<br />State - 00000, USA<br />
</address>
</div>
</template>

The root element refers to your components root div-like element which is <template></template>
So, vue is telling you that below these root components you should only have one element: which means,
<template>
<div>
// put everything here
</div>
</template>

As stated above, you need to encapsulate the content inside a unique block (div, section...).
<template>
<section>
....
</section>
</template>

Related

how to delegate content from vue slots to web components slots?

The Problem
Let's say we have a page template written as a Web component in a shared library to keep the company design system consistent. That page has some slots:
export class PageTemplate extends LitElement {
static properties = {
title: { type: String },
};
render() {
return html`
<div>
<h1>${title}</h1>
<slot name="template-body"></slot>
<div class="some-special-styles">
<slot name="template-buttons"></slot>
</div>
</div>
`;
}
}
customElements.define("page-template", PageTemplate);
Then we use this template in a Vue (v3.2.45) application on a base component to be used in the same app by multiple pages.
//page-base.vue
<template>
<page-template title="My App Name">
<slot name="base-body"></slot>
<slot name="base-buttons"></slot>
</page-template>
</template>
Here, we will use the page base vue component on a specific page.
//login-page.vue
<template>
<PageBase>
<template #base-body>
<div slot="template-body">
<input placeholder="some special code"/>
</div>
</template>
<template #base-buttons>
<button slot="template-buttons">login</button>
<button slot="template-buttons">back</button>
</template>
</PageBase>
</template>
To make the login page components show inside that original page template web component; we need to declare the slot property on the leaf components like in <button slot="template-buttons">
How can I implement the Vue Page Base component to avoid the need to remember to set the slot property in every leaf vue component?
Things I've Tryied
I've tried to solve this using the vanilla web syntax below, but Vue appears not to dispatch that information to the final HTML:
//page-base.vue
<template>
<page-template title="My App Name">
<!-- this does not work -->
<slot name="base-body" slot="template-body"></slot>
<slot name="base-buttons" slot="template-buttons"></slot>
</page-template>
</template>
There was also an attempt (after a suggestion in the comments) to use a template as a ghost intermediate in the page base. But nothing was rendered at runtime.
//page-base.vue
<template>
<page-template title="My App Name">
<!-- i can't have that span because of some-special-styles applied in the template-->
<template slot="template-body"><slot name="base-body"></slot></template>
<template slot="template-buttons"><slot name="base-buttons"></slot></template>
</page-template>
</template>
The approach to using some middle element to make the connection (like below) enables content rendering. Still, it does not work for the project requirements because, for style reasons, I need that the final components be the top-most nodes in the page template slots.
//page-base.vue
<template>
<page-template title="My App Name">
<!-- although it runs, i can't have these spans because of some-special-styles applied in the template -->
<span slot="template-body"><slot name="base-body"></slot></span>
<span slot="template-buttons"><slot name="base-buttons"></slot></span>
</page-template>
</template>

vue passing props to sub component will generate html attributes to wrapper root

So I have this component PageWrapper that has a title props.
<div id="page-wrapper">
<h1>{{title}}</h1>
<slot />
</div>
And I have a wrapper component that forwards most props to its child:
<PageWrapper v-bind="[$attrs]">
<slot name="default"/>
</PageWrapper>
It works as expected, except that my page wrapper root has an extra title html attribute that I don't want to be there.
<div id="page-wrapper" title="My Title">
<h1>My title</h1>
<!-- rest of the page -->
</div>
I have the feeling there is a confusion between html attributes and vue properties when forwarding to sub-component.
I thought this had to do with the difference between $props and $attrs but apparently not as it doesn't work in any case.
Can someone clarify this for me? How can I avoid this html-attributes behavior?
Cheers
you do not want to bind the attributes to the PageWrapper Component.
Instead just bind the title property.
<PageWrapper :title="title">
<slot name="default"/>
</PageWrapper>
EDIT:
Might also try to bind the attributes without the square brackets v-bind="$attrs"

Register multiple Vue components in parent component

I have a global sidebar component TheSidebar.vue:
<template>
<aside>
<slot></slot>
</aside>
</template>
In Blogs.vue (a page component) I try to register two components.
<template>
<div>
<h1>Experiences</h1>
<TheSidebar>
<SearchBlog />
<CategoryCheckboxFilter />
</TheSidebar>
<ExperienceList />
</div>
</template>
It seems like I cannot register two components in a slot?
Is this a good setup anyway and who do I have to achieve this?
Update
It's just working fine now and I can register more than one component in a <slot />. I think some webpack building issue before.

How do I use conditional rendering on template tag?

According to the Vue documentation I should be able to add the v-if condition to the <template> tag:
<template v-if="false">
<div>Invisible text</div>
</template>
But this will not hide the element, however it does work when added to the child element:
<template>
<div v-if="false">Invisible text</div>
</template>
Any suggestions?
I'm including the template in another .vue file:
<template>
<div id="app">
<H1 class= "main-title">Title</H1>
<span class="components">
<testtemplate></testtemplate>
</span>
</div>
</template>
The template tag of a single-file component is not rendered by Vue like normal <template> tags. It is simply one of the placeholders, along with <script> and <style> that vue-loader uses to build the component. The root element of that template is what will be the root in the component.
But, even if it worked the way you want, there would be no difference between your first and second example. Using v-if on the root will prevent the entire component's template from rendering if set to false.
Had this problem with VUE3. Using SFC just nest tag template inside another tag template :
<template>
<template v-if="false">
You won't see this
</template>
</template>

Passing Form Data Between Components & Vue Routing

I am trying to create a step-by-step form using Components & Routing. If there is a better or easier approach to do this, please feel free to suggest, since I am new to Vue.js.
I have a and 3 templates.
<template id="step-1">
<h1>Welcome to Form</h1>
</template>
<template id="step-2">
<label>Name:</label>
<input type="text" name="name" v-model="name" />
<br />
<label>Email:</label>
<input type="email" name="email" v-model="email" />
</template>
<template id="step-3">
<p>Review:</p>
<!-- Display Step 2 Form Values -->
{{ name }}
{{ email }}
<button>Submit</button>
</template>
What I want to do is, display the input values on #step-3, and on a button click, submit the form via an ajax call.
You can view the Fiddle from here: https://jsfiddle.net/j7mwc9wk/
One way to do this is for all three components use the same data object. For the purposes of this bit of code it can be a simple javascript object. A bit more sophisticated approach is to use Vuex an official Vue data store.
You could also have these three components have the same parent in which case name and email would be properties of parent data method and therefore accessible to all children. I don't know how this would work with Vue router but it should be fine.