When I click in a router-link to go to register-form page, the URL changes, but the component doesn´t load.
I have the navbar in a component, and I thought that it was wrong, but no...
Here's the router's file code:
import {createRouter, createWebHashHistory} from 'vue-router'
const routes = [
{
path: '/',
name: 'Home',
component: () => import(/* webpackChunkName: "home" */ '../views/Home.vue')
},
{
path: '/formulario-registro',
name: 'RegisterForm',
component: () => import(/*webpackChunkName: "registerform"*/ '../views/RegisterForm.vue')
}
]
const router = createRouter({
history: createWebHashHistory(),
routes
});
export default router
And here's my nav componet, where there are the router-link:
<div class="nav">
<div class="brand">
<router-link to="/">BookArt</router-link>
</div>
<div class="collapse">
<span id="mobile-icon" v-on:click="responsiveNavbar"></span>
</div>
<div class="links">
<ul id="nav-list-group">
<li class="list-item">
<router-link to="/"> Inicio</router-link>
</li>
<li class="list-item">
<router-link to="/formulario-registro"> Registro</router-link>
</li>
<li class="list-item">
<router-link to=""> Login</router-link>
</li>
</ul>
</div>
My main.js code:
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
createApp(App).use(store).use(router).mount('#app')
And my App.vue code:
<template>
<Nav></Nav>
<router-view/>
</template>
<script>
import Nav from '#/components/Nav.vue'
export default {
components: {
Nav
}
}
</script>
Here's my register-form component's code:
<template>
<form action="">
<div class="form-group">
<input type="text" name="form.username" id="form.username" class="username" placeholder="Nombre de usuario....">
</div>
<div class="form-group">
<input type="file" name="form.profile_pic" id="form.profile_pic" class="profile_pic"
placeholder="Foto de perfil....">
</div>
<div class="form-group">
<input type="email" name="form.email" id="form.email" class="email" placeholder="Email....">
</div>
<div class="form-group">
<input type="password" name="form.password" id="form.password" class="password" placeholder="*******">
</div>
<div class="form-group">
<input type="password" name="form.confirm_password" id="form.confirm.password" class="confirm_password"
placeholder="*******">
</div>
<div class="form-group">
<button>Registrarse</button>
</div>
</form>
</template>
<script>
export default {
name: "Register-form",
mounted() {
console.log('Its ok');
}
}
</script>
The issue is in ../view/RegisterForm component which renders itself :
<template>
<RegisterForm></RegisterForm><!-- this is the component itself not th child one-->
</template>
<script>
import RegisterForm from '#/components/Register-form';
export default {
components: {
RegisterForm
},
name: "RegisterForm"
}
</script>
<style scoped>
</style>
this generates an infinite loop, to solve this just change the name of imported component :
<template>
<RegisterForm1></RegisterForm1>
</template>
<script>
import RegisterForm1 from '#/components/RegisterForm1';
export default {
components: {
RegisterForm1
},
name: "RegisterForm"
}
</script>
<style scoped>
</style>
change in App.vue =>
<template>
<router-view />
</template>
<template>
<router-view :key="$route.path" />
</template>
Related
When logging in, I want to show the user in the header.
I want to separate before and after login using v-if.
The response received upon successful login is
access_token: "token"
token_type: "bearer"
user: "test18"
I haven't used stores like Vuex and Pinia yet.
How should I display the user in the header? I wonder how.
Is there a way to get the username of a setItem in local storage?
Sorry if this was a basic question to you. i can't find any reference documentation for v-if user display, so I'm leaving a post.
login.vue
<template class="login">
<div class="login_box">
<h3>welcome!</h3>
<div class="login_form">
<form #submit.prevent="submit()">
<div class="login_id">
<input
v-model="state.login.loginId"
type="email"
placeholder="E-mail" />
<span class="login_icon">
<img src="../../public/images/people_icon.svg" />
</span>
</div>
<div class="login_pass">
<input
v-model="state.login.loginPw"
type="password"
placeholder="password" />
<span class="login_icon">
<img src="../../public/images/lock.svg" />
</span>
</div>
<p class="login_go">
Not id.
<router-link to="/signup">
<span>signup</span>
</router-link>
</p>
<button
class="login_btn">
Login
</button>
</form>
</div>
</div>
</template>
<script>
import axios from 'axios'
import { useRouter } from 'vue-router'
import { reactive } from 'vue'
export default {
setup() {
const router = useRouter()
const state = reactive({
login: {
loginId: '',
loginPw: '',
},
})
const submit = async () => {
const args = new FormData()
args.append('username', state.login.loginId)
args.append('password', state.login.loginPw)
console.log(state.login)
try {
await axios.post('http://127.0.0.1:8000/login/token', args, {
header: { 'Content-Type': 'application/json'}, withCredentials:true
})
.then((res) => {
console.log(res.data)
localStorage.setItem('loginId', state.login.loginId)
localStorage.setItem('access_token', `Bearer ${res.data.access_token}`)
document.cookie = `access_token=Bearer ${res.data.access_token}`
})
alert('welcome')
router.push({
name: 'home',
params: {
args
}
})
} catch (error){
alert('Login Faild')
console.error(error)
}
}
return { state, submit }
},
}
</script>
heade.vue
<template>
<div class="header">
<div class="header_wrap">
<img
class="logo"
style="cursor:pointer"
#click="dashboard()" />
<ul class="gnb">
<li>
<router-link to="/service_center/notice">
Service center
</router-link>
</li>
</ul>
<ul class="tnb" v-if=loggin>
<li>
{{ $route.params.loginId}}
</li>
<li>
logout
</li>
</ul>
<ul class="tnb" v-else>
<li>
<router-link to="/login">
login
</router-link>
</li>
<li>
<router-link to="/signup">
signup
</router-link>
</li>
</ul>
</div>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
const dashboard = () => {
router.push({
path:'/home',
})
}
</script>
layout.vue
<template>
<ToHeader />
<router-view />
<ToFooter />
</template>
<script setup>
import ToHeader from '~/components/ToHeader.vue'
import ToFooter from '~/components/ToFooter.vue'
</script>
<style>
.margin-top{
margin-top: 150px;
}
</style>
I am working on a small Todo App with Vue 3.
In App.vue I have the 3 child components and the methods:
<template>
<div id="app">
<Header/>
<List/>
<Footer/>
</div>
</template>
<script>
import axios from 'axios'
import Header from './components/Header.vue'
import List from './components/List.vue'
import Footer from './components/Footer.vue'
export default {
name: 'App',
components: {
Header,
List,
Footer
},
props: ['todos'],
data() {
return {
url: "https://jsonplaceholder.typicode.com/todos?&_limit=5",
dataIsLoaded: false,
isValidInput: true,
todos: [],
unsolvedTodos: [],
newTitle: "",
}
}
}
</script>
In List.vue I have:
<template>
<div>
<h1>List</h1>
<ul class="todo-list" v-if="dataIsLoaded">
<TodoItem v-for="todo in todos.slice().reverse()" :key="todo.id" v-bind:class="{done: todo.completed}" :todo="todo" />
</ul>
</div>
</template>
<script>
import TodoItem from "./TodoItem.vue";
export default {
name: 'List',
components: { TodoItem },
props: ['todos']
}
</script>
In TodoItem.vue:
<template>
<li>
<input type="checkbox" :checked="todo.completed" #change="toggleTodo(todo)" />
<span class="title">{{todo.title}}</span>
<button #click="deleteTodo(todo.id)">
<i class="fa fa-trash" aria-hidden="true"></i>
</button>
</li>
</template>
<script>
export default {
name: 'TodoItem',
props: ['todo']
}
</script>
The todo list's <h1> heading is displayed, but the unordered list of todos is not.
Introducing props: ['todos'] in App.vue throws the error Duplicated key 'todos'.
What am I missing?
On your App.vue you defined props['todos'] and at the same time todos is defined in your data(). That might be the one causing the error.
Looks like you forgot to define dataIsLoaded in List.vue. It either needs to be defined in data or be a computed property.
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>
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 trying to create a Vue-Routes application in which it should be possible to change colors of two divs in index.html by writing the name of the selected colors in two input fields. This is a bit complicated since this is a routes app. How do I accomplish this task?
The finished application should have this functionality: Codepen.
index.js (Routes)
import ColorPage from '../components/colorPage.js'
const routes = [
{path: '/', component: ColorPage},
];
const router = new VueRouter({
routes
});
var vm = new Vue({
el: '.container',
router,
});
ColorPage.js
const ColorPage = {
props:
['bga', 'bgb'],
data() {
bga: {
backgroundColor: ''
},
bgb: {
backgroundColor: ''
}
},
template: `
<div id="middle">
<label id="colorLabel"><h2>'Change Colors By Typing Their Names:'</h2></label>
</br>
<input type="text" class="colorInput" v-on:input="bga.backgroundColor = $event.target.value" placeholder="here...">
</br>
<input type="text" class="colorInput" v-on:input="bgb.backgroundColor = $event.target.value" placeholder="... and here!">
</div>
`,
};
export default ColorPage
Index.html
<body>
<div class="container" v-bind:style="bga">
<div class="top" v-bind:style="bgb">
<div id="app">
<h1 id="vueHead">Vue routing</h1>
<h2 class="menu">
<router-link to="/">Color</router-link>
<router-link to="/main">Main</router-link>
<router-link to="/settings">Settings</router-link>
<router-link to="/vue">Vue</router-link>
</h2>
</div>
</div>
<router-view></router-view>
</div>
</body>
You need to define bga and bgb in parent also
const ColorPage = {
props:['bga','bgb'],
template: `
<div id="middle">
<label id="colorLabel"><h2>Change Colors By Typing Their Names:</h2></label>
</br>
<input type="text" class="colorInput" v-model="$parent.bga" placeholder="here...">
</br>
<input type="text" class="colorInput" v-model="$parent.bgb" placeholder="... and here!">
</div>
`
};
const routes = [
{path: '/', component: ColorPage}
];
const router = new VueRouter({
routes
});
var vm = new Vue({
el: '.container',
router,
data:{
bga:'',
bgb:''
}
});
<script type="text/javascript" src="https://unpkg.com/vue#2.5.16/dist/vue.js"></script>
<script type="text/javascript" src="https://unpkg.com/vue-router#2.7.0/dist/vue-router.js"></script>
<div class="container">
<div v-bind:style="bga">
<div class="top" v-bind:style="'background-color:'+bga+';'">
<div id="app">
<h1 id="vueHead" v-bind:style="'color:'+bgb+';'">Vue routing</h1>
<h2 class="menu">
<router-link to="/">Color</router-link>
<router-link to="/main">Main</router-link>
<router-link to="/settings">Settings</router-link>
<router-link to="/vue">Vue</router-link>
</h2>
</div>
</div>
<router-view></router-view>
</div>
</div>
Another way is by $parent
const ColorPage = {
data:function(){
return {
bga: this.$parent.bga,
bgb: this.$parent.bgb,
}
},
methods:{
changeBgaColor:function(){
this.$parent.bga = this.bga;
},
changeBgbColor:function(){
this.$parent.bgb = this.bgb;
}
},
template: `
<div id="middle">
<label id="colorLabel"><h2>Change Colors By Typing Their Names:</h2></label>
</br>
<input type="text" class="colorInput" v-on:keyup="changeBgaColor" v-model="bga" placeholder="here...">
</br>
<input type="text" class="colorInput" v-on:keyup="changeBgbColor" v-model="bgb" placeholder="... and here!">
</div>
`
};
const routes = [
{path: '/', component: ColorPage}
];
const router = new VueRouter({
routes
});
var vm = new Vue({
el: '.container',
router,
data:{
bga:'',
bgb:''
}
});
<script type="text/javascript" src="https://unpkg.com/vue#2.5.16/dist/vue.js"></script>
<script type="text/javascript" src="https://unpkg.com/vue-router#2.7.0/dist/vue-router.js"></script>
<div class="container">
<div v-bind:style="bga">
<div class="top" v-bind:style="'background-color:'+bga+';'">
<div id="app">
<h1 id="vueHead" v-bind:style="'color:'+bgb+';'">Vue routing</h1>
<h2 class="menu">
<router-link to="/">Color</router-link>
<router-link to="/main">Main</router-link>
<router-link to="/settings">Settings</router-link>
<router-link to="/vue">Vue</router-link>
</h2>
</div>
</div>
<router-view></router-view>
</div>
</div>