Passing Form Data Between Components & Vue Routing - vue.js

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.

Related

how to use template in vue3 instead of native template?

I'm tring to make a SelectBox component
<Options>
<Option
v-for="person in people"
:value="person"
>
{{ person.name }}
</Option>
</Options>
And I want Option to be a dynamic component:
<component :is="props.as || 'li'">
<slot />
</component>
So I can custom content in Option (not only with <li> tag), for example use div or template to render
<Options>
<Option
v-for="person in people"
:value="person"
as="template"
>
<li>
<span>{{ person.name }}</span>
<span>other</span>
</li>
</Option>
</Options>
But if prop.as is 'template', it's rendered in html native template and can't see it in browser
I expect the result:
Vue document show some detail
But it can't work for me to add any director on it, like this
<component
:is="props.as || 'li'"
v-if="true"
>
Anyone can help me?
You probably shouldn't be using the component tag for what you're trying to do.
According to the Vue docs, here are the options of what you can pass for the is prop:
The actual component to render is determined by the is prop.
When is is a string, it could be either an HTML tag name or a component's registered name.
Alternatively, is can also be directly bound to the definition of a component.
You are trying to pass a template instead of a Vue component, which component is not designed to work with. It is unclear exactly what you are trying to do, but you can probably use a slot to accomplish it. Otherwise, to get the component tag working, define a Vue component and pass that in.

How to communicate between components and slots?

I'd like to know if it's possible to have a component communicate with a v-model within a slot?
<medical-form>
<input type="text" v-model="dob" />
</medical-form>
In this example the dob data is defined in the medical-form component. The contents of the slot are generated server side as it uses sensitive information to work out which fields should be presented, because of this I can't fully move the form into the medical-form component.
Yes you can give slot-scope and you will get the data
In your medical-form component bind your dynamic value.
<slot :dob="dob" />
<medical-form>
<template slot-scope="{dob}">
<input type="text" v-model="dob" />
</slot>
</medical-form>
But recently vue deprecated using of slot-scope but it is backward compatible and will work. However I would like to show you that also.
Reference - https://v2.vuejs.org/v2/guide/components-slots.html
<medical-form>
<template v-slot="{dob}">
<input type="text" v-model="dob" />
</template>
</medical-form>

vue emit data back to parent when using a slot

I have input on custom component and when i click on the next button on the wrapper component i need to emit details to the parent component.
How is this possible in vue?
wrapper.vue
<template>
<div :id="contentId" class="mt-3">
<div>
<slot></slot>
</div>
<b-row class="float-right">
<b-col>
<button cssClass="e-outline" v-on:click="btnNext">{{nextButtonText}}</button>
</b-col>
</b-row>
</div>
</template>
parent.vue
<template>
<div>
<Wrapper contentId="1">
<CustomComponent1 />
</wrapper>
<Wrapper contentId="2">
<CustomComponent1 />
</wrapper>
</div>
</template>
customComponent1.vue
<template>
<div>
<input v-model="name" />
<input v-model="name2" />
</div>
</template>
code above is for illustrative purposes.
The problem is that the wrapper doesn't innately have access to data of the scoped component, therefore these links have to be created manually. There is no way to tell how many children or slots the component may have, so this kind of functionality is not part of the vue magic.
So in an example where you have parent App component, which holds a Wrapper that has a MyInput component in the slot...
MyInput
The MyInout component doesn't automatically update other components, so it needs to be setup to $emit the internal data.
This can be done using a watch, #change listener for the input, or some other way. You can emit multiple datum as they change, or use a single payload with all the data
this.$emit("input", myData);
App
The App needs to explicitly connect the data between MyInout and Wrapper
<Wrapper> <MyInput #input="onInput" slot-scope="{ onInput }" /> </Wrapper>
The magic/trick happens here, where we bind the input emit function of the input to the onInput function using slot-scope.
Wrapper
The wrapper then needs to listen to the events passed (via App) from Wrapper
<slot :onInput="onInput" />
where onInput is a method that would process the data
see example below
I would recommend the following reading
https://github.com/vuejs/vue/issues/4332 (specifically Evan's response why it's not possible)
https://adamwathan.me/renderless-components-in-vuejs/ Adam has a thoroughly documented way of using render functions and slots to abstract functionality from the UI. While it's not directly related, it's a worthwhile read and may provide more info on using slot-scope as well as some perspective on improving the structure of UI components.

Aurelia component slotting in markup for components model

I am building an autocomplete component. The plan is that I can slot in some markup for what I know the component is going to bind to.
The idea is this could be any object rather than a simple display value and identifier.
I have this working using templates but I am wondering if there is a better approach.
So far it looks like this (options is hard coded for now within the components model):
// Usage:
<autocomplete>
<template replace-part="item">
//this is the content for each option within the component
<b>${option.lastName}<b/>, ${option.firstName}
</template>
</autocomplete>
//autocomplete
<template>
<input type="text" placeholder="Type 3 characters ...">
<ul>
<li repeat.for="option of options">
<template replaceable part="item"></template>
</li>
</ul>
</template>
I don't really like the templating boilerplate, slots are much nicer, is there any way to make slots work like this?
<autocomplete>
<li repeat.for="option of options">
${option.lastName}<b/>, ${option.firstName}
<li/>
</autocomplete>
//autocomplete
<template>
<input type="text" placeholder="Type 3 characters ...">
<ul>
<slot></slot>
</ul>
</template>
Slot in Aurelia is the emulation based on standard spec, which mean it doesn't work with repeat situation. repaceable was introduced to handle this scenario and I don't think we have any other options. Sometimes it feels weird but with a little documentation, probably you and your team will be fine. What you can do is for each replacement, what properties it can look for to get the item.

Creating first view in 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>