Why email validation in Vue for input doesn't work if id div is removed - vue.js

I am very new to Vue.js, I want to learn in this codepen (not mine) why if we remove the div with id="app" fails to render email validator input field.
<div class="container" id="app">
<div :class="['input-group', isEmailValid()]">
<span class="input-group-addon" id="basic-addon1"><span class="fa fa-envelope"></span></span>
<input type="email" class="form-control" placeholder="Email Address" v-model="email" />
</div>
</div>
I want to sue this email validator input field in my single file component i.e. (.vue), if I add attribute el: '#app' still I get not able to find element app in the console. even if I keep the div with id="app"
I tried this:
<div :class="['input-group', isEmailValid()]" id="app>
<span class="input-group-addon" id="basic-addon1"><span class="fa fa-envelope"></span></span>
<input type="email" class="form-control" placeholder="Email Address" v-model="email" />
</div>
to fit it in my single file component but it doesn't work!

It's because Vue doesn't know where to mount.
see new Vue({ el: '#app' in the script? If you want to change the id, change both the div id and the el value. If you remove it, you'll need to find another way to mount.

Related

Bootstrap 5's input group: How to make entire input group clickable for datepicker item?

I am using the Vue-datetime package for a datepicker in the UI and also am using Bootstrap 5's input group form component for placing buttons on sides of input fields.
I would like to make the entire input field clickable, as well as the button. Does anyone have any advice on how to do so? My current attempt just makes only a small part of the input field clickable. How to extend it for the entire field, as well as the button?
Screenshot of my current attempt:
I have a codesandbox here: https://codesandbox.io/s/gallant-glade-orwv9?file=/src/components/HelloWorld.vue
Note: It would be nice to hide the inner date field border, as well.
You can solve this issue by using some Bootstrap utility classes.
Applying form-control and p-0 to the wrapper will give it the look of a normal bootstrap input.
Then we can add some classes to the input itself using the input-class prop.
Here we'll add w-100 to stretch it to full width. py-1 and px-2 to give the placeholder some padding and then border-0 to remove the base border on the <input />.
class="form-control p-0"
input-class="w-100 py-1 px-2 border-0"
You'll also want to move the hidden input field to after the datetime component, to avoid the border-radius being messed up on the left side.
The button we can make into a <label> and point to the input to allow us to open the datepicker by pressing it. We can style the label using the btn classes.
new Vue({
el: "#app"
})
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap#5.1.0/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="//unpkg.com/vue-datetime#1.0.0-beta.14/dist/vue-datetime.min.css" />
<script src="//unpkg.com/vue#2.6.14/dist/vue.min.js"></script>
<script src="//unpkg.com/luxon#1.28.0/build/global/luxon.min.js"></script>
<script src="//unpkg.com/weekstart#1.1.0/dist/commonjs/main.js"></script>
<script src="//unpkg.com/vue-datetime#1.0.0-beta.14/dist/vue-datetime.js"></script>
<div id="app" class="p-4">
<label class="form-label" for="date_input">Date:</label>
<div class="input-group">
<datetime input-id="date_input" type="date" ref="dateInput" class="form-control p-0" input-class="w-100 py-1 px-2 border-0" placeholder="Choose a date..." aria-label="Choose a date..." aria-describedby="dateField" auto required></datetime>
<input type="text" class="d-none" placeholder="Choose a date..." aria-label="Choose a date..." aria-describedby="dateField" />
<label for="date_input" class="btn btn-primary">
Button
</label>
</div>
</div>

Can I use parts of html template of a component in different part in parent component

I have a component which returns locations, then places, then hotels one after her other but I want these in 3 different parts like they show in tabs.
component code:
<template>
<li class="col-xs-12" :id="location.id">
<p class="col-xs-3">{{location.name}} - Days : </p>
<div class="col-xs-2"><input type="text" v-model="location.days"></div>
<div class="col-xs-4">
<!-- {{hotelset(location.id,hotels)}}-->
<!-- {{typeof (hotels)}}{{index}}-->
<v-select v-model="hotelselect[location.id]" name="addhotel" label="title"
#input="addtohotel(index,location.id)" :value="non" :options=hoteloptions[location.id] />
<!--{{hoteloptions}}-->
<!--{{$props}}-->
</div>
<button #click="remove" class="col-xs-3 btn btn-danger">Remove</button>
<div></div>
<div class="col-xs-12" v-for="day in parseInt(location.days)" :key="day">
Day {{day}}-
{{preselect(day,defaultt,location.id,place)}}
<v-select v-model="days[day]" name="addplaceloc" label="title" #input="addtoplaces(day,location.id)"
:value="defaultt" :options="localplace[location.id][day]" multiple />
<!--{{localplace[location.id][day]}}-->
<div v-for="(placeinfo, index) in objj[location.id]['day-'+day]['place']">Place: {{placeinfo['title']}}:
<label>From:</label><input type="text"
v-model="objj[location.id]['day-'+day]['place'][index]['from_time']">
<label>To:</label><input type="text" v-model="objj[location.id]['day-'+day]['place'][index]['to_time']">
<label>Remark:</label><input type="text"
v-model="objj[location.id]['day-'+day]['place'][index]['remark']">
<button #click="run"> yess</button>
</div>
</div>
</li>
<!--#click="remove"-->
in above code there are 2 v-select and 1 input listed one after the other as they are dependent to each other but I want it in different tabs in parent vue file. How to achieve it? tabs have its own style and html structure.
As #muka.gergely said, the only way to re-use HTML is to break it off into separate components.

adding component on add button

i am a absolute beginner in vuejs,i have a feature of adding dynamic input fields on click of a button it will keep on adding rows and keeping in mind the counter should be incrementing also so that i can validate on backend, this is my code so far
<div id="settlement_container" class="container-fluid mt-4">
<div class="card rounded-0 shadow-lg">
<div class="card-body p-0">
<div class="card-header px-2">
<div class="row wow fadeIn">
<div class="col-5">
<h3>Add Store Status</h3>
</div>
</div>
</div>
<form class="custom-form-group" action="{{url('stores/addStoreStatusDB')}}" method="POST">
<div class="form-group col-6">
<label for="exampleInputEmail1">Tax</label>
<input type="text" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" name="tax" placeholder="Tax" required>
</div>
<div class="display-inline">
<div class="form-group col-md-6">
<button #click="addstatus" class="btn btn-primary">Add Rows</button>
</div>
</div>
<div class="display-inline">
<div class="form-group col-md-6">
<button type="submit" class="btn btn-primary">Update Tax</button>
</div>
</div>
<dynamic-rows/>
</form>
</div>
</div>
</div>
{{-- Main layout --}}
#push('script')
<script src="{{ asset('js/app_vue.js') }}" ></script>
<script>
Vue.component('dynamic-rows',{
//accept data inside template
props:['counter'],
//accept data inside template
template:"<label for='exampleInputEmail1'>counter</label>"
});
const app = new Vue({
el: '#settlement_container',
data: {
counter:0
},
component:['dynamic-rows'],
methods:{
addstatus:function(e){
appendDiv=""
e.preventDefault();
alert("inside");
}
}
});
</script>
now i can do this in jquery in 5 minutes , but as i am beginner in vuejs i cant developer the sense of it of how to do it, i have a component and i want to repeat the component every time the button is clicked,
here is the fiddle! fiddle
OK, so a lot going on here and I think it may be easier to break down some of the points in isolation for you to play with and learn.
To add inputs, I think it makes more sense to have the values being in an array. Using Vue, you can iterate through that array to let each array element have its own <input/> while also simply adding another array element to add a new input:
<template>
<div>
<div v-for="(tax, index) in taxes" :key="index">
<input v-model="taxes[index]" />
</div>
<button type="number" #click="add">Add</button>
<p>Count: {{taxes.length}}</p>
</div>
</template>
<script>
export default {
data(): {
return {
taxes: [0]
}
},
methods: {
add() {
this.taxes.push(0);
}
}
});
</script>
Now with regards to the counter, I don't know what you mean validate on the backend. You could add a watcher on the taxes array and process changes there? Watchers are used sparingly, with computed properties being much preferred, but they may make sense if you need to be sending data to the backend instead of into the DOM.
The counter prop you registered in your code is not really going to work for the pattern I showed. Generally, props are for parent components to pass data to child components. The preferred pattern when sending data from child to parent is to use $emit. Read more here.

Vue.js: Loading template (or div) when user clicks button?

So I currently have a template sitting in a ".vue" file like so:
<template>
<div id="dataAttachToMe"></div>
</template>
I don't want this to load, unless a user clicks a button, something like
<button #click="loadTheTemplateAbove">See Data</button>
I've tried using this example:https://v2.vuejs.org/v2/guide/conditional.html#Controlling-Reusable-Elements-with-key. But it says something like "Component template should contain exactly one root element" in the error message.
I need more than a show/hide here I think, something that can initiate the template dynamically.
<template>
<div id="data">
<button #click="loadTemplate">Load the template</button>
<div v-if="buttonClicked">
<div id="dataAttachedToThisDiv"></div>
</div>
</div>
</template>
The error you are getting, means that there is more than one root element inside <template></template> tag.
It is required in Vue.js (and other template based frameworks/libraries) to have only one root element.
This will NOT work:
<template>
<div id="dataAttachToMe"></div>
<button #click="loadTheTemplateAbove">See Data</button>
</template>
This will work:
<template>
<div id="someRootDiv">
<div id="dataAttachToMe">Some data</div>
<button #click="loadTheTemplateAbove">See Data</button>
</div>
</template>
Here is a code example (App.vue) of what you are trying to achieve:
Basic idea: we have to create a variable, that will be changed upon button click. We add v-if directive that depends on that variable and will handle element's visibility.
Welcome to StackOverflow. When you get the error Component template should contain exactly one root element it means that you can only have one root element in your template. You can fix that error by wrapping everything in a blank div like so
<template>
<div>
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address">
</template>
</div>
</template>
Please edit your post and place you <script> tag. Conditional Rendering requires a data field of a boolean that you can place in your if statement on your template
<template>
<div>
<div v-if="show">{{message}}</div>
<div v-if="#show">Not Showing when show is set to false</div>
<button v-on:click="show = true">Show</button>
</div>
</template>
<script>
module.exports {
data: function () {
message: 'Hello Vue!',
show: false
}
}
</script>

v-if and v-else not working in nested v-for list

I have a nested v-for of item
<div class="media" v-for="(comment, parentIndex) in adminComments">
<div class="media-body">
<div class="media" v-for="(answer, index) in comment">
<label class="control-label upload" v-if="comment.data===''">
<input class="file-upload" type="file" #change="uploadFile($event, parentIndex)">
Upload file
</label>
<label class="control-label upload" v-else>
<input class="file-upload" type="file" #change="uploadFile($event, parentIndex)">
{{comment.name}}
</label>
</div>
</div>
</div>
This is basically it, my adminComments is an array of objects and these objects have some attrs, including name, however, this name is changed with a function after the file is uploaded as well as a "loading" attribute to change an icon class, however, none of them is rendering.
As i read here the labels should be rendered well, however, this is not happening. I know that my comment object is indeed working because I also have a textarea with a v-model="comment.response". What could be wrong? I have done the same before and it has worked but in a single v-for and not in a nested list. Thanks in advance