Using nuxt.js google recaptcha module - vue.js

There is a problem that is wasting too much time. I installed the Nuxt js recaptcha module. but the information given in the documentation is insufficient. I haven't used recaptcha before. How exactly should I use it.
<template>
<div class="mx-auto mt-5" style="width: 500px; max-width:90%">
<div class="mx-auto mt-5" style="width: 230px;">
<img
src="#/assets/media/images/site/logo.png"
style="width: 110px"
/>.com'a Üye Olun
</div>
<div class="bg-white p-4 mt-2" style="border-radius:20px">
<b-form #submit.prevent="onSubmit" #reset="onReset" v-if="show">
<b-form-group id="input-group-2" label-for="input-2">
<b-form-input
id="input-2"
class="form-control form-control-lg"
v-model="form.userFullName"
placeholder="İsim soyisim"
required
></b-form-input>
</b-form-group>
<b-form-group id="input-group-2" label-for="input-2">
<b-form-input
id="input-5"
class="form-control form-control-lg"
v-model="form.userName"
placeholder="Kullanıcı adı"
required
></b-form-input>
</b-form-group>
<b-form-row>
<b-col>
<b-form-input
id="input-1"
v-model="form.userEmail"
type="email"
class="form-control form-control-lg"
placeholder="E-mail adresiniz"
required
></b-form-input>
</b-col>
<b-col>
<b-form-input
id="input-3"
v-model="form.userPassword"
class="form-control form-control-lg"
placeholder="Şifreniz"
required
></b-form-input>
</b-col>
</b-form-row>
<b-form-group
id="input-group-4"
class="mt-3"
v-slot="{ ariaDescribedby }"
>
<b-form-checkbox-group
v-model="form.checked"
id="checkboxes-4"
:aria-describedby="ariaDescribedby"
>
<b-form-checkbox class="text-dark" value="1"
>Beni Hatırla</b-form-checkbox
>
</b-form-checkbox-group>
</b-form-group>
<b-button
:disabled="isClickSubmit"
type="submit"
class="btn btn-dark btn-lg btn-block"
variant="primary"
>
<b-spinner v-if="isClickSubmit" small style="margin-bottom:3px" type="grow"></b-spinner>
Kaydol</b-button
>
</b-form>
</div>
</div>
</template>
import axios from "axios";
export default {
layout: "default",
data() {
return {
isClickSubmit: false,
form: {
userEmail: "",
userFullName: "",
userName: "",
userPassword: null
},
show: true
};
},
methods: {
async mounted() {
try {
const bune = await this.$recaptcha.init();
console.log(bune);
} catch (e) {
console.log(e);
}
},
async onSubmit(event) {
this.isClickSubmit = true;
this.onReset();
try {
console.log(this.$recaptcha);
const token = await this.$recaptcha.execute("login");
console.log("ReCaptcha token:", token);
// await this.$recaptcha.reset()
const form = this.form;
const sonuc = await axios.post("http://localhost:3000/api/users", {
form
});
this.isClickSubmit = false
} catch (error) {
console.log("Login error:", error);
}
// console.log(JSON.stringify(this.form));
},
onReset() {
this.form.userEmail = "";
this.form.userFullName = "";
this.form.userName = "";
this.form.userPassword = null
}
}
};
nuxt.config.js:
env: {
GOOGLE_SECRET: '...' },
privateRuntimeConfig: {
secretKey: process.env.GOOGLE_SECRET },
modules: [
[
"#nuxtjs/recaptcha",
{
siteKey:process.env.GOOGLE_SECRET ,
version: 3,
} ]
],

You don't seem to have the recaptcha element in your template.
<!-- Add this where you want the captcha, regardless of version -->
<recaptcha #error="onError" #success="onSuccess" #expired="onExpired" />
<script>
export default {
data() {
return {
isClickSubmit: false,
form: {
userEmail: "",
userFullName: "",
userName: "",
userPassword: null,
token: null
},
show: true
};
},
methods: {
onSuccess(token) {
this.form.token = token;
},
onExpired() {
this.$recaptcha.reset();
},
onError(error) {
console.error(error);
}
}
}
Before you make your request, you'll need to send some things to Google. You'll make this call before serving any requests. This function is from a project of mine.
// Backend code
function Recaptcha(token, ip, callback) {
axios.post(`https://www.google.com/recaptcha/api/siteverify?secret=${SECRET_KEY}&response=${token}`,
{
remoteip: ip,
},
{
headers: {
'Content-Type':
'application/x-www-form-urlencoded; charset=utf-8',
},
},
)
.then(callback);
}
Example usage of Recaptcha function:
Hopefully this helps you understand it a bit better.

Related

Hide the buttons on the back of the modal form (bootstrap-vue, vue.js)

I want to hide the buttons on the back of the modal window. When I open the modal window, the buttons on the back are visible in the modal window. I have tried use opasity etc.
Here is my code for modal form.
Modal form :
<template>
<popup-modal-spr style="opacity: $modal-backdrop-opacity; filter: alpha(opacity=50); background: rgba(0, 0, 0, 0.8); overflow: hidden;" ref="popup">
<confirm-dialogue-info ref="confirmDialogueInfo"></confirm-dialogue-info>
<h2 style="margin-top: 0">{{ titleListAllCustomers }}</h2>
<b-form-radio-group
v-model="selectedRadioTypeCustomerSearch"
:options="RadioModelTypeCustomerSearch"
value-field="itemTypeCustomerSerarch"
text-field="nameTypeCustomerSerarch"
disabled-field="notEnabled"
/>
<b-form-group
id="labelNameCustomerSearch"
content-cols-sm
description="Наименование клиента"
label="Наименование клиента"
label-for="NameCustomerSearch"
>
<b-form-input id="NameCustomerSearch" v-model="NameCustomerSearch" size="sm"></b-form-input>
</b-form-group>
<b-form-group
id="labelInnCustomerSearch"
content-cols-sm
description="ИНН клиента"
label="ИНН клиента"
label-for="InnCustomerSearch"
>
<b-form-input id="InnCustomerSearch" v-model="InnCustomerSearch" size="sm"></b-form-input>
</b-form-group>
<b-button
id="btnSearchCustomer" name="btnSearchCustomer"
#click="RefreshData"
variant="primary">
Поиск
</b-button>
<b-form-group align="center">
<b-container fluid>
<b-col>
<label>Фильтрация выгруженного списка :</label>
</b-col>
<b-col>
<b-input-group size="sm">
<b-form-input
id="filter-input"
v-model="filter"
type="search"
placeholder="Введите для фильтрации списка"
></b-form-input>
<b-input-group-append>
<b-button :disabled="!filter" #click="filter = ''">Очистить</b-button>
</b-input-group-append>
</b-input-group>
</b-col>
</b-container>
</b-form-group>
<div class="overflow-auto">
<b-pagination
v-model="currentPage"
:total-rows="rows"
:per-page="perPage"
aria-controls="list-All-Customers"
></b-pagination>
<p class="mt-3">Текущая страница: {{ currentPage }}</p>
<!-- <b-button #click="RefreshData" variant="primary">Обновить</b-button> -->
<b-button #click="_confirm" variant="danger">Закрыть</b-button>
<b-table
:items="ListAllCustomers"
:fields="fields"
:per-page="perPage"
:current-page="currentPage"
:filter="filter"
:filter-included-fields="filterOn"
#filtered="onFiltered"
small
id="list-All-Customers"
ref="listAllCustomerssselect">
<template v-slot:cell(actions)="{item:{customerID}}">
<b-button size="sm" #click="_confirm(customerID)" variant="info" class="mr-2" >Выбрать</b-button>
</template>
</b-table>
</div>
</popup-modal-spr>
</template>
<script>
import Vue from 'vue'
import axios from 'axios'
import VueAxios from 'vue-axios'
import { BootstrapVue, IconsPlugin } from 'bootstrap-vue'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
import PopupModalSpr from './PopupModalSpr.vue'
Vue.use(VueAxios,axios);
axios.defaults.headers.common['Access-Control-Allow-Origin'] = '*';
axios.defaults.headers.common['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS, PUT, PATCH, DELETE';
axios.defaults.headers.common['Access-Control-Allow-Headers'] = 'Origin,Content-Type,X-Requested-With,Accept,Authorization';
axios.defaults.headers.common['Authorization'] = "Bearer "+sessionStorage.authHash;
Vue.use(BootstrapVue);
Vue.use(IconsPlugin);
import ConfirmDialogueInfo from '/src/components/ConfirmDialogueInfo.vue'
export default {
name: 'ConfirmDialogue',
components: { PopupModalSpr,ConfirmDialogueInfo },
data() {
return{
NameCustomerSearch:"",
InnCustomerSearch:"",
selectedRadioTypeCustomerSearch: 0,
RadioModelTypeCustomerSearch: [
{ itemTypeCustomerSerarch: 0, nameTypeCustomerSerarch: 'Все' },
{ itemTypeCustomerSerarch: 1, nameTypeCustomerSerarch: 'Физ.' },
{ itemTypeCustomerSerarch: 2, nameTypeCustomerSerarch: 'Юр.' },
],
rows:0,
perPage: 15,
currentPage: 1,
titleListAllCustomers:undefined,
resolvePromise: undefined,
rejectPromise: undefined,
filter: null,
filterOn: [],
ListAllCustomers:[],
fields: [
{
key: 'customerID',
label:"ИД клиента",
},
{
key: 'nameCustomer',
label:"Название клиента",
},
{
key: 'actions',
label:"Действие",
},
],
}
},
methods:
{
onFiltered(filteredItems) {
// Trigger pagination to update the number of buttons/pages due to filtering
this.totalRows = filteredItems.length
this.currentPage = 1
},
rows() {
this.rows=this.ListAllCustomers.length
return this.rows
},
show(opts = {}) {
this.titleListAllCustomers = opts.title
// this.RefreshData();
this.$refs.popup.open()
// Return promise so the caller can get results
return new Promise((resolve, reject) => {
this.resolvePromise = resolve
this.rejectPromise = reject
})
},
_confirm(item) {
this.$refs.popup.close()
const SelectedCustomers= this.ListAllCustomers.filter(i=>i.customerID == item);
this.resolvePromise(SelectedCustomers[0])
},
_cancel() {
this.$refs.popup.close()
this.resolvePromise(false)
},
RefreshData() {
this.isBusy = !this.isBusy
const HeaderBearer="Bearer "+sessionStorage.authHash
axios.post
(
`/api/SprsObGets/GetCustomers`,
{
TypeCustomer:this.selectedRadioTypeCustomerSearch,
NameCustomer:this.NameCustomerSearch,
IdentificationNumberCustomer:this.InnCustomerSearch,
},
{
headers:
{
"Authorization": HeaderBearer
},
mode: 'no-cors',
credentials: 'include'
}
)
.then((result)=>{
this.ListAllCustomers = result.data;
this.rows=this.ListAllCustomers.length;
console.warn(result.data);
})
.catch(err => {
if(err.response.status==401)
{
sessionStorage.loginIn = false;
sessionStorage.setItem("UsersMenuItems", JSON.stringify("")) ,
sessionStorage.authHash = "",
sessionStorage.setItem("ObInfoSys", JSON.stringify("")),
sessionStorage.setItem("UsersData", JSON.stringify("")),
this.$router.push({
path: '/Auth'
});
}
else{
this.$refs.confirmDialogueInfo.show({
title: 'Ошибка',
message: err.response.data.errorText,
cancelButton: 'ОК',
});
}
})
this.isBusy = !this.isBusy
}
},
}
</script>
I want to hide the buttons on the back of the modal window. When I open the modal window, the buttons on the back are visible in the modal window. I have tried use opasity etc.
Here is my code for modal form.

Using SendGrid with Nuxt.js

This post is not a question actually.
More like help to the world for people who are struggling with Nuxt.js and SendGrid.
I've been using stackoverflow for such a long time so maybe now it's my turn to start helping others.
I've been working on Nuxt.js WebApp development for the past 8 weeks.
Nuxt.js is a massive learning curve and challenge for me but I really love working with this technology.
I spent the last 2 days developing sending the form with the use of SendGrid. There's not too much help online and I've been struggling a lot but I made it!
So maybe some people will find my post useful.
Here's my form:
<form
v-show="!isSubmitted"
class="contact-us__form"
#submit.prevent="validate">
<b-form-group :class="{'form-group--error': $v.name.$error}">
<b-form-input
id="name"
v-model.trim="$v.name.$model"
type="text"
placeholder="Full Name">
></b-form-input>
<div class="error" v-if="!$v.name.required">Field is required</div>
<div class="error" v-if="!$v.name.minLength">Name must have at least {{$v.name.$params.minLength.min}} letters.</div>
</b-form-group>
<b-form-group :class="{'form-group--error': $v.phone.$error}">
<b-form-input
id="phone"
v-model.trim="$v.phone.$model"
type="number"
placeholder="Phone Number">
></b-form-input>
<div class="error" v-if="!$v.phone.required">Field is required</div>
</b-form-group>
<b-form-group :class="{'form-group--error': $v.email.$error}">
<b-form-input
id="email"
v-model.trim="$v.email.$model"
type="email"
placeholder="Email Address">
></b-form-input>
<div class="error" v-if="!$v.email.required">Field is required</div>
</b-form-group>
<div class="d-flex align-items-end">
<b-form-group :class="{'form-group--error': $v.message.$error}">
<b-form-textarea
id="message"
v-model.trim="$v.message.$model"
type="text"
placeholder="Message"
></b-form-textarea>
<div class="error" v-if="!$v.message.required">Field is required</div>
<div class="error" v-if="!$v.message.minLength">Name must have at least {{$v.message.$params.minLength.min}} characters.</div>
</b-form-group>
<b-form-group>
<b-button
type="submit"
variant="secondary"
v-html="'S'"
:disabled="submitting" />
</b-form-group>
</div>
</form>
script:
export default {
mixins: [validationMixin],
components: {
subscribeBox
},
data() {
return {
map: bgMap,
name: "",
phone: "",
email: "",
message: "",
submitting: false,
isSubmitted: false,
error: false,
}
},
validations: {
name: {
required,
minLength: minLength(4)
},
phone: {
required,
},
email: {
required,
email
},
message: {
required,
minLength: minLength(5)
}
},
methods: {
validate() {
if (this.$v.$invalid || this.$v.$error|| this.submitting) {
this.$v.$touch();
return
}
this.onSsubmit();
},
async onSsubmit() {
this.submitting = true;
this.error = false;
try {
await this.$axios.$post('/api/v1/send-email', {
name: this.name,
phone: this.phone,
email: this.email,
message: this.message,
});
this.submitting = false
this.isSubmitted = true
await new Promise(resolve => setTimeout(resolve, 2500))
} catch(e) {
this.submitting = false
this.error = true
console.error(e)
}
},
},
}
nuxt.config.js
serverMiddleware: ['~/api/v1/send-email.js'],
api/v1/send-email.js (all the API Keys are placed in .env file)
const express = require("express");
const bodyParser = require('body-parser')
const sgMail = require('#sendgrid/mail');
const app = express();
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
app.use(bodyParser.json())
app.post("/", (req, res) => {
let msg = {
to: req.body.email, // Change to your recipient
from: '', // Change to your verified sender
subject: 'Message from ' + req.body.name,
text: 'telephone ' + req.body.phone + ', ' + 'message ' + req.body.message,
}
sgMail
.send(msg)
.then(() => {
return res.status(200).json({ 'message': 'Email sent!' })
})
.catch((error) => {
return res.status(400).json({ 'error': 'Opsss... Something went wrong ' + error })
})
});
module.exports = {
path: "/api/v1/send-email",
handler: app
};
This app is still not finished but the code is working 100%!
I'm new to Nuxt.js so some bits may not look awesome but I'm also happy and open to feedback and suggestions.
Thank you for reading my post and good luck with your project! :)

Parent component only pass the dynamic v-modal ID to the child of the first page in pagination

I am using vue#2.6.11 and bootstrap-vue#2.11.0
I am having a component called index.vue to list all customers.
and a child component customerModal.vue to control the v-modal for Edit and Create Cusotmer form.
I am using v-table to list the customers details with button actions
index.vue //customer create btn
<!-- {{-- CREATE CUSTOMER --}} -->
<b-button #click="$root.$emit('bv::show::modal', 'customerModal' , $event.target)" variant="success" title="Create New Customer">
<i class="fas fa-plus-circle" id="action-icon" style="right:3%"></i>
</b-button>
<!-- Modal Customer -->
<customer-modal :customers="customers" modalType="create" #create-customer="customers.push($event)"></customer-modal>
index.vue //customer edit btn
<b-table
show-empty
:filter="filter"
#filtered="on_filtered"
id="customers-table"
:sort-by.sync="sort_by"
:sort-desc.sync="sort_desc"
:items="customers"
:fields="fields"
:per-page="per_page"
:current-page="current_page"
responsive
hover
head-variant="light"
class="text-center mt-4"
>
<template v-slot:cell(actions)="data">
<div class="btn-group" role="group">
<!-- {{-- EDIT CUSTOMER --}} -->
<b-button #click="$root.$emit('bv::show::modal', data.item.first_name.replace(/\s/g, '')+data.item.id, $event.target)" variant="primary" title="Edit Customer">
<i class="fas fa-edit"></i>
</b-button>
<!-- Customer Modal-->
<customer-modal modalType="edit" :selectedCustomer="data.item" :customers="customers" #update-customer="data.item = $event"></customer-modal>
</div>
</template>
index.vue //b-pagination
<b-pagination
class=" m-auto justify-content-center"
pills
:per-page="per_page"
:total-rows="rows"
v-model="current_page"
aria-controls="#customers-table"
>
</b-pagination>
customerModal.vue
<b-modal
:id="this.customer.first_name.replace(/\s/g, '')+this.customer.id || 'customerModal'"
title="Customer Modal"
#hidden="resetModal"
hide-footer
>
The problem
when I go to next page using b-pagination the btn edit does not show the corresponding v-modal. While in the first page all edit btns for each customer are working just fine.
However if I add the create btn to the list in the second page, it will work fine
The issue is that Vue is trying to reuse your modal on page 1, to save how much it has to re-render.
The root of your issue is that inside the modal component, you set this.customer to this.selectedCustomer in the create hook and no where else. Since the create doesn't run again on page 2, it wont update this.customer meaning the ID will still match the rows from page 1.
In the long term it might be a good idea for for you to rethink that logic.
But you should be able to solve the issue by adding :key="data.item.id" to the customer-modal, which forces Vue to re-render the modal when the id updates. So it can't try to reuse the modals across the pages.
<customer-modal modalType="edit" :selectedCustomer="data.item" :customers="customers" #update-customer="data.item = $event" :key="data.item.id"></customer-modal>
Working snippet (based on codepen from this Github Issue.
Vue.use(window.vuelidate.default);
const { required, email, numeric, minLength, maxLength } = window.validators;
let OMDModal = {
props: ["selectedCustomer", "modalType", "customers"],
template: '#customer-modal',
validations: {
customer: {
first_name: {
required,
minLen: minLength(3),
maxLen: maxLength(12)
},
last_name: {
required,
minLen: minLength(3),
maxLen: maxLength(12)
},
email: {
required,
email,
isUnique: function (val) {
if (val === "") return true;
else if (val === this.currentEmail) return true;
return axios.get(`api/validateEmail/${val}`).then((res) => {
return res.data.unique;
});
}
}
}
},
data() {
return {
currentEmail: "",
alert_sec: 0,
alert_duration: 5,
alert_message: "",
alert_color: "",
customer: {
id: "",
first_name: "",
last_name: "",
email: ""
},
customer_default: {
first_name: [],
last_name: [],
email: []
}
};
},
watch: {
"customer.first_name"(newVal, oldVal) {
if (this.modalType === "edit") {
this.customer_default.first_name.push(oldVal);
}
},
"customer.last_name"(newVal, oldVal) {
if (this.modalType === "edit") {
this.customer_default.last_name.push(oldVal);
}
},
"customer.email"(newVal, oldVal) {
if (this.modalType === "edit") {
this.customer_default.email.push(oldVal);
}
}
},
computed: {
ModalID() {
if (this.modalType === "create") {
return "customerModal";
} else {
return this.customer.first_name.replace(/\s/g, "") + this.customer.id;
}
},
now() {
const monthNames = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
];
const today = new Date();
let day = today.getDate().toString();
let month = (today.getMonth() + 1).toString();
let year = today.getFullYear().toString();
return year + "-" + month + "-" + day;
},
first_nameValidate() {
if (this.$v.customer.first_name.$dirty) {
return !this.$v.customer.first_name.$anyError;
} else return null;
},
last_nameValidate() {
if (this.$v.customer.last_name.$dirty) {
return !this.$v.customer.last_name.$anyError;
} else return null;
},
emailValidate() {
if (this.$v.customer.email.$dirty) {
return !this.$v.customer.email.$anyError;
} else return null;
}
},
methods: {
setFirstName(e) {
this.customer.first_name = e;
this.$v.customer.first_name.$touch();
},
setLastName(e) {
this.customer.last_name = e;
this.$v.customer.last_name.$touch();
},
setEmail(e) {
this.customer.email = e;
this.$v.customer.email.$touch();
},
resetModal() {
this.$nextTick(() => {
this.$v.$reset();
});
if (this.modalType === "create") {
this.customer = {
id: "",
first_name: "",
last_name: "",
email: ""
};
}
if (this.alert_color != "success") {
if (this.customer_default.first_name[1] != undefined) {
this.customer.first_name = this.customer_default.first_name[1];
}
if (this.customer_default.last_name[1] != undefined) {
this.customer.last_name = this.customer_default.last_name[1];
}
if (this.customer_default.email[1] != undefined) {
this.customer.email = this.customer_default.email[1];
}
}
},
onSubmit(v, e) {
v.customer.$touch();
if (this.$v.customer.$anyError) {
this.alert_message = "Correct the inputs Please";
this.alert_color = "danger";
this.show_alert();
} else {
this.customer.first_name =
this.customer.first_name.charAt(0).toUpperCase() +
this.customer.first_name.slice(1);
// CREATE CUSTOMER
if (this.modalType === "create") {
this.customer.created_at = this.now;
let last_index = this.customers.length - 1;
let last_customer = this.customers[last_index];
this.customer.id = last_customer.id + 1;
fetch(`api/customers`, {
method: "POST",
body: JSON.stringify(this.customer),
headers: { "content-type": "application/json" }
})
.then((res) => res.json())
.then((res) => {
this.$nextTick(() => {
this.$v.$reset();
});
this.$bvModal.hide(
this.customer.first_name.replace(/\s/g, "") +
this.customer.id || "customerModal"
);
this.$emit("create-customer", this.customer);
this.customer = {
id: "",
first_name: "",
last_name: "",
email: ""
};
})
.catch((e) => console.log(e));
} else {
// UPDATE CUSTOMER
this.customer.updated_at = this.now;
fetch(`api/customers/${this.customer.id}`, {
method: "put",
body: JSON.stringify(this.customer),
headers: {
"content-type": "application/json"
}
})
.then((res) => res.json())
.then((data) => {
this.$nextTick(() => {
this.$v.$reset();
this.$bvModal.hide(
this.customer.first_name.replace(/\s/g, "") +
this.customer.id || "customerModal"
);
});
this.$emit("update-customer", this.selectedCustomer);
this.alert_color = "success";
this.alert_message = "Customer Updated Successfully";
})
.catch((error) => console.log(error));
}
}
},
show_alert() {
this.alert_sec = this.alert_duration;
},
countDown(alert_sec) {
this.alert_sec = alert_sec;
}
},
created() {
if (this.modalType === "edit") {
this.customer = this.selectedCustomer;
this.currentEmail = this.selectedCustomer.email;
}
}
};
window.onload = () => {
new Vue({
el: "#app",
data() {
return {
per_page: 3,
current_page: 1,
fields: [
{ key: "#", sortable: false },
{ key: "id", sortable: true },
{ key: "first_name", label: "Name", sortable: true, class: "w-25" },
{ key: "email", sortable: true },
{ key: "actions", sortable: false }
],
sort_by: "email",
sort_desc: false,
filter: null,
filter_on: [],
customers: [],
customer: {
id: "",
first_name: "",
last_name: "",
email: ""
}
};
},
computed: {
now() {
const monthNames = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
];
const today = new Date();
let day = today.getDate().toString();
let month = (today.getMonth() + 1).toString();
let year = today.getFullYear().toString();
return year + "-" + month + "-" + day;
},
rows() {
return this.customers.length;
}
},
methods: {
fetchCustomers() {
fetch("https://reqres.in/api/users")
.then((res) => res.json())
.then((res) => {
this.customers = res.data;
})
.catch((err) => console.log(err));
},
on_filtered(filtered_items) {
this.rows;
},
openModal(id) {
this.$root.$emit('bv::show::modal', id)
}
},
created() {
this.fetchCustomers();
},
components: {
"omd-modal": OMDModal
}
});
};
<link href="https://unpkg.com/bootstrap#4.5.0/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue#2.15.0/dist/bootstrap-vue.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.15.0/dist/bootstrap-vue.js"></script>
<div id="app">
<div class="card">
<div class="card-body">
<!-- Card Header (Title & Create btn) -->
<div class="row ">
<div class="col-sm-4">
<h4 class="card-title font-weight-bold">
User Management
</h4>
</div>
<div class="col-sm-4 offset-sm-4">
<div class="btn-toolbar float-right">
<!-- {{-- CREATE CUSTOMER --}} -->
<b-button #click="$root.$emit('bv::show::modal', 'customerModal', $event.target)" variant="success" title="Create New Customer">
CREATE
</b-button>
</div>
</div>
</div>
<!-- Modal Customer Create -->
<omd-modal :customers="customers" modal-type="create" #create-customer="customers.push($event)"></omd-modal>
<!-- Search Bar -->
<div class="row">
<div class="col-12">
<b-input-group class="w-50 m-auto">
<b-form-input placeholder="Search for Customers" v-model="filter" class="rounded-pill searchbar">
</b-form-input>
</b-input-group>
</div>
</div>
<!-- Customer List (Card Content) -->
<div class="row ">
<div class="col">
<b-table ref="table" :key="customer.id" show-empty :filter="filter" #filtered="on_filtered" id="customers-table" :sort-by.sync="sort_by" :sort-desc.sync="sort_desc" :items="customers" :fields="fields" :per-page="per_page" :current-page="current_page" responsive hover head-variant="light" class="text-center mt-4">
<template v-slot:cell(#)="data">
{{data.index+1}}
</template>
<template v-slot:cell(first_name)="data">
{{data.item.first_name}} {{data.item.last_name}}
</template>
<template v-slot:cell(actions)="data">
<div class="btn-group" role="group">
<!-- {{-- EDIT CUSTOMER --}} -->
<b-button #click="$root.$emit('bv::show::modal', data.item.first_name.replace(/\s/g, '')+data.item.id)" variant="primary" title="Edit Customer">
Edit
</b-button>
</div>
<!--Edit Customer Modal-->
<omd-modal modal-type="edit" :selected-customer="data.item" :customers="customers" #update-customer="data.item = $event" :key="data.item.id"></omd-modal>
</template>
</b-table>
</div>
</div>
<hr>
<!-- {{-- Card Footer --}} -->
<div class="row">
<div class="col-sm-4">
<small class="text-muted"> Total Customers {{rows}} </small>
</div>
<div class="col-sm-4">
<b-pagination class=" m-auto justify-content-center" pills :per-page="per_page" :total-rows="rows" v-model="current_page" aria-controls="#customers-table">
</b-pagination>
</div>
</div>
</div>
</div>
</div>
<template id="customer-modal">
<b-modal :id="customer.first_name.replace(/\s/g, '')+customer.id || 'customerModal'" title="Customer Modal" #hidden="resetModal" hide-footer>
<b-alert id="alert" style="width: 100%;" :show="alert_sec" dismissible :variant="alert_color" #dismissed="alert_sec=0" #dismiss-count-down="countDown">
{{alert_message}}
</b-alert>
<b-form #submit.prevent="onSubmit($v, $event)">
<!-- first_name -->
<b-form-group id="first-name-group" label="First Name" label-for="first-name">
<b-form-input id="first-name" type="text" :value="customer.first_name" :state="first_nameValidate" #change="setFirstName($event)" required></b-form-input>
<b-form-invalid-feedback :state="first_nameValidate">First Name is required and must be 3-5 character long.</b-form-invalid-feedback>
</b-form-group>
<!-- Last_name -->
<b-form-group id="last-name-group" label="Last Name" label-for="last-name">
<b-form-input id="last_name" :value="customer.last_name" :state="last_nameValidate" #change="setLastName($event)" type="text" required>
</b-form-input>
<b-form-invalid-feedback :state="last_nameValidate">Last Name is required and must be 3-5 character long.</b-form-invalid-feedback>
</b-form-group>
<!-- Email -->
<b-form-group id="email-group" label="Email" label-for="email">
<b-form-input id="email" :state="emailValidate" :value="customer.email" #change="setEmail($event)" type="email" required>
</b-form-input>
<b-form-invalid-feedback :state="emailValidate">Invalid Email.</b-form-invalid-feedback>
</b-form-group>
<hr style="margin-top: 2rem; margin-bottom: 1rem;">
<div class="row justify-content-center">
<b-button variant="success" class="mr-1" type="submit">Save Changes</b-button>
<b-button variant="danger" class="ml-1" #click="$bvModal.hide(customer.first_name.replace(/\s/g, '')+customer.id || 'customerModal')">Cancel</b-button>
</div>
</b-form>
</b-modal>
</template>
<script src="https://unpkg.com/vuelidate#0.7.5/dist/validators.min.js"></script>
<script src="https://unpkg.com/vuelidate#0.7.5/dist/vuelidate.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

#submit.prevent not working on vue md-input

when I click 'login button' even I don't fill data in md-input it still running,
I test my onSubmit() method by login with my user and it works!
I don't think I do thing wrong in the method so I guess that my form is incorrect.
here is my code :
my form
<form #submit.prevent="onSubmit">
<login-card header-color="green">
<h4 slot="title" class="title">CCRP Sign On</h4>
<p slot="description" class="description">IT solution by เจ้เก๋ IT-PM</p>
<md-field class="md-form-group" slot="inputs">
<md-icon>account_box</md-icon>
<label>ID...</label>
<md-input v-model.trim="userId" type="text"></md-input>
</md-field>
<md-field class="md-form-group" slot="inputs">
<md-icon>lock_outline</md-icon>
<label>Password...</label>
<md-input v-model.trim="password" type="password"></md-input>
</md-field>
<md-field class="md-form-group">
<md-icon>announcement</md-icon>
<label>Password...</label>
</md-field>
<md-button slot="footer" class="md-simple md-success md-lg" type="submit">Login</md-button>
</login-card>
</form>
in scrpit methods
async onSubmit() {
const authData = {
userId: this.userId,
password: this.password
};
await this.login(authData).then(() => {
if (this.isAuthenticated) {
this.$router.push("dashboard");
} else {
console.log("err");
}
});
},
can you help me solve this?
Your understanding of "prevent" key is quite incorrect.
All it does is not reload the form after submit action. However the submit action will be called irrespective of whether the prevent is used or not.
It is just preventing the default functionality of form getting reloaded after each submit.
On the other hand what you need to do is validate your form before actually submitting it.
Example :
//- Requires "vuelidate" - npm install vuelidate
<script>
import { validationMixin } from "vuelidate";
import { required, email } from "vuelidate/lib/validators";
export default {
name: "FormValidation",
mixins: [validationMixin],
data: () => ({
form: {
email: null,
password: null
},
userSaved: false,
sending: false,
lastUser: null
}),
validations: {
form: {
email: {
required,
email
},
password: {
required
}
}
},
methods: {
getValidationClass(fieldName) {
const field = this.$v.form[fieldName];
if (field) {
return {
"md-invalid": field.$invalid && field.$dirty
};
}
},
clearForm() {
this.$v.$reset();
this.form.email = null;
this.form.password = null;
},
saveUser() {
this.sending = true;
// Instead of this timeout, here you can call your API
window.setTimeout(() => {
this.lastUser = `${this.form.email}`;
this.userSaved = true;
this.sending = false;
this.clearForm();
}, 1500);
},
validateUser() {
this.$v.$touch();
if (!this.$v.$invalid) {
this.saveUser();
}
}
}
};
</script>
<style lang="scss" scoped>
.md-progress-bar {
position: absolute;
top: 0;
right: 0;
left: 0;
}
</style>
<template>
<div>
<!-- Calling validateUser insted of submit action -->
<form novalidate class="md-layout" #submit.prevent="validateUser">
<md-card class="md-layout-item md-size-50 md-small-size-100">
<!-- Title of the form -->
<md-card-header>
<div class="md-title">Login</div>
</md-card-header>
<!-- Inputs for the form -->
<md-card-content>
<md-field :class="getValidationClass('email')">
<label for="email">Email</label>
<md-input
type="email"
name="email"
id="email"
autocomplete="email"
v-model="form.email"
:disabled="sending"
/>
<span class="md-error" v-if="!$v.form.email.required">The email is required</span>
<span class="md-error" v-else-if="!$v.form.email.email">Invalid email</span>
</md-field>
<md-field :class="getValidationClass('password')">
<label for="password">Password</label>
<md-input
type="password"
name="password"
id="password"
autocomplete="password"
v-model="form.password"
:disabled="sending"
/>
<!-- to show errors in case validation fails -->
<span class="md-error" v-if="!$v.form.password.required">The email is required</span>
<span class="md-error" v-else-if="!$v.form.email.email">Invalid email</span>
</md-field>
</md-card-content>
<md-progress-bar md-mode="indeterminate" v-if="sending"/>
<md-card-actions>
<md-button type="submit" class="md-primary" :disabled="sending">Create user</md-button>
</md-card-actions>
</md-card>
<md-snackbar :md-active.sync="userSaved">The user {{ lastUser }} was saved with success!</md-snackbar>
</form>
</div>
</template>

React Router: login post

I'm a beginner with React & Router and I'm trying to set up a very simple login form & redirection.
I don't really understand where i have to put my 'logic code' (an ajax call and a redirection).
This is what I get when I try to login..
GET security/login?callback=jQuery33102958950754760552_1525660032193&format=json&_=1525660032194 40 5()
It should be "POST" not "GET"
Here is what I've write.
import React from "react";
import { Link } from "react-router-dom";
import $ from "jquery";
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
userid: "",
password: "",
submitted: false
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(e) {
e.preventDefault();
var root = 'security/login';
//var userid = $("#userid").val();
// var password = $("#password").val();
var formData = {
"userId" : $('input[name=userid]').val(),//$('input[name=userid]').val()
"password" : $('input[name=password]').val()//$('input[name=password]').val()
};
var jsondata = JSON.stringify(formData);
console.log(jsondata);
alert("test" +jsondata);
$.ajax({
url: root,
method: 'POST',
data: {
format: 'json'
},
contentType : "application/json; charset=utf-8",
error: function() {
$('#info').html('<p>An error has occurred</p>');
},
headers: {
'Content-Type': 'application/json', /*or whatever type is relevant */
'Accept': 'application/json' /* ditto */
},
dataType: 'jsonp',
encode : true,
success: function(data, response) {
alert(+data.status.message);
var $title = $('<h1>').text(data.talks[0].talk_title);
var $description = $('<p>').text(data.talks[0].talk_description);
$('#info')
.append($title)
.append($description);
}
});
//done(Login.function(data)
// {
// this.setState({});
// console.log(this.state.data);
// }
}
render() {
// const { loggingIn } = this.props;
// const { userid, password, submitted } = this.state;
return (
<div className="container">
<div className="col-md-5 col-md-offset-13 login-form text-center">
<div className="form-top">
<div className="form-top-left">
<h3>LOGIN PAGE</h3>
<p>Please enter your userID and password</p>
</div>
</div>
<form onSubmit={this.handleSubmit}>
<div className="input-group col-lg-10 col-md-offset-1">
<span className="input-group-addon">
<i className="glyphicon glyphicon-user" />
</span>
<input
className="form-control"
placeholder="UserID"
name="userid"
id="userid"
type="text"
required
/>
</div>
<div className="input-group col-lg-10 col-md-offset-1">
<span className="input-group-addon">
<i className="glyphicon glyphicon-lock" />
</span>
<input
type="password"
name="password"
id="password"
className="form-control"
placeholder="Password"
required
/>
</div>
<button type="submit"
className="btn btn-danger btn-block col-xs-6 col-lg-11"
id="login">
>
LOGIN
</button>
</form>
<div className="form-footer">
<div className="row">
<div className="col-xs-7 blink">
<i className="fa fa-unlock-alt" />
</div>
</div>
</div>
</div>
</div>
);
}
}
export default Login;
Hope you all can help me... Thanks in advance