Simple validation in vue - javascript

I am beginner web developer.
I make my first application in vue project.
I have this code:
<template>
<CRow>
<CCol col="12" lg="6">
<CCard no-header>
<CCardBody>
<h3>
Create Note
</h3>
<CAlert
:show.sync="dismissCountDown"
color="primary"
fade
>
({{ dismissCountDown }}) {{ message }}
</CAlert>
<CInput label="Title" type="text" id="title" placeholder="Title" v-model="note.title"></CInput>
<CInput textarea="true" label="Content" id="content" :rows="9" placeholder="Content.."
v-model="note.content"></CInput>
<CInput label="Applies to date" type="date" id="applies_to_date" v-model="note.applies_to_date"></CInput>
<CSelect id="status_id"
label="Status"
:value.sync="note.status_id"
:plain="true"
:options="statuses"
>
</CSelect>
<CInput label="Note type" type="text" id="note_type" v-model="note.note_type"></CInput>
<template>
<div id="app">
<ckeditor v-model="editorData" :config="editorConfig"></ckeditor>
</div>
</template>
<CButton color="primary" #click="store()">Create</CButton>
<CButton color="primary" #click="goBack">Back</CButton>
</CCardBody>
</CCard>
</CCol>
</CRow>
</template>
import axios from 'axios';
import Vue from 'vue';
import CKEditor from 'ckeditor4-vue';
Vue.use(CKEditor);
export default {
name: 'EditUser',
props: {
caption: {
type: String,
default: 'User id'
},
},
data: () => {
return {
note: {
title: '',
content: '',
applies_to_date: '',
status_id: null,
note_type: '',
},
statuses: [],
message: '',
dismissSecs: 7,
dismissCountDown: 0,
showDismissibleAlert: false,
editorData: '',
editorConfig: {
// The configuration of the editor.
filebrowserImageBrowseUrl: Vue.prototype.$apiAdress+'/api/laravel-filemanager?token=' + localStorage.getItem("api_token"),
filebrowserImageUploadUrl: Vue.prototype.$apiAdress+'/api/laravel-filemanager/upload?type=Images&_token=&token=' + localStorage.getItem("api_token"),
filebrowserBrowseUrl: Vue.prototype.$apiAdress+'/api/laravel-filemanager?type=Files&token=' + localStorage.getItem("api_token"),
filebrowserUploadUrl: Vue.prototype.$apiAdress+'/api/laravel-filemanager/upload?type=Files&_token=&token=' + localStorage.getItem("api_token"),
height: 500,
language: 'pl',
//extraPlugins: 'facebookvideo, youtube, html5video',
editorUrl: "facebookvideo.js",
extraPlugins: 'a11yhelp,about,basicstyles,bidi,blockquote,clipboard,colorbutton,colordialog,contextmenu,copyformatting,dialogadvtab,div,editorplaceholder,elementspath,enterkey,entities,exportpdf,filebrowser,find,flash,floatingspace,font,format,forms,horizontalrule,htmlwriter,iframe,image,indentblock,indentlist,justify,language,link,list,liststyle,magicline,maximize,newpage,pagebreak,pastefromgdocs,pastefromlibreoffice,pastefromword,pastetext,preview,print,removeformat,resize,save,scayt,selectall,showblocks,showborders,smiley,sourcearea,specialchar,stylescombo,tab,table,tableselection,tabletools,templates,toolbar,undo,uploadimage, wysiwygarea,autoembed,image2,embedsemantic',
image2_alignClasses: ['image-align-left', 'image-align-center', 'image-align-right'],
image2_disableResizer: true,
}
}
},
methods: {
goBack() {
this.$router.go(-1)
// this.$router.replace({path: '/users'})
},
store() {
let self = this;
axios.post(this.$apiAdress + '/api/notes?token=' + localStorage.getItem("api_token"),
self.note
)
.then(function (response) {
self.note = {
title: '',
content: '',
applies_to_date: '',
status_id: null,
note_type: '',
};
self.message = 'Successfully created note.';
self.showAlert();
}).catch(function (error) {
if (error.response.data.message == 'The given data was invalid.') {
self.message = '';
for (let key in error.response.data.errors) {
if (error.response.data.errors.hasOwnProperty(key)) {
self.message += error.response.data.errors[key][0] + ' ';
}
}
self.showAlert();
} else {
console.log(error);
self.$router.push({path: 'login'});
}
});
},
countDownChanged(dismissCountDown) {
this.dismissCountDown = dismissCountDown
},
showAlert() {
this.dismissCountDown = this.dismissSecs
},
},
mounted: function () {
let self = this;
axios.get(this.$apiAdress + '/api/notes/create?token=' + localStorage.getItem("api_token"))
.then(function (response) {
self.statuses = response.data;
}).catch(function (error) {
console.log(error);
self.$router.push({path: 'login'});
});
}
}
I need add to my project validation with alert box when input is empty.
I need required for title and content. When user click button "Create" I need check this inputs. If it's empty - then I need show alert().
How can I make it?
Please help me :)

You can make method:
checkInputs() {
if(!this.note.title) {
this.message = 'pls enter title'
this.showAlert()
return true
}
if(!this.note.content) {
this.message = 'pls enter content'
this.showAlert()
return true
}
return false
}
and in store method:
store() {
if(this.checkInputs()) return
...

Related

Vue.js Loop Input [v-model] updating all form elements not just one

I have form data of:
const form = {
title: null,
content: null,
language: {
en: { title: null, content: null },
es: { title: null, content: null }
}
}
My Form inputs
<v-form ref="formEl" #submit.prevent="validate">
<div v-if="Object.keys(form.language).length > 0">
<div v-for="(language, langCode) in form.language" :key="langCode">
<v-text-field
v-model="form.language[langCode].title"
:label="$t('form.title')"
/>
<v-textarea
v-model="form.language[langCode].content"
:label="$t('form.content')"
/>
</div>
</div>
</form>
Now when I change the input of 1 form input, it updates both to be the same.
I tried placed a KEY on each input field, with the same result. Does anyone have any thoughts or direction on this? Much appreciated.
const form = ref(lodash.cloneDeep(state.pages.one))
// GET CONTENT
useFetch(async () => {
loading.value = true
try {
await dispatch('pages/getOne', route.value.params.id).then((res) => {
if (res !== false) {
form.value = lodash.cloneDeep(res)
}
})
} catch(e) {
$system.log({
comp: 'AdminPagesEdit', msg: 'useFetch', val: e
})
} finally {
loading.value = false
}
})

Error: MercadoPago.js - Could not find HTML element for provided id: MPHiddenInputPaymentMethod

I have an Nuxt desktop app here, am i am facing this problem with MERCADO PAGO API.
This is part of the Mercado documentation : https://www.mercadopago.com.br/developers/pt/guides/online-payments/checkout-api/v2/testing
The problem is:
I make use of the index.vue that makes use of the default form from the documentation itself:
<template>
<div >
<form id="form-checkout" >
<input type="text" name="cardNumber" id="form-checkout__cardNumber" />
<input type="text" name="cardExpirationMonth" id="form-checkout__cardExpirationMonth" />
<input type="text" name="cardExpirationYear" id="form-checkout__cardExpirationYear" />
<input type="text" name="cardholderName" id="form-checkout__cardholderName"/>
<input type="email" name="cardholderEmail" id="form-checkout__cardholderEmail"/>
<input type="text" name="securityCode" id="form-checkout__securityCode" />
<select name="issuer" id="form-checkout__issuer"></select>
<select name="identificationType" id="form-checkout__identificationType"></select>
<input type="text" name="identificationNumber" id="form-checkout__identificationNumber"/>
<select name="installments" id="form-checkout__installments"></select>
<button type="submit" id="form-checkout__submit">Pagar</button>
<progress value="0" class="progress-bar">Carregando...</progress>
</form>
</div>
</template>
nuxt.config:
export default{
head:{
...
script: [
{ src: 'https://sdk.mercadopago.com/js/v2' },
{src: "/js/index.js", },
}
}
and the "/js/index.js file in static folder:
//i know the YOU_PUBLIC_KEY must be from the Mercado Pago account, i have one already
const mp = new MercadoPago('YOUR_PUBLIC_KEY', {
locale: 'pt-BR',
})
const cardForm = mp.cardForm({
amount: '100.5',
autoMount: true,
processingMode: 'aggregator',
form: {
id: 'form-checkout',
cardholderName: {
id: 'form-checkout__cardholderName',
placeholder: 'Cardholder name',
},
cardholderEmail: {
id: 'form-checkout__cardholderEmail',
placeholder: 'Email',
},
cardNumber: {
id: 'form-checkout__cardNumber',
placeholder: 'Card number',
},
cardExpirationMonth: {
id: 'form-checkout__cardExpirationMonth',
placeholder: 'MM'
},
cardExpirationYear: {
id: 'form-checkout__cardExpirationYear',
placeholder: 'YYYY'
},
securityCode: {
id: 'form-checkout__securityCode',
placeholder: 'CVV',
},
installments: {
id: 'form-checkout__installments',
placeholder: 'Total installments'
},
identificationType: {
id: 'form-checkout__identificationType',
placeholder: 'Document type'
},
identificationNumber: {
id: 'form-checkout__identificationNumber',
placeholder: 'Document number'
},
issuer: {
id: 'form-checkout__issuer',
placeholder: 'Issuer'
}
},
callbacks: {
onFormMounted: error => {
if (error) return console.warn('Form Mounted handling error: ', error)
console.log('Form mounted')
},
onFormUnmounted: error => {
if (error) return console.warn('Form Unmounted handling error: ', error)
console.log('Form unmounted')
},
onIdentificationTypesReceived: (error, identificationTypes) => {
if (error) return console.warn('identificationTypes handling error: ', error)
console.log('Identification types available: ', identificationTypes)
},
onPaymentMethodsReceived: (error, paymentMethods) => {
if (error) return console.warn('paymentMethods handling error: ', error)
console.log('Payment Methods available: ', paymentMethods)
},
onIssuersReceived: (error, issuers) => {
if (error) return console.warn('issuers handling error: ', error)
console.log('Issuers available: ', issuers)
},
onInstallmentsReceived: (error, installments) => {
if (error) return console.warn('installments handling error: ', error)
console.log('Installments available: ', installments)
},
onCardTokenReceived: (error, token) => {
if (error) return console.warn('Token handling error: ', error)
console.log('Token available: ', token)
},
onSubmit: (event) => {
event.preventDefault();
const cardData = cardForm.getCardFormData();
console.log('CardForm data available: ', cardData)
},
onFetching: (resource) => {
console.log('Fetching resource: ', resource)
// Animate progress bar
const progressBar = document.querySelector('.progress-bar')
progressBar.removeAttribute('value')
return () => {
progressBar.setAttribute('value', '0')
}
},
}
})
Anyone can help me with this? And is facing more problems with the MERCADO PAGO's API?
Thanks for the atention!
Use iframe to render custom vanilla HTML/CSS/JS.
I'm using vue/quasar2 and my workaround was using an Iframe to render a custom page which can use this lib, you can see the directory structure here.
I created a page to and use an iframe tag to render the custom page:
<template>
<q-page class="flex flex-center">
<iframe width="100%" height="545vh" style="border: none;" :src='`static_site/index.html?obj=${JSON.stringify(getQueryParameters())}`'/>
</q-page>
</template>
<script>
import { defineComponent } from 'vue';
export default defineComponent({
name: 'PageIndex',
setup () {
function getQueryParameters () {
return {
name: "name",
email: "name#gmail.com",
valor: "20"
}
}
return {
getQueryParameters,
}
}
})
</script>
I'm using the query parameters ( obj ) in the iframe src to pass down information from vue to the lib. In the callbacks section of the cardForm function, I used the URLSearchParams object to catch the information I sended, you can see it here.
OBS: I just found this workaround yesterday and haven't tested in production yet, but in dev it's working fine, will test soon in production and update this answer, hope it's useful to you.

Extracting data from an API in typescript vue and to a prop

I need some help guys. Anytime I've done this I've used a v-for and extracted the data manually. The problem I am facing here is that the component I am passing the data to is a custom component already written to accept the data in an :options prop. But all I am getting is "null" for every piece of state.
Here is the template
<WDropDown label="Commissioner" :options="dropdownCommissionerValues" v-model="commissioner1"/>
And the script lang="ts"
// Data Section
apiInvoker= methods; //this is coming from a service file that logs to the API
public commissioner1 = "1";
dropdownCommissionerValues= [];
mounted () {
this.apiInvoker.viewRequestGet("resources/GetCommisionerList").then((response) => {
if(response.data) {
this.dropdownCommissionerValues = response.data.Table;
console.log("My Response is", this.dropdownCommissionerValues);
}
});
}
Inspecting the Vue Dev Tool, and the console, I am connecting to the API and I am getting data in the component. See image below
But this is what I am getting in the browser See image
NOTE, If I hardcode my data in dropdownCommissionerValues as shown below, it get it to work. But I need it to come from the API
this.dropdownCommissionerValues= [
{
value:"1",
text:"Something 1"
},
{
value:"2",
text:"Something 2"
}
]
I assume somehow I have to pass CommissionerId as value and CommissionerName as text because that's how the component reads it? I just can't figure out how
Thanks in advance!
Here is the custom component
<template>
<ValidationProvider :vid="id" :name="id" :rules="rules" v-slot="wDropDown">
<wFormGroup :class="classObject"
:id="groupId('lbl', id)"
:label="label"
:label-for="id"
:label-sr-only="labelSrOnly">
<template v-if="(pagePlaintext || plaintext || isPlaintext) && !dropDownBind">
<b-form-input plaintext
aria-readonly="true"
readonly="readonly"
:aria-label="label"
:data-vv-as="label"
:id="id"
:name="name"
:type="type"
:value="refDataValue" />
</template>
<template v-else-if="dropDownBind">
<div :class="divClass">
<b-form-select class="attachedSelect"
:id="id"
:aria-label="label"
:aria-required="required"
:data-vv-as="label"
:data-vv-name="label"
:data-vv-scope="scope"
:class="{ 'is-invalid': wDropDown.errors.length > 0 }"
:disabled="disabled || arcDisabledObj"
:label="label"
:multiple="multiple"
:name="name"
:options="options"
:select-size="selectSize"
:text-field="selectText"
v-model="computedVal"
:value-field="selectValue"
#input="onInput">
<template slot="first" v-if="!(multiple) && displayFirstSlot">
<option v-if="customFirstSlotValue !== null"
:value="customFirstSlotValue">
{{placeholderText}}
</option>
<option v-else-if="computedVal !==null && computedVal !== undefined && computedVal.length ===0"
computedVal>
{{placeholderText}}
</option>
<option v-else :value="null">{{placeholderText}}</option>
</template>
</b-form-select>
</div>
</template>
<template v-else>
<div :class="divClass">
<b-form-select class="form-control"
:id="id"
:aria-label="label"
:aria-required="required"
:data-vv-as="label"
:data-vv-name="label"
:data-vv-scope="scope"
:class="{ 'is-invalid': wDropDown.errors.length > 0 }"
:disabled="disabled || arcDisabledObj"
:label="label"
:multiple="multiple"
:name="name"
:options="options"
v-model="computedVal"
:select-size="selectSize"
:text-field="selectText"
:value-field="selectValue"
#input="onInput">
<template slot="first" v-if="!(multiple) && displayFirstSlot">
<option v-if="customFirstSlotValue !== null"
:value="customFirstSlotValue">
{{placeholderText}}
</option>
<option v-else-if="computedVal !==null && computedVal !== undefined && computedVal.length ===0"
computedVal>
{{placeholderText}}
</option>
<option v-else :value="null">{{placeholderText}}</option>
</template>
</b-form-select>
</div>
</template>
<b-form-text v-if="helpText" :id="groupId('hlp', id)">{{helpText}}</b-form-text>
<div class="invalid-feedback" v-if="wDropDown.errors.length > 0">{{ Message }}</div>
<!-- {{ isRequired && (!plaintext && !pagePlaintext) }} {{ isRequired }} {{ plaintext}} {{ overridePageMode }} -->
</wFormGroup>
</ValidationProvider>
</template>
<script>
import uuid from "uuid/v1";
import { groupId } from "#/helpers";
import { classObject } from "#/computed";
import { pagePlaintext } from "#/mixins";
/*
[DEPRECATED]: Left in to support Organization page. Do not use otherwise.
This should be removed in the future.
*/
import { arcInputStateMixin } from "#/components/mixins/UI/inputStateMixin";
export default {
data () {
return {
scope: uuid(),
Message: 'This field is required.',
};
},
methods: {
groupId,
onInput (value) {
this.$emit("input", value);
},
getSelectedDataValue (options, keyValue, keyField, valueField) {
let result = null;
let response = null;
console.log(options);
console.log(keyValue);
console.log(keyField);
console.log(valueField);
console.log(keyValue !== undefined && keyValue !== null);
if(keyValue !== undefined && keyValue !== null) {
response = options.filter(option => option[keyField].toString() === keyValue.toString());
}
console.log('wDropDown', this.id);
console.log(response);
if (this.isNotNullOrUndefined(response)) {
result = response[0][valueField] || null;
}
return result !== null ? result : this.readOnlyValue;
},
},
mixins: [arcInputStateMixin, pagePlaintext],
model: {
event: "input",
prop: "value",
},
name: "wDropDown",
props: {
isRequired: Boolean,
dropDownBind: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
},
displayonly: {
type: String,
},
helpText: {
type: String,
},
id: {
required: true,
type: String,
},
inputState: {
type: String,
},
label: {
required: true,
type: String,
},
labelFor: {
type: String,
},
labelSrOnly: {
type: Boolean,
},
maxlength: {
type: String,
},
multiple: {
type: [String, Boolean],
default: false,
},
name: {
type: String,
},
options: {
default () {
return [];
},
type: [Array, String],
},
placeholderText: {
type: String,
default: "- Select One -",
},
plaintext: {
type: Boolean,
},
required: {
type: Boolean,
},
selectSize: {
type: String,
},
selectText: {
type: String,
default: "text",
},
selectValue: {
type: String,
default: "value",
},
type: {
type: String,
},
value: {
type: [Number, String, Array],
default: null,
},
validation: {
type: String,
},
customFirstSlotValue: {
type: [String, Number],
default: null,
},
displayFirstSlot: {
type: [String, Boolean],
default: true,
},
lookUpTableName: {
type: String,
},
overridePageMode: {
type: Boolean,
default: false,
},
readOnlyValue: {
type: String,
},
},
computed: {
rules () {
return (this.isRequired && (!this.plaintext && !this.pagePlaintext) ) ? "required" : "";
},
computedVal: {
get () {
return this.value;
},
set (val) {
return val;
},
},
classObject,
refDataValue () {
return this.getSelectedDataValue(
this.options,
this.computedVal,
this.selectValue,
this.selectText,
);
},
divClass () {
return this.multiple
? "multiSelect"
: (this.disabled || this.arcDisabledObj) === true
? "disable"
: "autofill";
},
},
beforeDestroy () {
//this.$store.commit("Common/SET_ADDRESS_MIXIN_COUNT", 0);
},
};
</script>
The custom component has selectValue and selectText props, which allows setting the b-form-select's value-field and text-field, respectively. You could set those to the desired values without having to remap your data:
<WDropDown :options="dropdownCommissionerValues"
selectText="CommissionerName"
selectValue="CommissionerId"
/>
demo
While not familiar with boostrapVue you could add keys (text and value) either after api call or from the component and using a computed.
Something like:
this.dropdownCommissionerValues = response.data.Table.map(option=>{
option.text=option.commissionerName
option.value=option.commissionerValue
delete option.commissionerName // optional .... clean up the object
delete option.commissionerValue // optional .... clean up the object
return option
})

Vue component watch

all how i can watch changes in my component in data?
I need watch when user choose car brand to take from server models for that brand
this is my code
Templete
<template>
<div class="category-info">
<div v-for="input in inputs.text">
<label >{{ input.placeholder}}</label>
<input type="text" id="location" :name="input.name" v-model="input.value" #click="console">
</div>
<div class="select" v-for="select in inputs.select">
<label >{{ select.placeholder }}</label>
<my-select :data="select" v-model="select.value"></my-select>
</div>
<button #click="console">click</button>
</div>
Script
<script>
export default {
name: "profile-add-inputs",
props: ['category'],
data() {
return {
inputs: {
text : {},
select: {}
},
}
},
methods: {
getCategories(){
axios.get('/profile/inputs', {
params: {
category: JSON.stringify(this.category.href)
}
})
.then((response) => {
this.inputs.text = response.data.text;
this.inputs.select = response.data.select;
for(let key in this.inputs.text){
this.inputs.text[key].value = '';
}
for(let key in this.inputs.select){
this.inputs.select[key].value = '';
if(this.category.href.sub == 'car' && this.inputs.select[key].name == 'brand'){
console.log('CAR BREND');
this.$watch.inputs.select[key].value = function () {
console.log(this.inputs.select[key].value);
}
}
}
},this)
.catch(function (error) {
console.log(error);
});
},
console(){
console.log(this.inputs.select);
}
},
watch: {
category : function () {
this.getCategories();
console.log('categoty');
},
inputs : {
handler() {
console.log('watch inputs');
}
}
}
}
So, i tried to use watch and $watch but its not working, plz give me a reason why that not work, or maybe some another way to resolve this problem
this.$watch can i create dynamiclly watchers with this stement?
The correct syntax is
watch : {
inputs : function(val, oldVal){
//val : New value
//oldVal : Previous value.
}
}

method on the server side is invoked two times, why?

I have problem with method on the server side. It is invoked two times, but it should only one. Error occur when I change password. To change password I use Accounts.setpassword(). Below code of that method:
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import { TAPi18n } from 'meteor/tap:i18n';
import { Accounts } from 'meteor/accounts-base';
import _ from 'lodash';
Meteor.methods({
'users/change-user-settings'(formData) {
if (!this.userId) {
throw new Meteor.Error(401, TAPi18n.__('errors.you_are_not_logged'));
}
check(formData, App.Schemas.userSettingsSchema);
//change password
if (formData.password) {
Accounts.setPassword(this.userId, formData.password, {logout: false});
}
//change email
if (formData.email) {
Meteor.users.update({_id: this.userId}, {
$set: {
'emails.0.address': formData.email
}
});
}
//change phone number
if (formData.phoneNumber) {
Meteor.users.update({_id: this.userId}, {
$set: {
'phoneNumber': formData.phoneNumber
}
});
}
return true;
}
});
My autoform form and schema to it:
<template name="userSettingsTemplate">
<div class="user-settings-form-wrapper">
<h4>Change settings</h4>
{{ #autoForm id="userSettingsForm" type="method" meteormethod="users/change-user-settings" schema=getUserSettingsSchema class="form-horizontal"}}
{{ > afQuickField name="password" label="Change password: " template="bootstrap3-horizontal" label-class="col-xs-6" input-col-class="col-xs-6"}}
{{ > afQuickField name="passwordConfirmation" label="Confirm password: " template="bootstrap3-horizontal" label-class="col-xs-6" input-col-class="col-xs-6"}}
{{ > afQuickField name="email" label="E-mail: " template="bootstrap3-horizontal" label-class="col-xs-6" input-col-class="col-xs-6"}}
{{ > afQuickField name="phoneNumber" label="Phone number: " template="bootstrap3-horizontal" label-class="col-xs-6" input-col-class="col-xs-6"}}
<div class="form-group">
<button type="submit" class="btn btn-primary full-width">Send</button>
</div>
{{ / autoForm }}
</div>
</template>
Schema:
import { SimpleSchema } from 'meteor/aldeed:simple-schema';
import { TAPi18n } from 'meteor/tap:i18n';
import { Meteor } from 'meteor/meteor';
Meteor.startup(() => {
// for running tests this is temporary workaround
try {
SimpleSchema.messages({
"passwordMismatch": "passwords are not the same"
});
}
catch (e) {
console.log(e.message, e.name, e.stack);
}
});
App.Schemas.userSettingsSchema = new SimpleSchema({
password: {
type: String,
optional: true,
min: 6,
autoform: {
type: "password"
}
},
passwordConfirmation: {
type: String,
min: 6,
optional: true,
autoform: {
type: "password"
},
custom: function() {
if (this.value !== this.field('password').value) {
return "passwordMismatch";
}
}
},
email: {
type: String,
optional: true,
regEx: SimpleSchema.RegEx.Email
},
phoneNumber: {
type: String,
optional: true
}
});
Just a side note. Unless I'm missing something here, you should not be using Accounts.setPassword() like that. It's a server side method, so the new password gets sent as plain text over the wire. Instead, take a look at Accounts.changePassword(), which runs on client and is meant to do what you want to do.

Categories

Resources