Vue / Buefy Datetimpciker: How can I submit the results of an vue compontent to a form? - vue.js

For my new website project I wanted to use a datetime picker in a html form. As i use Bulma as CSS framework, I want to use the buefy datetimepicker https://buefy.org/documentation/datetimepicker, which is using vue.
For now, the datetimepicker is displayed nicely on my website, however, I am not able to receiving results when submitting the html form by a POST request.
What do I need to change to make the selected datetime available as a variable in php $_POST variable?
Code on codepen
<form action="submit.php" method="POST">
<div id="app" class="container">
<b-field label="Select datetime">
<b-datetimepicker
rounded
placeholder="Click to select..."
icon="calendar-today"
:locale="locale"
:datepicker="{ showWeekNumber }"
:timepicker="{ enableSeconds, hourFormat }"
horizontal-time-picker>
</b-datetimepicker>
</b-field>
</section>
</div>
<div class="field">
<div class="control">
<button class="button is-primary">Submit</button>
</div>
</div>
</form>
<script>
const example = {
data() {
return {
showWeekNumber: true,
enableSeconds: false,
hourFormat: undefined, // Browser locale
locale: undefined // Browser locale
}
}
}
const app = new Vue(example)
app.$mount('#app')
</script>

You should bind datetimepicker to a variable normally with v-model, then assign that variable to a hidden input field.
In HTML file
<input type="hidden" name="mydate" value="{{ mydate }}" />
<b-datetimepicker
v-model="mydate"
...>
</b-datetimepicker>
In JS file
data() {
...,
mydate: null
}

Related

Get components from custom attributes with vue?

Im usign vue js for validate form before submit.
This code start a new Vue getting data from the ID = app:
const app = new Vue({
el:"#app",
data:{
text: null
}
I want create a custom attribute named form-number and get data usign my
attribute and not the div.
Example:
Change this
<form id="app" method="post">
<input type="text" v-model='text'>
</form>
For this
<form form-number="1" method="post">
<input type="text" v-model='text'>
</form>
const app = new Vue({
el:"form-number='1'",
data:{
text: null
}
In Vue the template is not to be read - inputs are possible through bindings (like v-model).
See this snippet:
const app = new Vue({
data: {
formNumber: 1,
text: ''
}
})
app.$mount('[myCustomAttribute="mounthere"]')
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div myCustomAttribute="mounthere">
<form :form-number="formNumber" method="post">
<label for="text1">
From{{ formNumber }} input:
<input id="text1" type="text" v-model="text" />
</label>
</form>
{{ text }}
</div>
formNumber is also defined in the data attribute and bound to the form-number attribute, which also appears in the HTML.
EDIT
el: "#app" is just a convention for the basic Vue app. You can choose where to mount the app by any valid selector - like [myCustomAttribute="mounthere"] also works.

Vue.js and Bootstrap Modal - Invoking JS

Trying to implement the bootstrap-datepicker in conjunction with Vue, and not quite sure why my solution won't work.
I am using the code example at https://eonasdan.github.io/bootstrap-datetimepicker/
I added a v-on:click on the INPUT that then ties to a method.
TEMPLATE CODE:
<div class="container">
<div class="row">
<div class='col-sm-6'>
<div class="form-group">
<div class='input-group date' id='datetimepicker1'>
<input v-on:click="displayCal" type='text' class="form-control" />
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
</div>
</div>
</div>
VUE
import jquery from 'jquery';
....
methods: {
displayCal: function () {
jquery('#datetimepicker1').datetimepicker();
}
}
Will that help with what I'm trying to do?
Not exactly, I misunderstood and thought that the datepicker is a bootstrap component. Unfortunately it is not, and so while vue implementation of bootstrap could be helpful, it would leave you still with quite a bit to implement yourself.
Option 1
Use a Vue component that has the functionality out of the box
const app = new Vue({
el: '#app',
components: {
vuejsDatepicker
}
})
<div id="app">
<vuejs-datepicker></vuejs-datepicker>
</div>
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/vuejs-datepicker"></script>
Demo: https://codesandbox.io/s/mpklq49wp
If that does what you need then vuejs-datepicker component may be better for you to implement.
Option 2
Get jquery and Vue to talk
This is not ideal, because the two libraries will compete for DOM control. Vue mounts and unmounts of DOM elements are data driven. That means if your data changes, your DOM may replace an element that jquery may be relying on. SO you may be able to get it to work, but based on all the other stuff going on in the app, you may find some odd things happening, that said, here is a way you can do it...
<div id="app">
<div class="container">
<p>
TIMEDATE: {{timedate}}
</p>
<div class="row">
<div class='col-sm-6'>
<input type='text' class="form-control" id='datetimepicker4' />
</div>
</div>
</div>
</div>
const app = new Vue({
el: '#app',
data(){
return{
timedate: new Date(),
}
},
methods:{
onUpdate(e){
this.timedate=e.date;
}
},
mounted() {
const dp = $('#datetimepicker4')
dp.datetimepicker({
defaultDate: this.timedate,
});
dp.on('dp.change', this.onUpdate )
}
})
demo: https://jsfiddle.net/fjk6cLo8/7/
This code will allow you to add the datetime picker with a preset date. Upon change of the date, using the datetime picker, the data will be updated in the vue component (using dp.change listener)
The datetime picker is mounted once right after the component mounts, and the <input type='text' class="form-control" id='datetimepicker4' /> element is available.

Don't see div with v-if, regardless of the value in the data

I have problem with displaying component with v-if.
In one component i have <div v-if="seen">...</div>.
In another component I have <button v-on:click="seen = !seen">...</button>.
In "var vue = nev Vue({...})" file, in data: I have seen: true and this is not working.
I found "solution" which works: example
and I tried this "function version" of data in my code, but it doesn't work too :/
Here is my code:
Main File
var vue = new Vue({
el: '#app',
components: {
Navigation,
Home,
Footer,
Login
},
data: function () {
return {
seen: true
}
},
template: "<div><navigation></navigation><login></login><home></home><Footer></Footer></div>"
})
template that I can't see
<div v-if="seen" id="loginbox">
<form>
<input type="text" placeholder="login" class="input is-rounded"/>
<input type="password" placeholder="password" class="input is-rounded"/>
</form>
</div>
button template
<div class="navbar-menu">
<div class="navbar-start"></div>
<div class="navbar-end">
<p class="nav-item">
<a class="nav-link" v-on:click="seen = !seen">Login</a>
</p>
<p class="nav-item">
<a class="nav-link">Register</a>
</p>
</div>
</div>
I expect that when I click on button, "loginbox" template will be shown.
EDIT:
I did it in half way. I used props (used export default...) in in template that I cannot seen. It not work properly, becouse now I can change value of "seen" only with button which is in this template. I'd like change value of it by button which is in another template.
You should somehow share data between components.
You can do it many ways, but for this case i suggest to use event handling https://v2.vuejs.org/v2/guide/events.html#ad
Edited your sandbox with example - https://codesandbox.io/s/mzq0r2w88j

Using vuejs with existing html

I have a list of elements, rendered server-side.
Each item has a button that changes its status.
<div class="list">
<div class="list-item" data-is-published="1" data-item-id="11">
<div class="item-link">Item 1</div>
<form method="post" class="list-item-form">
<div class="vue-mount">
<input type="submit" name="changeStatus" class="button-unpublish" value="Unpublish">
<!-- some hidden fields -->
</div>
</form>
</div>
<div class="list-item" data-is-published="1" data-item-id="12">
<div class="item-link">Item 2</div>
<form method="post" class="list-item-form">
<div class="vue-mount">
<input type="submit" name="changeStatus" class="button-unpublish" value="Unpublish">
<!-- some hidden fields -->
</div>
</form>
</div>
</div>
I'm using the following code to replace each item with a vue component
var ms = document.querySelectorAll('.vue-mount')
for (var i = 0; i < ms.length; i++) {
new Vue({
render: h => h(SubscriptionButton)
}).$mount(ms[i])
}
And on the component i get the values of data-is-published and data-item-id and set them on the component
<template>
<input
type="submit"
#click.prevent="changeStatus()"
:value="isPublished === 1 ? 'Unpublish' : 'Publish'">
</template>
<script>
export default {
....
created: function () {
const el = this.$root.$el.parentNode.parentNode
const status = el.dataset.isPublished
this.isPublished = parseInt(status)
this.itemID = el.dataset.itemID
}
}
I'm doing it this way to ensure that it works even if javascript is disabled, but the part this.$root.$el.parentNode.parentNode doesn't feel right.
Is the way I'm doing it ok? Are there better ways to achieve the same?
EDIT
I can put the data attributes on the element that vue will mount to and access them with this.$root.$el.dataset.
What I'm not sure about is how compliant to the best practices the use of this.$root.$el is.
You could use Element.closest (with a polyfill if IE support is required)
const el = this.$root.$el.closest("*[data-is-published]");
That avoids having to know the hierarchy depth of the DOM.
Info on MDN
Edited to add:
The appropriateness of using this.$root.$el depends on how you plan to structure the code. If the element you're trying to find is guaranteed to be a parent of the Vue application, then starting the search from $root is fine. If that bothers you, though, starting the search from this.$el instead would work.
The less conventional part of your approach is that it effectively creates a separate Vue application for each .vue-mount

vue js navigate to url with question mark

my Vue js project login template click button it redirects to like this
http://localhost:8080/#/login to http://localhost:8080/?#/login
both Url show interface.
1st Url not set the local storage variable 'token'.
2nd Url is set the local storage variable 'token'.
how to solve it?
Login.vue
<template>
<div class="row col-sm-12">
<form>
<div class="form-group">
<label>Email address:</label>
<input type="email" class="form-control" v-model="email">
</div>
<div class="form-group">
<label>Password:</label>
<input type="password" class="form-control" v-model="password">
</div>
<div class="checkbox">
<label><input type="checkbox"> Remember me</label>
</div>
<button #click="login" type="submit" class="btn btn-success">Submit</button>
</form>
</div>
</template>
<script>
export default{
data(){
return{
email:'',
password:''
}
},
methods: {
login(){
var data = {
email:this.email,
password:this.password
}
this.$http.post("api/auth/login",data)
.then(response => {
this.$auth.setToken(response.body.token)
// console.log(response)
})
}
}
}
</script>
The form is getting submitted as the button you have provided in the form has type="submit" which is the default behaviour of a button present inside form even if you do not add the attribute type="button"
So replace the type submit to button o prevent form submission like this:
<button #click="login" type="button" class="btn btn-success">Submit</button>
I just faced the same issue, and the provided solution did not worked for me (Vue 2.5.17).
I had to add a modifier to the #click event to prevent the default behavior:
<button class="btn btn-primary" #click.prevent="login">Login</button>
Changing the button type to button, you disable default form behaviour, like pressing enter and release submit event.
Just add a modifier to the #submit or #reset event to prevent default behaviour:
<b-form #submit.prevent="onSubmit" #reset.prevent="onReset">
In order to keep the default behaviour of submitting the form using the "Enter" key on the keyboard as well, another solution is:
to keep the type = 'submit' on the button
handle the event parameter on the callback and process it with event.preventDefault(); like that:
login(event){
event.preventDefault()
var data = {
email:this.email,
password:this.password
}
...
}
Event.preventDefault() will prevent the default behaviour which is here to submit the form on the current url with the issue we are dealing with here.
See https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault