I have created one login page using VuejS and when I'm accessing directly into the browser in server it gives me 500 error. but when i click from my website it works.
My Login.vue :
<template>
<div>
<div v-if="progress" class="progress-bg">
<div class="lds-ellipsis"><div></div><div></div><div></div><div></div></div>
</div>
<section class="container login">
<h1 class="login-title text-center">Login With Email</h1>
<form>
<p v-if="error">{{error}}</p>
<div class="form-group">
<input type="text" v-on:keyup="validate()" v-model="email" :disabled="disabled" class="edt-text" name="email" placeholder="Email">
<p v-if="emailError">{{ emailError}}</p>
</div>
<div class="form-group">
<input type="password" v-on:keyup="validate()" v-model="password" :disabled="disabled" class="edt-text" name="password" placeholder="Password">
<p v-if="passwordError">{{ passwordError}}</p>
</div>
<p class="label-forgot-password">Forgot Password?</p>
<div class="form-group">
<button type="button" :disabled="disabled" v-on:click="login" class="btn-login">Login</button>
</div>
</form>
<p class="text-center">Or Connect With</p>
<div class="row social-login-buttons text-center">
<div class="col-lg-6 col-md-6 col-sm-6 col-xs-6">
<button type="button" class="btn-google"><i class="fa fa-google"></i>Google</button>
</div>
<div class="col-lg-6 col-md-6 col-sm-6 col-xs-6">
<button type="button" class="btn-facebook"><i class="fa fa-facebook"></i>Facebook</button>
</div>
</div>
<div class="row">
<p class="text-center yellow-text margin-20">Don't you have an account?</p>
</div>
</section>
</div>
</template>
<script>
import axios from 'axios'
export default {
name:"Login",
data() {
return {
email:'',
password:'',
progress:false,
disabled:false,
emailError:null,
passwordError:null,
error:null,
}
},
methods: {
async login() {
this.error = ''
if (this.email && this.password && this.validEmail(this.email)) {
this.progress = true
this.disabled = true
let result = await axios.get(
`https://example.com/login/direct?email=${this.email}&password=${this.password}`
)
this.progress=false
this.disabled=false
if(result.status == "200"){
if(result.data['status'] == true) {
localStorage.setItem("user-token", JSON.stringify(result.data['token']))
this.$router.push({name:'Home'})
}
else {
this.error = "Invalid email address / password"
this.email=''
this.password=''
}
}
}
else {
this.validate()
}
},
validate() {
if (!this.email) {
this.emailError = 'Email address required.';
}
else if (!this.validEmail(this.email)) {
this.emailError = 'Enter valid email address.';
}
else{
this.emailError = null;
}
if (!this.password) {
this.passwordError = 'Password is required';
}
else{
this.passwordError = null;
}
},
validEmail(email) {
var re = /^(([^<>()[\]\\.,;:\s#"]+(\.[^<>()[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(email);
},
}
};
</script>
My router/index.js :
import Vue from 'vue'
import VueRouter from 'vue-router'';
import ChatList from '../views/Chat/ChatList.vue'
import Chat from '../views/Chat/Chat.vue'
import Login from '../views/Login/Login.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/inbox',
name: 'ChatList',
component:ChatList
},
{
path: '/chat',
name: 'Chat',
component:Chat
},
{
path: '/login',
name: 'Login',
component:Login
},
]
const router = new VueRouter({
mode:'history',
routes
})
export default router
I'm able to access my login page when i click from my site which is linked via hyper link but when i directly hit the url into browser address bar it gives me Internal server error.
Related
I'm currently building a form in Vue and I'm having a hard time submitting the form when the form is free from error messages.
I'm currently fixed so that the errors show when they should but the goal is to change the page after pressing the submit button.
I would appreciate any tip that could help me :)
HTML
<template>
<form #submit.prevent="submitMessage">
<div class="form-control">
<label for="user-name">Name*</label>
<input id="user-name" name="user-name" type="text" v-model="userName" />
</div>
<div class="form-control">
<label for="age">Age</label>
<input id="age" name="age" type="number" v-model="userAge" />
</div>
<div class="form-control">
<label for="email">Email*</label>
<input id="email" name="email" type="email" v-model="email" />
</div>
<div class="form-control">
<label for="referrer">How did you hear about us?</label>
<select id="referrer" name="referrer" v-model="referrer">
<option value="google">Google</option>
<option value="wom">Word of mouth</option>
<option value="newspaper">Social Media</option>
<option value="other">Other</option>
</select>
</div>
<div class="form-control">
<label for="message">Message*</label>
<textarea rows="5" cols="50" id="message" name="message" v-model="message">Aa</textarea>
</div>
<div>
<button id="send" #click="sendForm()">Send Message</button>
</div>
<div class="errors">
<p v-if="errors.length > 0">
<b>Please correct the following error(s):</b>
<ul>
<li v-for="error in errors">{{ error }}</li>
</ul>
</p>
</div>
</form>
</template>
Vue
<script>
export default {
data() {
return {
userName: '',
userAge: null,
referrer: 'google',
email: '',
message: '',
errors: []
};
},
methods: {
submitMessage(e) {
this.userName = '';
this.userAge = null;
this.email = '';
this.referrer = 'google';
this.message = ''
},
sendForm() {
this.errors = [];
if (!this.userName) {
this.errors.push('Name is required');
}
if (!this.email) {
this.errors.push('Email is required');
} else if (!this.validEmail(this.email)) {
this.errors.push('Valid email required.');
}
if (!this.message) {
this.errors.push('Message is required');
}
if (!this.errors.length) {
return true;
}
if (this.errors.any()) {
this.$router.push('/thankyou');
}
},
validEmail: function (email) {
var re = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(email);
}
}
}
</script>
Router.js
import {
createRouter,
createWebHistory
} from 'vue-router';
import HomeBeerSearch from './pages/beers/HomeBeerSearch.vue';
import BeerList from './pages/beers/BeerList.vue';
import CustomerSupport from './pages/contact/CustomerSupport.vue';
import ThankYou from './pages/contact/ThankYou.vue'
const router = createRouter({
history: createWebHistory(),
routes: [{
path: '/',
component: HomeBeerSearch
},
{
path: '/beers',
component: BeerList
},
{
path: '/support',
component: CustomerSupport
},
{
path: '/thankyou',
component: ThankYou
}
]
});
export default router
You can change the page by Vue router on SPA:
this.$router.push({ name: 'route name' })
or you can use raw JavaScript for external links:
window.location.href = 'http://www.google.com';
// there is no such function errors.any()
if (this.errors.any()) {
this.$router.push('/thankyou');
}
Your doing the navigation correctly but I think that the if statment logic is a little flawed. Try this instead:
// check if there are errors; if not go to the thank you page
if (!this.errors.length) {
this.$router.push('/thankyou');
}
<script>
export default {
name: "Register",
props: {
msg: String,
},
};
</script>
-------------main.js---------------
new Vue({
data:{
max:30,
text:''
},
render:h => h(App),
}).$mount('#app'
<template>
<div class="pop-up-mask">
{{ msg }}
<div class="pop-up">
<input type="text" class="input-section"
placeholder="Enter your Name" :maxlength="max" v-model="text" />
</div>
</template>
If the user tries to enter more than 30 characters, user should get an error message: you can only enter 30 characters. Try with above logic like maxlength="max" v-model="text"
I had done something similar in the past, so I built on that component (plus some research) to build this component that solves the problem.
<template>
<div class="input-max">
<div class="form-row">
<div class="col-md-8">
<input class="form-control" type="text" placeholder="Address"
v-model="address" #keyup="updateAddress">
</div>
<div class="col-md-4">
<span v-if="displayWarning" class="error-msg">* You can only enter {{ maxLength }} characters</span>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
address: '',
previousAddress: '',
maxLength: 30,
displayWarning: false
}
},
methods: {
updateAddress(event) {
let newValue = event.target.value;
if (newValue.length > this.maxLength) {
event.preventDefault()
this.address = this.previousAddress;
this.displayWarning = true;
}
else {
this.address = newValue;
this.previousAddress = newValue;
this.displayWarning = false;
}
}
}
}
</script>
<style scoped>
.error-msg {
color: red;
}
</style>
I have a web page that displays items. For each items there is a button (vuejs component) which allow user to toggle (add/remove) this item to his collection.
Here is the component:
<template lang="html">
<button type="button" #click="toggle" name="button" class="btn" :class="{'btn-danger': dAdded, 'btn-primary': !dAdded}">{{ dText }}</button>
</template>
<script>
export default {
props: {
added: Boolean,
text: String,
id: Number,
},
data() {
return {
dAdded: this.added,
dText: this.text,
dId: this.id
}
},
watch: {
added: function(newVal, oldVal) { // watch it
this.dAdded = this.added
},
text: function(newVal, oldVal) { // watch it
this.dText = this.text
},
id: function(newVal, oldVal) { // watch it
this.dId = this.id
}
},
methods: {
toggle: function(event) {
axios.post(route('frontend.user.profile.pop.toggle', {
pop_id: this.dId
}))
.then(response => {
this.dText = response.data.message
let success = response.data.success
this.dText = response.data.new_text
if (success) {
this.dAdded = success.attached.length
let cardPop = document.getElementById('card-pop-'+this.dId);
if(cardPop)
cardPop.classList.toggle('owned')
}
})
.catch(e => {
console.log(e)
})
}
}
}
</script>
For each item, the user can also open a modal, loaded by a click on this link:
<a href="#" data-toggle="modal" data-target="#popModal" #click="id = {{$pop->id}}">
<figure>
<img class="card-img-top" src="{{ URL::asset($pop->img_path) }}" alt="Card image cap">
</figure>
</a>
The modal is also a Vuejs component:
<template>
<section id="pop" class="h-100">
<div class="card">
<div class="container-fluid">
<div class="row">
<div class="col-12 col-lg-1 flex-column others d-none d-xl-block">
<div class="row flex-column h-100">
<div v-for="other_pop in pop.other_pops" class="col">
<a :href="route('frontend.pop.collection.detail', {collection: pop.collection.slug, pop: other_pop.slug})">
<img :src="other_pop.img_path" :alt="'{{ other_pop.name }}'" class="img-fluid">
</a>
</div>
<div class="col active order-3">
<img :src="pop.img_path" :alt="pop.name" class="img-fluid">
</div>
</div>
</div>
<div class="col-12 col-lg-6 content text-center">
<div class="row">
<div class="col-12">
<img :src="pop.img_path" :alt="pop.name" class="img-fluid">
</div>
<div class="col-6 text-right">
<toggle-pop :id="pop.id" :added="pop.in_user_collection" :text="pop.in_user_collection ? 'Supprimer' : 'Ajouter'"></toggle-pop>
</div>
<div class="col-6 text-left">
<!-- <btnaddpopwhishlist :pop_id="propid" :added="pop.in_user_whishlist" :text="pop.in_user_whishlist ? 'Supprimer' : 'Ajouter'"></btnaddpopwhishlist> -->
</div>
</div>
</div>
<div class="col-12 col-lg-5 infos">
<div class="header">
<h1 class="h-100">{{ pop.name }}</h1>
</div>
<div class="card yellow">
<div class="card p-0">
<div class="container-fluid">
<div class="row">
<div class="col-3 py-2">
</div>
<div class="col-6 py-2 bg-lightgray">
<h4>Collection:</h4>
<h3>{{ pop.collection ? pop.collection.name : '' }}</h3>
</div>
<div class="col-3 py-2 bg-lightgray text-center">
<a :href="route('frontend.index') + 'collections/' + pop.collection.slug" class="btn-round right white"></a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</template>
<script>
export default {
props: {
id: Number
},
data() {
return {
pop: {
collection: {
}
}
}
},
ready: function() {
if (this.propid != -1)
this.fetchData()
},
watch: {
id: function(newVal, oldVal) { // watch it
// console.log('Prop changed: ', newVal, ' | was: ', oldVal)
this.fetchData()
}
},
computed: {
imgSrc: function() {
if (this.pop.img_path)
return 'storage/images/pops/' + this.pop.img_path
else
return ''
}
},
methods: {
fetchData() {
axios.get(route('frontend.api.v1.pops.show', this.id))
.then(response => {
// JSON responses are automatically parsed.
// console.log(response.data.data.collection)
this.pop = response.data.data
})
.catch(e => {
this.errors.push(e)
})
// console.log('fetchData')
}
}
}
</script>
Here is my app.js script :
window.Vue = require('vue');
Vue.component('pop-modal', require('./components/PopModal.vue'));
Vue.component('toggle-pop', require('./components/TogglePop.vue'));
const app = new Vue({
el: '#app',
props: {
id: Number
}
});
I would like to sync the states of the component named toggle-pop, how can I achieve this ? One is rendered by Blade template (laravel) and the other one by pop-modal component. But they are just the same, displayed at different places.
Thanks.
You could pass a state object as a property to the toggle-pop components. They could use this property to store/modify their state. In this way you can have multiple sets of components sharing state.
Your component could become:
<template lang="html">
<button type="button" #click="toggle" name="button" class="btn" :class="{'btn-danger': sstate.added, 'btn-primary': !sstate.added}">{{ sstate.text }}</button>
</template>
<script>
export default {
props: {
sstate: {
type: Object,
default: function() {
return { added: false, text: "", id: -1 };
}
}
},
data() {
return {};
},
methods: {
toggle: function(event) {
axios.post(route('frontend.user.profile.pop.toggle', {
pop_id: this.sstate.id
}))
.then(response => {
this.sstate.text = response.data.message
let success = response.data.success
this.sstate.text = response.data.new_text
if (success) {
this.sstate.ddded = success.attached.length
let cardPop = document.getElementById('card-pop-'+this.sstate.id);
if(cardPop)
cardPop.classList.toggle('owned')
}
})
.catch(e => {
console.log(e)
})
}
};
</script>
Live demo
https://codesandbox.io/s/vq8r33o1w7
If you are 100% sure that all toggle-pop components should always have the same state, you can choose to not define data as a function. Just declare it as an object.
data: {
dAdded: this.added,
dText: this.text,
dId: this.id
}
In https://v2.vuejs.org/v2/guide/components.html#data-Must-Be-a-Function, it mentions
a component’s data option must be a function, so that each instance
can maintain an independent copy of the returned data object
If Vue didn’t have this rule, clicking on one button would affect the
data of all other instances
Since you want to sync the data of all toggle-pop component instances, you don't have to follow the data option must be a function rule.
I have a "vue-cli webpack" like the following :
src/components/Signin.vue:
<template>
...
<form v-on:submit.prevent="userSignIn">
...
<div class="field">
<p class="control has-icons-left has-icons-right">
<input
v-validate="'required|email'"
v-bind:class="{'is-danger': errors.has('name')}"
name="email"
v-model="form.email"
class="input"
id="email"
type="email"
placeholder="Email"
>
<span class="icon is-small is-left">
<i class="fa fa-envelope"></i>
</span>
<span class="icon is-small is-right">
<i class="fa fa-check"></i>
</span>
<span class="help is-danger" v-show="errors.has('email')">{{ errors.first('email') }}</span>
</p>
</div>
<div class="field">
<p class="control has-icons-left">
<input
v-validate="'required|min:5'"
v-bind:class="{'is-danger': errors.has('name')}"
name="password"
v-model="form.password"
class="input"
id="password"
type="password"
placeholder="Password"
>
<span class="icon is-small is-left">
<i class="fa fa-lock"></i>
</span>
<span class="help is-danger" v-show="errors.has('password')">{{ errors.first('password') }}</span>
</p>
</div>
<div class="field is-grouped">
<div class="control">
<button v-bind:disabled="errors.any()" class="button is-primary" type="submit" :disabled="loading">
Submit
</button>
</div>
</div>
</form>
...
</template>
<script>
...
export default {
data () {
return {
form: {
email: '',
password: '',
alert: false
}
}
},
computed: {
error () {
return this.$store.getters.getError
},
loading () {
return this.$store.getters.getLoading
}
},
watch: {
error (value) {
if (value) {
this.alert = true
}
},
alert (value) {
if (!value) {
this.$store.dispatch('setError', false)
}
},
methods: {
userSignIn () {
this.$store.dispatch('userSignIn', {email: this.email, password: this.password})
}
}
},
...
}
</script>
src/App.vue:
<template>
<main>
<router-view></router-view>
</main>
</template>
<style lang="sass">
#import "~bulma"
/* Your css for this file... */
</style>
src/main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import firebase from 'firebase'
import { store } from './store'
import VeeValidate from 'vee-validate'
import { firebaseConfig } from './config'
Vue.use(VeeValidate)
Vue.config.productionTip = false
firebase.initializeApp(firebaseConfig)
/* eslint-disable no-new */
const unsubscribe = firebase.auth()
.onAuthStateChanged((firebaseUser) => {
new Vue({
el: '#app',
router,
store,
render: h => h(App),
created () {
store.dispatch('autoSignIn', firebaseUser)
}
})
unsubscribe()
})
and I get two errors when I click the button :
Property or method "userSignIn" is not defined on the instance but
referenced during render. Make sure to declare reactive data
properties in the data option.
Signin.vue?d58e:24 Uncaught TypeError: _vm.userSignIn is not a
function
You've defined your methods inside your watch. Move them outside.
watch: {
error (value) {
if (value) {
this.alert = true
}
},
alert (value) {
if (!value) {
this.$store.dispatch('setError', false)
}
},
},
methods: {
userSignIn () {
this.$store.dispatch('userSignIn', {email: this.email, password: this.password})
}
}
I've got an index component that contains this, in part:
<template>
<ul class="nav navbar-nav navbar-right">
<li v-if="state.user"><a #click.stop="do_logout" v-link="{ path: '/'}">Logout {{ state.user.display_name }}</a></li>
<li v-else v-link-active><a v-link="{ path: '/login' }">Login</a></li>
</ul>
<router-view></router-view>
<template>
<script>
import state from '../state';
import { logout } from '../actions';
export default {
data() {
return {
state
};
},
methods: {
do_logout() {
logout().then(() => this.$router.go('/'));
}
}
}
</script>
And I've got a login component that looks like this:
<template>
<form class="form-signin" #submit.prevent="do_login">
<input type="email" v-model="email" id="inputEmail" class="form-control" placeholder="Email address" required autofocus>
<input type="password" v-model="password" id="inputPassword" class="form-control" placeholder="Password" required>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign In</button>
</form>
</template>
<script>
import { login } from '../../actions';
export default {
data() {
return {
email: '',
password: ''
};
},
methods: {
do_login() {
login(this.email, this.password).then(() => this.$router.go('/'));
}
}
}
</script>
My login and logout methods look like this:
import state from './state';
export const login = (email, pwd) => {
return fetch_post_json('/api/login', {
email,
pwd
}).then(j => state.user = j.user);
};
export const logout = () => _fetch('/api/logout', 'GET', null, false).then(() => state.user = null);
Logging out works fine; clicking the link changes the text and presents the "Login" link. Logging in succeeds in logging in, in the Javascript, but doesn't update the link. I'm forced to reload the page to get the page to render correctly. Why?