How to simply navigate from One Component (Home Page ) to Another Component by clicking button using Router concept in Vue.js - vue.js

I know basics of html, css and js. I have just started learning Vue.js. There is a Home Page in my Vue JS Application which has two buttons. On Click of that button, navigation should happen. (New Component to be loaded). But, in the current code, on button click, navigation is not happening. Please Assist. Copying few file as seen below.
App.vue
<template>
<h3> Home </h3>
<button #click="goToCreate()"> Create Package </button>
<br><br>
<button #click="goToEdit()"> Update Package </button>
</template>
<script>
export default {
name: 'App',
components: {
},
methods:{
goToCreate(){
this.$router.push('/createpackage');
},
goToEdit(){
this.$router.push('/updatepackage');
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
main.js
import { createApp } from 'vue'
import { createRouter, createWebHistory } from 'vue-router'
import App from './App.vue'
import CreatePackage from './components/CreatePackage.vue'
import SearchAndUpdatePackage from './components/SearchAndUpdatePackage.vue'
const router = createRouter({
history: createWebHistory(),
routes:[
{
path : '/createpackage',
component:CreatePackage
},{
path : '/updatepackage',
component:SearchAndUpdatePackage
}
]
})
const app= createApp(App);
app.use(router).mount('#app')
config.js
let baseUrl = ''
if (process.env.NODE_ENV === 'production') {
baseUrl = 'http://yourdomain.com/api/'
}
else {
baseUrl = 'http://localhost:9000/'
}
export const apiHost = baseUrl
CreatePackage.vue
<template>
<div>
<form name="createPackageForm" #submit="submitNewPackage" method="post">
<input type="number" name="noOfPostpaid" placeholder="PostPaid" v-model="posts.noOfPostpaid">
<br> <br> <br>
<input type="number" name="noOfPrepaid" placeholder="PrePaid" v-model="posts.noOfPrepaid">
<br> <br> <br>
<button>Submit</button>
</form>
</div>
</template>
<script>
import { apiHost } from '../config'
import axios from 'axios'
export default {
name:"CreatePackage",
data(){
return{
posts: {
noOfPostpaid:null,
noOfPrepaid:null
}
}
},
methods:{
submitNewPackage(e){
console.warn(apiHost+'tdg/createpackage/'+this.posts.noOfPostpaid+'/'+this.posts.noOfPrepaid);
e.preventDefault();
axios.post(apiHost+'tdg/createpackage/'+this.posts.noOfPostpaid+'/'+this.posts.noOfPrepaid,{
headers: {
"Access-Control-Allow-Origin": "*"
}},null).then(
response => {
console.log(response.data)}
).catch(e => {
console.log(e);
})
this.posts.noOfPostpaid='';
this.posts.noOfPrepaid='';
}
}
}
</script>
SearchAndUpdatePackage.vue
<template>
<div>
<input type="search" name="accountUUID" placeholder="Account UUID" v-model="posts.accountUUID">
<br> <br> <br>
<button #click="searchAccountUUID">Search </button>
<br> <br> <br>
<textarea id="myTextArea" cols=100 rows=20 v-model="posts.responseJSON"></textarea>
</div>
</template>
<script>
import { apiHost } from '../config'
export default {
name:"SearchAndUpdatePackage",
data(){
return{
posts: {
accountUUID:null,
responseJSON:null
},
}
},
methods:{
searchAccountUUID(e){
const url=apiHost+'tdg/carbon/'+this.posts.accountUUID;
console.log(url);
e.preventDefault();
fetch(url).then(response => response.json())
.then(data=>this.posts.responseJSON=JSON.stringify(data,null,4))
.catch(e => {
console.log(e);
})
console.log(this.posts.responseJSON);
}
}
}
</script>

With Vue-Router, you need to use the router-view component. When you navigate to a URL defined in your routes config, Vue-Router will match that URL and display the associated component.
It's common to place it in App.vue:
<template>
<h3> Home </h3>
<button #click="goToCreate()"> Create Package </button>
<br><br>
<button #click="goToEdit()"> Update Package </button>
<router-view />
</template>
<script>
export default {
name: 'App',
methods: {
goToCreate() {
this.$router.push('/createpackage');
},
goToEdit() {
this.$router.push('/updatepackage');
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
You might have an issue with it being a direct descendent of <template>, but I'm not sure.

Related

I'm trying to make my button a route that shows a modal, but I want to stay on the same page

When I'm on the Home page, I want to click on the Login button in the Header and when I click, the Login modal is displayed, which is a separate component, but I want to stay on the Home page and not be redirected to another page.
Login component:
<script setup>
import { ref, onMounted } from 'vue'
import VueCookies from 'vue-cookies'
import axios from 'axios';
const LogInModalVisible = ref(false)
var baseURL = 'http://localhost:3000/'
var userURL = baseURL + "users";
let users = ref(null)
let email = ref(null)
let password = ref(null)
let emailError = ref(null)
let passwordError =ref(null)
let passwordValidation = ref(false)
onMounted(async () => {
try {
const res = await axios.get(baseURL + 'users');
users = res.data;
/* console.log(users) */
/* loginSubmit() */
} catch (e) {
console.error(e)
}
})
async function loginSubmit()
{
if(email.lenght == 0)
{
this.emailError = "Field is empty"
}
else
{
this.emailError = null
}
if(password.length == 0)
{
this.passwordError = "Field is empty!";
}
else if(password.length>0 && password.length<8)
{
this.passwordError = "Password is too short!"
}
else
{
this.passwordError = null
}
/* const res = await axios.get(userURL);
this.users = res.data; */
for (var i = 0; i <users.length; i++)
{
if (this.users[i].email == this.email.value)
{
if (this.users[i].password == this.password.value)
{
this.passwordValidation = true;
VueCookies.set('username', this.users[i].username, "120min");
VueCookies.set('email', this.email.value, "120min");
VueCookies.set('password', this.password.value, "120min");
VueCookies.set('id', this.users[i].id, "120min");
window.location.href = '/';
alert("Login successful");
}
}
}
if(this.passwordValidation == false){ this.passwordError = "Inccorect password or username!"}
}
</script>
<template>
<el-dialog v-model="LogInModalVisible" title="LogIn" width="50%" height="50%" center>
<el-form label-position='top' status-icon :label-width="80">
<el-form-item label="Email">
<el-input type="email" id='email' placeholder="Enter Email" v-model="email" />
<div class="input-message" v-if="emailError"><h6>{{emailError}}</h6></div>
</el-form-item>
<el-form-item label="Password">
<el-input type="password" id='password' placeholder="Enter Password" v-model="password" />
<div class="input-message" v-if="passwordError"><h6>{{passwordError}}</h6></div>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button #click="LogInModalVisible = false">Cancel</el-button>
<el-button type="primary" #click="LogInModalVisible = false; loginSubmit()">
Confirm
</el-button>
</span>
</template>
</el-dialog>
</template>
<style>
</style>
Header component:
<script setup>
import {Sunny, Moon} from '#element-plus/icons-vue'
import { ref, onMounted } from 'vue'
import { RouterLink } from 'vue-router'
import Home from '../views/Home.vue'
import { pokeStore } from '../store/store'
import VueCookies from 'vue-cookies'
import axios from 'axios';
import Pokedex from './Pokedex.vue'
const pokedexVisible = ref(false)
const PokemonStore = pokeStore();
let allpokemons = []
async function GetAllPokemons() {
try {
let response = await PokemonStore.getPokemonData();
allpokemons.value = response.data.results;
let randomPokemon = allpokemons.value[Math.floor(Math.random() * 151) + 1]
console.log(randomPokemon)
} catch (error) {
throw error;
}
}
GetAllPokemons()
</script>
<template>
<el-header class="navbar">
<div class="navbar-content">
<div>
<router-link to="/" custom v-slot="{ navigate }">
<img #click="navigate" role="link" class="logo" src="/src/assets/images/logo.png" />
</router-link>
</div>
<el-space size="large">
<div>
<input class="search" type="text" placeholder="Search pokemon" />
</div>
<div>
<el-button link><el-icon :size="20">
<Sunny />
</el-icon></el-button>
<el-button link><el-icon :size="20">
<Moon />
</el-icon></el-button>
</div>
<div>
<el-button #click="pokedexVisible = true" class="pokedexBtn">Pokedex</el-button>
<!-- <router-link #click="pokedexVisible = true" to="/pokedex" class="nav-link">Pokedex</router-link> -->
</div>
<div>
<el-button #click="LogInModalVisible = true" text>LogIn</el-button>
<router-link to="/login" custom v-slot="{ navigate }">
<button #click="navigate" role="link">
Login
</button>
</router-link>
</div>
</el-space>
</div>
</el-header>
</template>
<style scoped>
.navbar {
background-color: whitesmoke;
padding: 5px 30px;
position: fixed;
top: 0;
left: 0;
right: 0;
opacity: 0.9;
}
.navbar-content{
align-items: center;
justify-content: space-between;
display: flex;
}
.logo{
width: 100%;
max-width: 50px;
display: block;
}
.search{
display: block;
padding: 5px;
border-radius: 4px;
font-size: 14px;
width: 100%;
background-color: transparent;
float: right;
}
.search::placeholder {
opacity: 0.5;
}
.navbar-right{
align-items: center;
justify-content: space-between;
}
.pokedexBtn{
background-color: black;
color: whitesmoke;
}
</style>
Index.js component:
import { createRouter, createWebHistory } from 'vue-router'
import Login from '../components/Login.vue'
import Home from '../views/Home.vue'
import Pokedex from '../components/Pokedex.vue'
import App from '/src/App.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/pokedex',
name: 'Pokedex',
component: Pokedex
},
{
path: '/login',
name: 'Login',
component: Login
},
]
})
export default router
When I'm on the Home page, I want to click on the Login button in the Header and when I click, the Login modal is displayed, which is a separate component, but I want to stay on the Home page and not be redirected to another page.
I haven't tested this but it would be something like this.
<script setup>
import {Sunny, Moon} from '#element-plus/icons-vue'
import { ref, onMounted } from 'vue'
import { RouterLink } from 'vue-router'
import Home from '../views/Home.vue'
import { pokeStore } from '../store/store'
import VueCookies from 'vue-cookies'
import axios from 'axios';
import Pokedex from './Pokedex.vue'
const pokedexVisible = ref(false)
const PokemonStore = pokeStore();
let allpokemons = []
async function GetAllPokemons() {
try {
let response = await PokemonStore.getPokemonData();
allpokemons.value = response.data.results;
let randomPokemon = allpokemons.value[Math.floor(Math.random() * 151) + 1]
console.log(randomPokemon)
} catch (error) {
throw error;
}
}
GetAllPokemons()
import { LoginModal } from 'somewhere/LoginModal.vue';
const showLoginModal = ref(false);
</script>
<template>
<el-header class="navbar">
<div class="navbar-content">
<div>
<router-link to="/" custom v-slot="{ navigate }">
<img #click="navigate" role="link" class="logo" src="/src/assets/images/logo.png" />
</router-link>
</div>
<el-space size="large">
<div>
<input class="search" type="text" placeholder="Search pokemon" />
</div>
<div>
<el-button link><el-icon :size="20">
<Sunny />
</el-icon></el-button>
<el-button link><el-icon :size="20">
<Moon />
</el-icon></el-button>
</div>
<div>
<el-button #click="pokedexVisible = true" class="pokedexBtn">Pokedex</el-button>
<!-- <router-link #click="pokedexVisible = true" to="/pokedex" class="nav-link">Pokedex</router-link> -->
</div>
<div>
<el-button #click.prevent="showLoginModal = true" text>LogIn</el-button>
</div>
</el-space>
</div>
</el-header>
<LoginModal v-if="showLoginModal">
</template>

Nuxt - Using router.push inside a component not changing pages correctly

index.vue -
<template>
<div>
<Header />
<div class="container">
<SearchForm />
</div>
</div>
</template>
<script>
const Cookie = process.client ? require('js-cookie') : undefined
export default {
data() {
return {
form: {
email: '',
password: ''
},
show: true
}
},
methods: {
logout() {
// Code will also be required to invalidate the JWT Cookie on external API
Cookie.remove('auth')
this.$store.commit('setAuth', {
auth: null,
user_type: null
})
}
}
}
</script>
<style>
.container {
/* margin: 0 auto; */
/* min-height: 100vh; */
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
</style>
jobs.vue -
<template>
<div>
<Header />
<SearchForm />
<b-container class="main_container">
<b-row>
<h1> Results for "{{q}}"</h1>
</b-row>
<b-row>
<ul id="array-rendering">
<li v-for="item in results" :key="item.job_id">
{{ item.job_title }}
{{ item.job_city }}
{{ item.job_state }}
{{ item.job_work_remote }}
</li>
</ul>
</b-row>
</b-container>
</div>
</template>
<script>
const Cookie = process.client ? require('js-cookie') : undefined
export default {
// middleware: 'notAuthenticated',
watchQuery: ['q'],
data() {
return {
q: null,
results: []
}
},
async fetch() {
this.q = this.$route.query.q
this.results = await this.$axios.$get('/api/job/search', {
params: {
keyword: this.q,
}
})
},
methods: {
}
}
</script>
<style>
.container {
align-items: center;
text-align: center;
}
</style>
SearchForm.vue component -
<template>
<div id='searchFormDiv'>
<b-form inline #submit.prevent="onSubmit">
<label class="sr-only" for="inline-form-input-name"> keyword</label>
<b-form-input v-model="form.keyword" id="inline-form-input-name" class="mb-2 mr-sm-2 mb-sm-0" placeholder="Job title or keyword" size="lg"></b-form-input>
<label class="sr-only" for="inline-form-input-username">location</label>
<b-input-group class="mb-2 mr-sm-2 mb-sm-0">
<b-form-input v-model="form.location" id="inline-form-input-username" size="lg" placeholder="City, state or zip"></b-form-input>
</b-input-group>
<b-button type="submit" variant="primary">Find Jobs</b-button>
</b-form>
</div>
</template>
<script>
import {
BIconSearch,
BIconGeoAlt
} from 'bootstrap-vue'
export default {
data() {
return {
form: {
keyword: '',
location: ''
}
}
},
created () {
this.form.keyword = this.$route.query.q
},
methods: {
onSubmit() {
this.$router.push({
path: 'jobs',
query: {
q: this.form.keyword
}
});
}
},
components: {
BIconSearch,
BIconGeoAlt
},
}
</script>
<style>
#searchFormDiv {
margin-top: 50px
}
</style>
The route for "http://localhost:3000/" returns the index.vue page.
In this vue page, I have a component with a search form. Once you complete these form and hit the seach button, it will re-direct to a results page
if this.form.keyword = "Data", the next URL will be "http://localhost:3000/jobs?q=Data" and it will be using the jobs.vue page.
The issue I'm running into is the CSS is not being loaded from the jobs.vue page. It's still coming from the index.vue page for some reason. If I refresh the page, then the CSS from jobs.vue is loading. I need the CSS to load from jobs.vue on the initial redirect. All of the query data is working as expected so thats a plus.
However, the following CSS is being applied from index.vue for some reason instead of the CSS from the jobs.vue page -
display: flex;
justify-content: center;
Does anyone know whats going on here? This app is SSR and not SPA.
You have to scope your css from the index.vue page to the other pages with the scoped directive (see docs https://vue-loader.vuejs.org/guide/scoped-css.html)
<style scoped>
/* local styles */
</style>
<style>
/* global styles */
</style>
You can add your global CSS in your layouts/default.vue file.
This solved the issue -
methods: {
onSubmit() {
window.location = 'http://localhost:3000/jobs?q=' + this.form.keyword;
}
},

Error message when trying to pass data from component to page in Nuxt

I've created a component in Nuxt to get data from a Firestore database and would like to show that data in a page I created.
When I embed the component in a page I keep getting the error:
Property or method "provinces" 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.
Now, when I copy the code from the component in the page it works just fine, so I assume the problem is with passing the data between the component and the page.
Full code of the component in components/index.vue :
<template>
<section class="container">
<div class="index">
<div v-for="province in provinces" :key="province.id">
<div class="div_title">
<h2>{{ province.name_nl }}</h2>
</div>
</div>
</div>
</section>
</template>
<script>
// import { VueperSlides, VueperSlide } from 'vueperslides'
// import 'vueperslides/dist/vueperslides.css'
import firebase from 'firebase'
// import fireDb from '#/plugins/firebase.js'
export default {
name: 'Index',
components: {
// VueperSlides,
// VueperSlide
},
data: function() {
return {}
},
async asyncData() {
const moment = require('moment')
const date = moment(new Date()).format('YYYY-MM-DD')
const housesArray = []
const provincesArray = []
await firebase
.firestore()
.collection('provinces')
.orderBy('name_nl')
.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
provincesArray.push(doc.data())
})
})
await firebase
.firestore()
.collection('houses')
.where('valid_until', '>', date)
.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
housesArray.push(doc.data())
})
})
return {
provinces: provincesArray,
houses: housesArray
}
}
}
</script>
<style scoped>
div {
text-align: center;
}
h2 {
margin-top: 5vh;
margin-left: auto;
margin-right: auto;
width: 95vh;
}
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
p {
text-align: left;
}
li {
min-width: 100% !important;
margin-left: 0px;
text-align: left;
}
</style>
Page where I insert the component in pages/index.vue:
<template>
<v-layout column justify-center align-center>
<v-flex xs12 sm8 md6>
<div class="text-xs-center">
<logo />
<tabs />
<index />
</div>
</v-flex>
</v-layout>
</template>
<script>
import Logo from '~/components/Logo.vue'
import Tabs from '~/components/Tabs.vue'
import firebase from 'firebase'
import Index from '~/components/Index.vue'
export default {
components: {
Logo,
Tabs,
Index
},
data: function() {
return {}
}
}
</script>
I would expect the page to display the data that I retrieved when I import the component into the page but I keep getting the same error.
Should I be using the Nuxt store to transfer data between a component and a page or am I doing something else wrong?
The lifecycle hook asyncData is not know within Vue components. It's only known in Nuxt pages.
It's better to do the data request within your pages component and pass it as a property to your component:
pages/index.vue
<template>
<index :houses="houses" />
</template>
<script>
const delay = time => new Promise(resolve => setTimeout(resolve, time));
export default {
async asyncData() {
// fake data
await delay(500);
return {
houses: [...]
}
}
}
</script>
components/index.vue
<template>
<pre>{{ houses }}</pre>
</template>
<script>
export default {
props: {
houses: {
required: true,
type: Array
}
}
}
</script>

In vue js mdb footer get break how to solve this problem?

I am using mdb theme when the project is uploaded on aws instance footer gets break on right side. I checked the css the width of footer is 100% by default for mdb theme.
Below is the code-
App.vue
<template>
<div id="app">
<div class="flexible-content">
<navbar :page="activePage" />
<main class="mt-5 p-5">
<div class="pt-5">
<router-view></router-view>
</div>
</main>
<div class="white-skin">
<copyrights />
</div>
</div>
</div>
</template>
<script>
import SideNav from './components/SideNav'
import Navbar from './components/Navbar'
import Copyrights from './components/Footer'
import * as vm from "vue";
export default {
name: 'App',
mode:'history',
components: {
SideNav,
Navbar,
Copyrights
},
data () {
return {
activePage: 'dashboard',
toggle: false,
loader:true,
}
},
mounted () {
this.activePage = this.$route.name;
this.$on('toggle', function (value) {
this.toggle = value
});
},
updated () {
this.activePage = this.$route.name
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
Footer.vue
<template>
<mdb-footer>
<p class="footer-copyright mb-0 py-3 text-center">
© {{new Date().getFullYear()}} Copyright: xyz
</p>
</mdb-footer>
</template>
<script>
import { mdbFooter } from 'mdbvue'
export default {
name: 'Footer',
components: {
mdbFooter
},
data () {
return {
}
}
}
</script>
<style scoped>
</style>
This is the code of App.vue and Footer.vue .It is perfectly working on localhost but not on instance. After upload on instance footer gets break from right side

Could Vue.js router-view name be changed?

I am new to Vue.js and I know there is more than one component in a route with different names.
In App.vue file, could <router-view name="default"> be changed to other name? Thank you for your help.
HelloWorld.vue
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h2>Essential Links</h2>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
App.vue
<template>
<div id="app">
<!-- <img src="./assets/logo.png"> -->
<router-view name="default"></router-view>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
index.js
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '#/components/HelloWorld'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
}
]
})
You need dynamic components for this,
Html code
<template>
<div id="app">
<router-view :is="currentComponent"></router-view>
</div>
</template>
Js code: here depending on isTrue value set whichever component you need.
<script>
export default {
name: 'App' ,
components: {
LoginComponent,
HelloComponent
},
computed: {
currentComponent () {
return isTrue ? 'HelloComponent' : 'LoginComponent'
}
}
}
</script>