I'm stuck trying to work out how to initialize a local "signaturePad" canvas for every loop / signature required.
I'm also keen to bind "dataURL" to signaturePad.toDataURL("image/jpg"). I.e. show the dataURI for each signature entered.
Hope you can help! Here's the JSfiddle too: https://jsfiddle.net/kaihendry/kt53sa2r/1/
// var canvas = document.querySelector("canvas");
// var signaturePad = new SignaturePad(canvas);
// var wrapper = document.getElementById("signature-pad");
// How do I initialise signaturePad for every signatureNeeded?
new Vue({
el: "#app",
data: {
signaturesNeeded: 2,
},
methods: {
submitForm: function(x) {
fetch('/echo/html', {
method: 'POST',
body: new FormData(x.target)
})
.then(() => {
var button = document.getElementById("button")
button.innerText = 'Sent!'
})
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/signature_pad#2.3.2/dist/signature_pad.min.js"></script>
<div id="app">
<label>Number of signatures required
<input type=number v-model.number="signaturesNeeded">
</label>
<form id="myForm" v-on:submit.prevent="submitForm">
<template v-for="item in signaturesNeeded">
<div class="signature-pad">
<div class="signature-pad--body">
<canvas></canvas>
</div>
<div class="signature-pad--footer">
<div class="description">Sign above</div>
</div>
<input required type=text size=80 placeholder="Name" name=name>
<input required type=text size=80 name=dataURL>
</template>
<button class="button" id="button" type="submit">Sign</button>
</form>
Signature pad sources
</div>
You can define custom component (signature-pad for example) and initialize SignaturePad there. I created working snippet below. It also update signature data url when user stops writing(it shows below the canvas) and as example all urls are collected by parent component. Check it:
Vue.component('signature-pad', {
template: '#signaturepad',
data() {
return {
signaturePad: null,
dataUrl: null
}
},
mounted() {
this.signaturePad = new SignaturePad(this.$refs.canv, {
onEnd: () => {
this.dataUrl = this.signaturePad.toDataURL();
// as example collect all url in parent
this.$emit('update', this.dataUrl)
}
});
}
});
new Vue({
el: "#app",
data: {
signaturesNeeded: 2,
// all signature urls as example
signatureDataUris: []
},
methods: {
submitForm: function (x) {
fetch('/echo/html', { method: 'POST',
body: new FormData(x.target) })
.then(() => {
var button = document.getElementById("button")
button.innerText = 'Sent!'
})
},
updateSignature(index, url) {
Vue.set(this.signatureDataUris, index, url);
console.log(this.signatureDataUris);
}
}
})
<script src="https://cdn.jsdelivr.net/npm/signature_pad#2.3.2/dist/signature_pad.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
<label>Number of signatures required
<input type=number v-model.number="signaturesNeeded">
</label>
<form id="myForm" v-on:submit.prevent="submitForm">
<template v-for="item in signaturesNeeded">
<signature-pad #update="(val) => updateSignature(item-1, val)" ></signature-pad>
<input required type=text size=80 placeholder="Name" name=name>
</template>
<button class="button" id="button" type="submit">Sign</button>
</form>
Signature pad sources
</div>
<script type='text/x-template' id="signaturepad">
<div class="signature-pad">
<div class="signature-pad--body">
<canvas ref="canv"></canvas>
<div>{{dataUrl}}</div>
</div>
<div class="signature-pad--footer">
<div class="description">Sign above</div>
</div>
</div>
</script>
Related
I am using Vue.js and Axios.
I have two inputs on my html page for selecting an image. There is also a form. The two inputs and the form are separate and independent.
When I select an image, the image is automatically uploaded to the server.
The challenge is how to make it impossible to submit the form until at least one image is selected?
Tell me how to do this?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Add Item</title>
<script src="https://unpkg.com/vue#next"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<form name="addItem" method="post" action="/user/addItem">
<label for="name">name</label>
<input type="text" id="name">
<button type="submit" id="submit">Save Item</button>
</form>
<form #submit.prevent enctype="multipart/form-data">
<input type="file" ref="file1" #change="selectFile1">
</form>
<form #submit.prevent enctype="multipart/form-data">
<input type="file" ref="file2" #change="selectFile2">
</form>
</div>
<script>
const addProduct = {
name: "addProduct",
data() {
return{
file1: "",
image1:"",
file2: "",
image2: "",
}
},
methods:{
async selectFile1(){
const formData = new FormData();
this.file1 = this.$refs.file1.files[0];
formData.append('file', this.file1);
await axios.post('/user/uploadImage', formData)
},
async selectFile2(){
const formData = new FormData();
this.file2 = this.$refs.file2.files[0];
formData.append('file', this.file2);
await axios.post('/user/uploadImage', formData)
}
}
}
Vue.createApp(addProduct).mount('#app')
</script>
</body>
</html>
<form name="addItem" method="post" action="/user/addItem">
<label for="name">name</label>
<input type="text" id="name">
<button type="submit" #click="submitForm" id="submit">Save Item</button>
</form>
<script>
...
submitForm(e) {
if (!this.file1 && !this.file2) e.preventDefault()
}
...
</script>
By default your form submit button is disabled until any one of the file has been selected
Step 1: HTML template like
<template>
<div id="app">
<form name="addItem" #submit.prevent="submit">
<div class="row">
<label for="name">Name</label>
<input type="text" id="name" />
</div>
<div class="row">
<input type="file" ref="file1" #change="selectFile1" />
</div>
<div class="row">
<input type="file" ref="file2" #change="selectFile2" />
</div>
<div class="row">
<button type="submit" id="submit" :disabled="!this.file1 && !this.file2">Save Item</button>
<button type="button" #click.prevent="reset">Reset</button>
</div>
</form>
</div>
</template>
Step 2: methods like
methods: {
submit() {
if (!this.file1 && !this.file2) {
return false;
} else {
const savedata = {
name: this.name,
};
axios.post("/user/addItem", savedata);
}
},
async selectFile1() {
const formData = new FormData();
this.file1 = this.$refs.file1.files[0];
formData.append("file", this.file1);
await axios.post("/user/uploadImage", formData, {
headers: { "Content-Type": "multipart/form-data" },
});
},
async selectFile2() {
const formData = new FormData();
this.file2 = this.$refs.file2.files[0];
formData.append("file", this.file2);
await axios.post("/user/uploadImage", formData, {
headers: { "Content-Type": "multipart/form-data" },
});
},
reset() {
this.name = "";
this.$refs.file1.value = null;
this.$refs.file2.value = null;
this.file1 = "";
this.file2 = "";
},
},
DEMO Link
I have a basic input that should update a data on input change, but it doesn't because it returns Uncaught TypeError: Cannot read property 'settings' of undefined
Vue component
<template>
<div>
<div class="inner_container">
<p>
URL:
<span>{{settings.url}}</span>
</p>
<div class="input_row">
<input
class="input_text"
id="getURL"
type="url"
inputmode="url"
placeholder="Enter URL"
title="URL"
#input="changeUrl"
/>
<label class="label_" for="getURL">URL Link</label>
</div>
<button class="button" #click="saveSettings">Save all Values</button>
</div>
<div>
</template>
<script>
import axios from "axios";
import _ from "lodash";
export default {
name: "Home",
data() {
return {
settings: {
brightness: "",
},
};
},
methods: {
changeUrl: _.debounce((e) => {
this.settings.url = e.target.value;
}, 500),
},
};
</script>
On each input change I receive the above error.
What am I doing wrong ?
The problem is that this in the arrow function is not referring to the object you want. One solution is to use a normal function and predefine the property url in settings:
new Vue({
el: '#app',
data() {
return {
settings: {
brightness: "",
url: ""
},
};
},
methods: {
changeUrl: _.debounce(function(e) {
this.settings.url = e.target.value;
}, 500),
saveSettings(){
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.19/lodash.min.js"></script>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<div id="app">
<div class="inner_container">
<p>
URL: <span>{{settings.url}}</span>
</p>
<div class="input_row">
<input
class="input_text"
id="getURL"
type="url"
inputmode="url"
placeholder="Enter URL"
title="URL"
#input="changeUrl"
/>
<label class="label_" for="getURL">URL Link</label>
</div>
<button class="button" #click="saveSettings">Save all Values</button>
</div>
</div>
A simpler approach you may find useful is to set the variable using v-model:
new Vue({
el: '#app',
data() {
return {
settings: {
brightness: "",
},
};
},
methods: {
saveSettings(){
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.19/lodash.min.js"></script>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<div id="app">
<div class="inner_container">
<p>
URL: <span>{{settings.url}}</span>
</p>
<div class="input_row">
<input
class="input_text"
id="getURL"
type="url"
inputmode="url"
placeholder="Enter URL"
title="URL"
v-model="settings.url"
/>
<label class="label_" for="getURL">URL Link</label>
</div>
<button class="button" #click="saveSettings">Save all Values</button>
</div>
</div>
Ciao, try to use debounce like this:
_.debounce(function(e) {
this.settings.url = e.target.value;
}, 500)
The problem is that you are using this in a statement that is not being called on a JS class. Fix this by changing the this to a variable name, and setting that variable name to a class.
i have chuck of code in vue js.. I am not able to get value from input
here is my code
HTML Codes:
<div id = "app">
<div class="form-group">
<input type="text" class="form-control" name = "name" value = "lorem" v-model = "name"/>
</div>
<button class="btn btn-primary btn-block" v-on:click="sendData()">SIGN UP</button>
</div>
Vue js codes:
<script>
var app = new Vue({
el: "#app",
data() {
errors :{}
return {
input: {
name: "",
},
}
},
methods: {
sendData() {
alert(this.name);
}
}
})
Thanks
As the declare for the data properties, uses v-model="input.name", then alert(this.input.name).
If you'd like to assign default value for the input, decalre the data property like {input:{name: 'lorem'}}.
var app = new Vue({
el: "#app",
data() {
errors: {}
return {
input: {
name: "", // or pre-fill with other default value like `lorem`
},
}
},
methods: {
sendData() {
alert(this.input.name);
}
}
})
<script src="https://unpkg.com/vue#2.5.16/dist/vue.js"></script>
<div id="app">
<div class="form-group">
<input type="text" class="form-control" name="name" value="lorem" v-model="input.name" />
</div>
<button class="btn btn-primary btn-block" v-on:click="sendData()">SIGN UP</button>
</div>
Use v-model only, without value attribute:
<div id = "app">
<div class="form-group">
<input
type="text"
class="form-control"
name="name"
v-model="name"
/>
</div>
<button
class="btn btn-primary btn-block"
#click="sendData"
>
SIGN UP
</button>
</div>
<script>
var app = new Vue({
el: "#app",
data () {
return {
name: 'lorem'
}
},
methods: {
sendData () {
alert(this.name)
}
}
})
</script>
My vue component like this :
<template>
<div>
...
<form class="form-horizontal" id="form-profile">
...
<input type="number" class="form-control" required>
...
<button type="submit" class="btn btn-primary" #click="submit">Submit</button>
...
</form>
...
</div>
</template>
<script>
export default {
...
methods: {
submit(e) {
e.preventDefault()
if (this.checkForm()) {
// do ajax here
}
},
checkForm() {
let field = true
$('#form-profile :required').each(function(i) {
if(this.checkValidity() == false)
field = false
})
return field
},
}
}
</script>
I using required html5 to validation
I using e.preventDefault() to prevent page redirects. Because I want to using ajax
My problem here is the required validation html5 not show if not filled. Maybe it because I using e.preventDefault()
How can I display the required html5?
In order to work as expected you have to set the v-on:submit method on the form tag, and have a button/input type "submit".
Also, notice the event modifier prevent on the #submit, it's a shorcut to not have to write e.preventDefault() on the method
new Vue({
el: '#app',
data() {
return {
myText: ''
}
},
methods: {
submitForm() {
alert('submited: ' + this.myText)
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.15/vue.js"></script>
<div id="app">
<form #submit.prevent="submitForm">
<input type="text" v-model="myText" required />
<button type="submit">Submit</button>
</form>
</div>
1.i want to remove Link in the method from a vue.js component
please helm me..error in console is method splice is undefined.
link will add when the message in insert.message is not a problem.
insert link in not a problem.but it's not possible to remove.
push array in my single page.but if is not good for the user is possible to remove
<div class="list-group">
<div class="col-lg-4" style="margin-
top:3px">
<input type="text" v-model="link.title"
class="form-control" placeholder="titolo" id="title">
</div>
<div class="col-lg-7">
<input type="text" v-model="link.hyperlink"
class="form-control" placeholder="link" id="link">
</div>
<div class="col-lg-1">
<button #click="addLink" type="button"
id="add-link-btn" class="btn btn btn-primary pull-
right">+</button>
</div>
</div>
</div>
<div v-for="link in message.links"
:key="link.id">
<div class="row">
<div class="col-lg-6">
<p>{{link.title}}</p>
</div>
<div class="col-lg-6">
<a>{{link.hyperlink}}</a>
<button class="btn btn-xs btn-danger"
#click="removeLink(link)">Delete</button>
</div>
</div>
<scrip>
data() {
return {
title: "Aggiungi",
link: {
id: 1,
autore: "Amedeo",
title: "",
hyperlink: ""
},
}
}
methods: {
addMessage() {
var id = this.messages.length
? this.messages[this.messages.length - 1].id
: 0;
var message = Object.assign({}, this.message);
message.id = id + 1;
message.date = new Date();
this.messages.push(message);
this.message.title = "";
this.message.subtitle = "";
this.message.body = "";
},
// metodo addlink che inserisci un nuovo link ovvimente lavorando
sul id del messaggio padre
addLink() {
var messageId = this.messages.length
? this.messages[this.messages.length - 1].id
: 1;
var id = this.message.links.length
? this.message.links[this.message.links.length - 1].id
: parseInt(messageId + "0", 10);
var link = Object.assign({}, this.link);
link.id = id + 1;
link.date = new Date();
this.message.links.push(link);
this.link.title = "";
this.link.hyperlink = "";
},
removeLink(link) {
this.links.splice(this.links.indexOf(link), 1);
}
}
};
You need to pre-define every property you will access in data.
Due to the limitations of modern JavaScript (and the abandonment of
Object.observe), Vue cannot detect property addition or deletion.
https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats
In your code messages and links are not defined in your data object at the start, so the reactivity will not work.
For example, the following code doesn't work :
<div id="app">
Message: {{message}}<br />
<input type="text" v-on:input="update($event.target.value)" />
</div>
<script>
new Vue({
el: '#app',
data: {
},
methods: {
update: function(value) {
this.message = value;
}
}
});
</script>
https://jsfiddle.net/m4q44g7f/
But this code works because message is defined at the start.
<div id="app">
Message: {{message}}<br />
<input type="text" v-on:input="update($event.target.value)" />
</div>
<script>
new Vue({
el: '#app',
data: {
message: ''
},
methods: {
update: function(value) {
this.message = value;
}
}
});
</script>
https://jsfiddle.net/m4q44g7f/1/
Note: There might be other errors in your code but you first need to fix this one.