In my Vue app I have a main component where I have the following router views:
<router-view></router-view>
<div class="modal">
<router-view name="modal"></router-view>
</div>
In multiple places I want to open specific router-links to open a modal. To reach this I made a route the following way:
{
path: '/visitors/login',
props: true,
components: {
modal: ModalLogin
},
meta: {
modal: true,
}
},
This way the specific modal gets loaded into the modal router-view. The only thing is that the default router-view gets cleared when I do this. Is there a way to prevent the default router-view from changing, so it will keep is active page, and only fill the modal router-view?
As a follow up to my comment, instead of trying to map a modal to a route, I built this sample implementation with Vue 2 and the CLI.
For the routes / or /visitors, the Visitors component/page will be rendered, and you can click the 'Login' button to open the modal.
If you enter the route /visitors/login in the browser address bar, the modal will open over the Visitors page.
router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
import Visitors from '../Visitors.vue'
const routes = [
{
path: '/',
redirect: 'visitors'
},
{
name: 'visitors',
path: '/visitors/:modal?',
component: Visitors,
props: true
}
]
export default new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
App.vue
<template>
<div id="app" class="container">
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App',
components: {
},
data() {
return {
}
}
}
</script>
Visitors.vue
<template>
<div class="visitors">
<h4>Visitors</h4>
<div class="row">
<div class="col-md-4">
<button class="btn btn-secondary" #click="showModal">Login</button>
</div>
</div>
<login-modal v-if="displayLogin" #login-event="login" #close-modal-event="hideModal" />
</div>
</template>
<script>
import LoginModal from './LoginModal.vue';
export default {
components: {
LoginModal
},
props: {
modal: {
type: String,
required: false
}
},
data() {
return {
displayLogin: false
}
},
methods: {
showModal() {
this.displayLogin = true;
},
hideModal() {
this.displayLogin = false;
},
login(user) {
this.hideModal();
// Process login
console.log(user);
}
},
created() {
if (this.$route.params.modal) {
if (this.$route.params.modal === 'login') {
this.displayLogin = true;
}
}
}
}
</script>
LoginModal.vue
<template>
<div class="login-modal">
<div class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Login</h5>
<button type="button" #click="closeModal">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<form #submit.prevent="login">
<div class="form-group">
<label for="username">User Name</label>
<input type="email" class="form-control" id="username" v-model="user.name">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" class="form-control" id="password" v-model="user.password">
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" #click="login">Login</button>
<button type="button" class="btn btn-secondary" #click="closeModal">Close</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
user: {
name: '',
password: ''
}
}
},
methods: {
closeModal() {
this.$emit('close-modal-event');
},
login() {
this.$emit('login-event', this.user)
}
}
}
</script>
<style scoped>
/* Override default value of 'none' */
.modal {
display: block;
}
</style>
Related
I need to make the modal visible on click, I work through components, new Vue constructs do not work
I've never worked with Vue, now I'm asking for help
Error:
64:4 error 'showModal:' is defined but never used no-unused-labels
<template>
<modalPhoto v-if="showModal == 'true'"></modalPhoto>
<div class="block-inputs">
<div class="input-header">
<h3>Photos</h3>
</div>
<div class="photos">
<div class="photo-block">
<img src="../assets/photo.jpg" class="photo modal-img" v-on:click="viewPhoto('true')">
</div>
</div>
</div>
<div class="save-changes">
<div style="margin: 0 auto;">
<button class="button-add button-save">Save</button>
</div>
</div>
<script>
import modalPhoto from './modal/modalPhoto.vue';
export default {
name: 'Photos',
data() {
showModal: false
},
methods: {
viewPhoto() {
this.showModal = true;
}
},
components: {
modalPhoto,
}
}
I need some help displaying a selected an item on the page you are on. I have three component Home, Product, and Index. The Index component is Global component which have a list of items with a route-link attached to them to got to the Product Page (Component) and display the item that was click. I am passing the item in the route-link as params to be able to access the item on the Product page. I am using the Index Component on the Home component to display all item. And when I click an item from the Index component from the Home page, it go to the Product page and display that item. That part is working fine, but when I am on the Product page and I click an item from the Index component, it is not displaying the clicked item in the Product page. I really need some help how to solve this problem.
Main.js code
import Vue from 'vue'
import App from './App'
import router from './router/routes'
import Index from './components/Index'
Vue.component('list-items', Index)
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: {App},
template: '<App/>'
})
Route.js File
import Vue from 'vue'
import Router from 'vue-router'
import Home from '../pages/Home'
import Product from '../pages/Product'
Vue.use(Router)
export default new Router({
routes: [
{
path: '' || '/',
name: 'Home',
component: Home
},
{
path: '/product',
name: 'Product',
component: Product,
props: true
}
],
mode: 'history'
})
Home.vue component
<template>
<div class="container-fluid p-0">
<list-items />
</div>
</template>
<script>
export default {
name: 'Home',
data: () => ({
})
}
Product.vue component
<template>
<div class="container-fluid p-0">
<div class="container-fluid py-5">
<div class="row">
<div class="col-md-7">
<div class="col-md-12">
<img v-bind:src="item.url" alt="" class="img-fluid">
</div>
</div>
<div class="col-md-4 margin-padding-right">
<div class="col-md-12">
<h3>{{$route.params.product.name}}</h3>
<h5 class="price">${{item.price}}</h5>
</div>
</div>
</div>
<br>
<div class="container-fluid">
<div class="col-md-12 related-item">
<h5>Related Items</h5>
</div>
<list-items />
</div>
</div>
</div>
<script>
export default {
name: 'Product',
props: ['product'],
data: () => ({
quantity: 1,
item: {
name: '',
url: ''
}
}),
mounted () {
if (this.product) {
this.item.name = this.product.name
this.item.url = this.product.image
}
},
watch: {
change: function (newValue, oldValue) {
this.item.name = newValue.product.name
}
}
}
</script>
<style lang="scss" scoped>
</style>
This is an image of what I am trying to achieve.
I am new in Vue.js. I want to understand on using component. I tried to import my component to another component but it failed. I am using Laravel 5.8. Below are the error that I received.
Module not found: Error: Can't resolve
'./components/modalAlert.vue
Below are my codes.
app.js
Vue.component('form-to-do', require('./components/formToDo.vue').default);
Vue.component('modal-alert', require('./components/modalAlert.vue').default);
const app = new Vue({
el: '#app',
});
formToDo.Vue
<template>
// form
<modal-alert></modal-alert>
</template>
<script>
import modalAlert from './components/modalAlert.vue';
export default {
components: {
'modal-alert': modalAlert
},
data() {
return {
setErrors: [],
tasks: [],
task: {
id: '',
name: '',
completed: '',
date_completed: ''
},
result: '',
input: {
name: ''
}
};
},
}
</script>
modalAlert.vue
<template>
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
Test
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: ['id'],
data() {
return {
}
},
mounted() {
console.log('Component mounted.')
}
}
</script>
Your components are probably in the same folder. In your component formToDo.vue:
Change this:
import modalAlert from './components/modalAlert.vue';
To this:
import modalAlert from './modalAlert.vue';
To solve the other issue, as #ambianBeing suggested, your component formToDo.vue must have root element to be able to add child component inside it.
<template>
<div> <!-- this is the root -->
<modal-alert></modal-alert>
</div>
</template>
I have 2 modal windows: register and login. When I click to "Sign Up" button, the modal window should change. What should I do?
This is a project link.
https://jsfiddle.net/Alienwave/0kqj7tr1/4/
Vue.component('signup', {
template: '#signup-template'
})
Vue.component('login', {
template: '#login-template',
data() {
return {
loginInput: '',
passwordInput: ''
}
},
methods: {
sendRequest(e) {
//code not here
},
changeModal() {
// THIS!!
}
}
});
new Vue({
el: "#app",
data() {
return {
showLogin: true,
showSignup: false
}
}
});
This is login template:
<template id="login-template">
<transition name="modal">
<div class="login-mask">
<div class="login-wrapper">
<div class="login-container">
<div class="login-footer">
<slot name="footer">
<div class="change-mode">
<button class="change-mode-reg" #click="">Sign up</button> <!-- THIS BUTTON SHOULD CHANGE MODAL! -->
</div>
</slot>
</div>
</div>
</div>
</div>
</transition>
</template>
Register template looks the same.
I cut a big chunk.
This is a good use case for Vue's custom events. I would update your code as follows:
#login-template
...
<div class="login-footer">
<slot name="footer">
<div class="change-mode">
<button class="change-mode-reg" #click="changeModal">Sign up</button>
<div class="change-mode-line"></div>
</div>
</slot>
</div>
...
login component
Vue.component('login', {
template: '#login-template',
data() {
return {
loginInput: '',
passwordInput: ''
}
},
methods: {
sendRequest(e) {
//code not here
},
changeModal() {
this.$emit('change');
}
}
});
#app
<div id="app">
<login v-if="showLogin" #close="showLogin = false" #change="changeModal"></login>
<signup v-if="showSignup" #close="showSignup = false"></signup>
</div>
Here is an updated fiddle.
(NOTE: it looks like you might have some other issues going on here, but this gets your modal switching issue fixed.)
I'm relatively new to Vue and super stuck with this error message when I try to make this reset email modal work in my Vue project:
Property or method "sendResetMail" is not defined on the instance but
referenced during render. Make sure that this property is reactive,
either in the data option, or for class-based components, by
initializing the property.
I have no idea what I need to do to make this work. I followed the Vue documentation and declared resetEmail in the data option.
ForgotPassword.vue:
<template>
<section>
<a #click="isComponentModalActive = true">
Forgot Password?
</a>
<b-modal :active.sync="isComponentModalActive" has-modal-card>
<modal-form v-bind="resetEmail"></modal-form>
</b-modal>
</section>
</template>
<script>
import firebase from 'firebase/app'
import 'firebase/auth'
import 'firebase/firestore'
const ModalForm = {
props: ['resetEmail'],
template: `
<form #submit.prevent="sendResetMail">
<div class="modal-card" style="width: auto">
<header class="modal-card-head">
<p class="modal-card-title">Forgot password?</p>
</header>
<section class="modal-card-body">
<b-field label="Email">
<b-input
type="email"
:value="resetEmail"
placeholder="Your email"
required>
</b-input>
</b-field>
</section>
<footer class="modal-card-foot">
<button class="button" type="button" #click="$parent.close()">Close</button>
<button class="button is-primary">Reset</button>
</footer>
</div>
</form>
`
}
export default {
components: {
ModalForm
},
data () {
return {
isComponentModalActive: false,
resetEmail: '',
feedback: null
}
},
methods: {
sendResetMail () {
var auth = firebase.auth()
var emailAddress = this.resetEmail
auth.sendPasswordResetEmail(emailAddress).then(function () {
// Email sent.
console.log('email send')
}).catch(function (error) {
// An error happened.
this.feedback = error.message
console.log(error.message)
})
}
}
}
</script>
This is the file where I use the ForgotPassword.vue component,
Login.vue:
<template>
<section class="section">
<div class="container">
<div class="columns">
<div class="column"></div>
<div class="column is-half">
<div class="box">
<h1 class="title">Login</h1>
<form #submit.prevent="login">
<b-field label="Email" :message="feedback" :type="type">
<b-input placeholder="Email" icon="email" type="email" v-model="email">
</b-input>
</b-field>
<b-field label="Password" :message="feedback" :type="type">
<b-input placeholder="Password" type="password" icon="textbox-password" password-reveal v-model="password">
</b-input>
</b-field>
<button type="submit" class="button is-primary is-fullwidth">Login</button>
<div class="field">
<div class="control">
<p class="control has-text-centered">
<ForgotPassword/>
</p>
</div>
</div>
<div class="field">
<div class="control">
<p class="control has-text-centered">
Don't have an account?
<a href="/register">
<router-link :to="{ name: 'Signup' }">
Signup
</router-link>
</a>
</p>
</div>
</div>
</form>
</div>
</div>
<div class="column"></div>
</div>
</div>
</section>
</template>
<script>
import firebase from 'firebase/app'
import 'firebase/auth'
import 'firebase/firestore'
import ForgotPassword from '#/components/auth/ForgotPassword'
export default {
name: 'login',
metaInfo: {
// specify a metaInfo.title, this title will be used
title: 'Login',
// all titles will be injected into this template
titleTemplate: '%s | Wterdrops.com'
},
components: {
ForgotPassword
},
data () {
return {
email: null,
password: null,
feedback: null,
type: null
}
},
methods: {
login () {
if (this.email && this.password) {
firebase
.auth()
.signInWithEmailAndPassword(this.email, this.password)
.then(cred => {
this.$router.push({
name: 'Dashboard'
})
})
.catch(err => {
this.feedback = err.message
})
this.feedback = null
} else {
this.feedback = 'Please fill in both fields.'
this.type = 'is-danger'
}
}
}
}
</script>
<style>
.login {
max-width: 400px;
margin-top: 60px;
}
</style>
I would be very grateful if someone can explain to me what I'm missing :)
You are referencing
<form #submit.prevent="sendResetMail">
inside your ModalForm component.
The problem is that this template is going to look for the method sendResetMail on that ModalForm component template when it gets rendered since you the code is referencing it. However this sendResetMail method is not directly associated on that.
You can consider using a mix-in if you need to use the sendResetMail in many places , or maybe just move that method directly to the same component "ModalForm" that is referencing it.
You can also look into for example eventBus to trigger the method by emitting an event.
The simplest option if you only need to call it from the MOdalForm component is to just move the sendResetMail direcly to that component. I believe that would probably fix your issue.