How to pass an array values from one function to another function in vuejs? - vue.js

I am trying to get the array values from
"validateBeforeSubmit" function to "saveForm" function. But I am
getting values of "undefined" in "arrlength". Please help me to solve.
This my code in vue.js
export default {
name: '',
data() {
return {}
},
ready: function() {
this.validateBeforeSubmit()
this.saveForm();
},
methods: {
validateBeforeSubmit() {
var fieldsVal = new Array();
var firstName = document.getElementById('firstName').value
var lastName = document.getElementById('lastName').value
var designation = document.getElementById('designation').value
if (firstName != "" && lastName != "" && designation != "") {
fieldsVal.push(firstName);
fieldsVal.push(lastName);
fieldsVal.push(designation);
return fieldsVal;
} else {
fieldsVal.length = 0;
return fieldsVal;
}
return fieldsVal;
},
saveForm() {
var fieldsValArray = this.validateBeforeSubmit();
var arrLength = fieldsValArray.length;
}
}
}

I can see multiple issues in your code:
1) Don't apply jQuery-like approach for getting input values. Use v-model instead. This will simplify your code
<template>
<input v-model="form.firstName" type="text"/>
</template>
<script>
export default {
data: {
form: {
firstName: '',
}
},
methods: {
validateBeforeSubmit() {
// take `firstName` directly from `data` not need for `getElementById`
const firstName = this.form.firstName;
}
},
}
</script>
2) Remove validateBeforeSubmit and saveForm from ready. Ready hook is obsolete in vue#2. And also it makes no sense. It's better to call it on form #submit.
3) It's better to create array using [] syntax instead of new Array()
Why never use new Array in Javascript
4) Always provide name for your component for easier debug
export default {
name: 'ValidationForm',
}
5) I don't know where was an issue but it works. Check this link below. I have updated your code. Try to submit form and check the console:
https://codesandbox.io/s/w6jl619qr5?expanddevtools=1&module=%2Fsrc%2Fcomponents%2FForm.vue

Related

Handle paste event in vue2-editor

I'm using this text editor https://github.com/davidroyer/vue2-editor that is based on Quilljs
I want to handle the paste event so it pastes only the plain text without any format but seems in the documentation that paste is not a supported event by default.
Is there any way to add the paste event?
I've already tried using v-on:paste in the Editor and adding the Quill custom module Clipboard but haven't had any success.
As I didn't find a way of doing it with the library I did it with the DOM
onPaste() {
const x = document.getElementById("removePasteFormat");
console.log(x);
x.addEventListener("paste", (e) => {
e.stopPropagation();
e.preventDefault();
let text = e.clipboardData.getData("text/plain");
// access the clipboard using the api
if (document.queryCommandSupported("insertText")) {
document.execCommand("insertText", false, text);
} else {
document.execCommand("paste", false, text);
}
});
},
Added the id to the div containing the text editors like this:
<div id="removePasteFormat"> *<<Here goes the text editor component>>* </div>
And register the method on mounted()
mounted() {
this.onPaste();
},
I think it would be good to make a plugin.
I made it simple.
src/utils/vue2Plugin/clipboard.ts
import Delta from 'quill/node_modules/quill-delta';
import Clipboard from 'quill/modules/clipboard';
import { Quill } from 'vue2-editor';
export class CustomClipboardPlugin extends Clipboard {
public quill!: Quill;
public options: any = {};
constructor(quill: Quill) {
super(quill, {
matchers: [],
});
this.quill = quill;
this.quill.root.addEventListener('paste', this.onPaste.bind(this), true);
}
onPaste(event: ClipboardEvent) {
event.preventDefault();
event.stopPropagation();
const range = this.quill.getSelection(true);
if (range === null) return;
let _textHtml;
if (event.clipboardData?.getData('text/html')) {
_textHtml = event.clipboardData?.getData('text/html');
} else if (event.clipboardData?.getData('text/plain')) {
_textHtml = `<p>${event.clipboardData?.getData('text/plain')}</p>`;
}
if (_textHtml) {
const pastedDelta = this.quill.clipboard.convert(_textHtml);
const delta = new Delta()
.retain(range.index)
.delete(range.length)
.concat(pastedDelta);
this.quill.updateContents(delta, Quill.sources.USER);
this.quill.setSelection(delta.length() - range.length, 0, Quill.sources.SILENT);
}
}
}
vue file
<template>
...
<VueEditor
...
:custom-modules="customModulesForEditor"
...
/>
...
</template>
// script
import CustomClipboardPlugin fro 'src/utils/vue2Plugin/clipboard.ts';
...
data() {
return {
customModulesForEditor: [{ alias: 'clipboard', module: CustomClipboardPlugin }],
};
},
...
I was wondering the same and came up with the following solution.
1 - Use the :editorOptions option referenced here
<template>
VueEditor(:editorOptions="editorSettings")
</template>
2 - Fill with the module.clipboard module with the option described here
3 - You can then handle the paste with your personal function (applied after quill's matcher). I've written mine following this answer on github
<script>
data() {
return {
editorSettings: {
modules: {
clipboard: {
matchers: [[Node.ELEMENT_NODE, this.customQuillClipboardMatcher]]
}
}
}
}
},
methods: {
customQuillClipboardMatcher(node, delta) {
delta.ops = delta.ops.map((op) => {
return {
insert: op.insert
}
})
return delta
},
}
</script>

How can I use a computed function inside a method function?

Hi I am trying to call a computed function inside a method function.
VueJs Code:
<script>
export default {
created() {
this.isDisabled(0);
},
data: function() {
return {
form: {
branch_office_id: null,
cashier_id: null,
gross_amount: '',
released_tickets: '',
start_ticket: '',
end_ticket: '',
z_inform_number: '',
created_at: '',
support: null,
error_end_bill_number_validation: ''
},
postsSelected: "",
branch_office_posts: [],
cashier_posts: []
}
},
methods: {
checkEndBillNumber() {
if(this.form.start_ticket > this.form.end_ticket) {
this.isDisabled(1);
this.$awn.alert("El número de boleta inicial no puede ser ", {labels: {success: "Error"}});
} else {
this.isDisabled(0);
}
}
},
computed: {
isDisabled(value) {
if(value == 0) {
return true;
} else {
return false;
}
}
}
}
</script>
I am trying to user isDisabled() function inside checkEndBillNumber() method function but when I do that it says:
[Vue warn]: Error in v-on handler: "TypeError: this.isDisabled is not a function"
So I wonder how can I use it? how can I do that? Thanks!
Computed properties as mentioned above are not functions. Hence passing arguments like isDisabled(value) wont work. But you can trick it to anonymously accept the value like this
computed: {
isDisabled() {
return (value) => {
if(value == 0) return true;
else return false;
}
}
}
This way you don't need a data property.
You do not have computed functions, but computed properties! So you have to store the value you want to use as a parameter in your computed property - e.g. in a data attribute, and then use that:
<script>
export default {
created() {
this.disabledParam = 0;
this.isDisabled; // Evaluates to "true" - what do you want with that result?
},
data: function() {
return {
form: {
branch_office_id: null,
cashier_id: null,
gross_amount: '',
released_tickets: '',
start_ticket: '',
end_ticket: '',
z_inform_number: '',
created_at: '',
support: null,
error_end_bill_number_validation: ''
},
postsSelected: "",
branch_office_posts: [],
cashier_posts: [],
disabledParam: null,
}
},
methods: {
checkEndBillNumber() {
if (this.form.start_ticket > this.form.end_ticket) {
this.disabledParam = 1;
this.isDisabled; // Evaluates to "false" - what to you want to do with that value?
this.$awn.alert("El número de boleta inicial no puede ser ", {labels: {success: "Error"}});
} else {
this.disabledParam = 0;
this.isDisabled; // Evaluates to "true" - what to you want to do with that value?
}
}
},
computed: {
isDisabled() {
if (this.disabledParam == 0) {
return true;
} else {
return false;
}
}
}
}
</script>
Also, please note that your calls to isDisabled(1) wouldn't so anything even if you could use them as functions. You should probably do something with the return values of isDisabled.
And you do not need computed properties in this way - in your example, you should simply create isDisabled(value) as another method and call that. But I guess your code is just an example, not your real code. Computed properties usually are being used as values in your template.
My example code is just there to illustrate how you can pass parameters into the code of computed properties. Besides that, your code has some issues.

Want to update my input value with v-model

I am trying to change the value of an hidden input with vue js. I added a v-model to the input and I am trying to update it in a method.
My input looks like this:
<input type="hidden" name="payment_method" v-model="payment_method">
My vue js:
data: function() {
return {
name: '',
payment_method: '',
.
.
.
methods: {
submitAddPaymentMethod(){
window.stripe.handleCardSetup(
this.clientSecret, card, {
payment_method_data: {
//billing_details: { name: cardHolderName.value }
}
}
).then(function(result) {
if(result.error) {
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
// has no effect on my input
this.payment_method = result.setupIntent.payment_method;
this.$refs.form.submit();
}
}.bind(this));
Maybe someone has an idea how to do this. Would appreciate that!
Best
You are getting a different this in the promise callback than the one you're expecting.
Use fat arrow to solve this.
.then(result => {
if(result.error) {
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
// has no effect on my input
this.payment_method = result.setupIntent.payment_method;
this.$refs.form.submit();
}
}
I needed to add nextick() to wait for the DOM to be updated.

Prevent Vue Multiple Select to Store an Empty Array

I want this select multiple to pre-select one option, and not be able to deselect all options.
Whenever the last selected option is deselected it should be reselected. In other words when the user tries to deselect the last selected option it should visually not be deselected.
<template>
<b-select
if="Object.keys(doc).length !== 0 /* wait until firebase has loaded */"
:options="computedOptions"
v-model="model"
multiple
#input="onChange"
/>
</template>
<script>
//import Vue from 'vue'
import { fb } from "../fbconf";
export default {
name: "MyMultiSelect",
props: {
doc: Object, // firestore document
},
data() {
return {
options: []
};
},
firestore() {
var options = fb.db.collection("options");
return {
options: options
};
},
computed: {
computedOptions: function() {
return this.options.map(function(option) {
return {
text: option.name,
value: option.id
};
});
},
// to make sure mySelectedOptions is an array, before this.doc is loaded
// I use the following custom model
// because not using 'get' below causes a warning:
// [Vue warn]: <select multiple v-model="localValue"> expects an Array value for its binding, but got Undefined
model: {
get: function() {
if (!this.doc.hasOwnProperty('mySelectedOptions')) return []; // empty array before this.doc is loaded
else return this.doc['mySelectedOptions'];
},
set: function(newValue) {
// here I can prevent the empty array from being stored
// but visually the user can deselect all options, which is bad UX
//if (Array.isArray(newValue) && newValue.length > 0) this.doc['mySelectedOptions'] = newValue;
}
},
},
methods: {
onChange: function(newValue){
// I can manually store the array as I want here
// but I cannot in any way prevent the user from deselecting all options
if (Array.isArray(newValue) && newValue.length > 0) this.doc['mySelectedOptions'] = newValue;
else {
// none of these reselects the last selected option
var oldValue = this.doc['mySelectedOptions'];
this.doc['mySelectedOptions'] = this.doc['mySelectedOptions'];
//this.$forceUpdate();
//this.$emit("change", newValue);
//Vue.set(this.doc, 'mySelectedOptions', this.doc['mySelectedOptions']);
}
}
}
};
</script>
You could add watcher and when length becomes 0 just add previous value.
watch: {
model(val, oldVal) {
if(val.length == 0 && oldVal.length > 0) {
// take only one item in case there's clear button or etc.
this.model = [oldval[0]];
}
}
}

Vue: Watch array data variable doesnt work

i'm trying to watch an array declarated in data method (the 'validated' variable). I already have a watcher to an input (legal_name) and it works correctly but the array watcher doesnt give any response. Any idea?
export default {
data() {
return {
legal_name : '',
validated: [],
errors: []
}
},
watch: {
validated() {
console.log('modified')
},
legal_name(value) {
this.eventName();
this.legal_name = value;
this.checkLength(value, 3);
}
},
methods: {
checkLength(value, lengthRequired) {
if(value.length < lengthRequired) {
this.errors[name] = `Debes ingresar al menos ${lengthRequired} caracteres`;
this.validated[name] = false;
return false;
}
this.errors[name] = '';
this.validated[name] = true;
return true;
},
eventName() {
name = event.target.name;
}
}
}
You need to call Vue.set() for arrays, and NOT use indexing such as
foo[3]= 'bar'
Vue DOES recognize some operations, such as splice and push, however.
Read more about it here: https://vuejs.org/2016/02/06/common-gotchas/ and here: https://v2.vuejs.org/v2/guide/list.html#Array-Change-Detection
So for your code, and using the Vue handy helper method $set:
this.validated.$set(name, true);
Why...
Javascript does not offer a hook (overload) for the array index operator ([]), so Vue has no way of intercepting it. This is a limitation of Javascript, not Vue. Here's more on that: How would you overload the [] operator in javascript