passing data between components not working - vue.js

i have been struggling for hours on this one, i am a newbie in vuejs basically i have a modal based on tabs and i want to show some data into the modal-content of my modal, the place where click event of open modal occurs is in another vue file and the place where i want to populate the modal content is in another vue,here's my code
main blade file
#section('main-content')
<div class="full-page-taps">
<div class="page-head p-4 mb-lg-4">
<h3>Directory</h3>
</div>
<div class="container">
<div class="row">
<div class="col-md-12">
<employee-search :inplaceholder="'Search Techs'"></employee-search>
</div>
</div>
<employee-card-section :indata="{{ $employees }}"></employee-card-section>
</div>
<modal name="employee-modal"
:width="'94%'"
:height="'94%'"
>
<employee-modal-content v-on:custom="customHandler"></employee-modal-content>
</modal>
</div>
#endsection
employeecard.vue
methods: {
openEmployee() {
// if(this.viewEmployees) {
this.$modal.show('employee-modal');
// this.$emit("passdata",this.employee.id);
this.$emit('chalja');
// this.$emit('custom', 'somedata');
// this.$eventHub.$emit("passdata");
// })
// }
}
},
employee-modal-content.vue
<template>
<div>
<div class="secondary-header no-margin">
<h2>UNEEB</h2>
</div>
<div class="customer-panel">
<input type="hidden" id="eid" value="" />
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item">
<a class="nav-link active" data-toggle="tab" href="#profile" role="tab">Profile</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#bio" role="tab">Bio</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#audit" role="tab">Audit</a>
</li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div class="tab-pane active" id="profile" role="tabpanel">
</div>
<div class="tab-pane" id="bio" role="tabpanel">
</div>
<div class="tab-pane" id="audit" role="tabpanel">
</div>
</div>
</div>
</div>
</template>
<script>
export default {
methods:{
customHandler : function(e){
console.log(e);
console.log("works");
}
},
mounted(){
this.$eventHub.$on('chalja', ()=> {
alert("agya");
});
}
}
</script>
i basically want to pass in the ID from employeecard.vue to directory-modal-content.vue. i have tried many solutions but none worked for me, any help?

Should be so:
1.Pass your id as dynamic prop of component
<employee-modal-content :id="employee.id"></employee-modal-content>
2.In your child component u have to use props to receive the id variable
<template>
<div>
{{ id }}
</div>
</template>
<script>
export default {
props: ['id'],
methods:{
//...
}
}
</script>

Related

How can i change theme (dark / light ) in VueJS

I have a problem in VueJS. I coding a website and i want to add a sun icon. I want to change theme when click icon. You knows; if theme is dark do light and the exact opposite. I think emit() is not work. But I am not sure.
This is codes:
Navbar.vue
<script setup>
import { RouterLink, RouterView } from 'vue-router'
defineEmits(['toggle'])
</script>
<template>
<div>
<nav class="navbar navbar-expand-lg" id="navbar">
<div class="container-fluid">
<a href="/" class="navbar-brand">
<span>osman<span>beyhan</span></span>
</a>
<div class="iconsTwo">
<i class="bi bi-sun-fill d-block d-lg-none" id="icon" #click="this.$emit('toggle')"></i>
<i class="bi bi-list navbar-toggler" data-bs-toggle="offcanvas" href="#offcanvasMenu" aria-controls="offcanvasMenu"></i>
</div>
<div class="offcanvas offcanvas-start" tabindex="-1" id="offcanvasMenu" aria-labelledby="offcanvasMenuLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="offcanvasMenuLabel">
<a href="/">
<span>osman<span>beyhan</span></span>
</a>
</h5>
<i class="bi bi-x-lg btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></i>
</div>
<div class="offcanvas-body">
<ul class="navbar-nav">
<li class="nav-item">
<a class="" href="/about">About Me</a>
</li>
<li class="nav-item">
<a class="" href="/projects">Projects</a>
</li>
<li class="nav-item">
<a class="" href="/contact">Contact</a>
</li>
</ul>
<hr id="line">
<ul class="nav-item d-flex d-md-flex" id="icons">
<li>
<a class="" target="_blank" href="https://www.instagram.com/osmn_byhn/?hl=tr">
<i class="fa-brands fa-instagram"></i>
</a>
</li>
<li>
<a class="" target="_blank" href="https://github.com/osmn-byhn">
<i class="fa-brands fa-github"></i>
</a>
</li>
<li>
<a class="" target="_blank" href=" https://wa.me/905350217844">
<i class="fa-brands fa-whatsapp"></i>
</a>
</li>
<li>
<a class="" target="_blank" href="https://www.linkedin.com/in/osman-beyhan-12304b23a/">
<i class="fa-brands fa-linkedin"></i>
</a>
</li>
<br>
<li id="ayrac" class="d-none d-lg-block"> | </li>
<li>
<i class="bi bi-sun-fill d-none d-lg-block mysun" id="icon"></i>
</li>
</ul>
</div>
</div>
</div>
</nav>
</div>
</template>
<style lang="scss" scoped>
#import '/public/Navbar.scss';
#import '/public/Theme.scss';
</style>
App.vue
<script setup>
import { RouterLink, RouterView } from 'vue-router'
import Navbar from './components/Navbar.vue'
import { ref } from 'vue'
var mode = ref('dark')
function toggle() {
if (mode === "dark") {
mode = "light"
console.log(mode)
} else {
mode = "dark"
console.log(mode)
}
}
</script>
<template>
<div class="app" :class="mode">
<Navbar :mode="mode" #toggle="toggle" />
<RouterView />
</div>
</template>
<style scoped lang="scss">
#import '../public/App.scss';
#import '../public/Theme.scss';
</style>
When i click sun icon; function is works but theme don't change:
enter image description here
Please help me!
In the script setup syntax, you shouldn't use $this when emitting something, instead you should handle it like this:
<script setup>
// more logic ...
const emit = defineEmits(["toggle"]);
</script>
<template>
<div>
<button #click="emit('toggle', someData)">toggle theme</button>
</div>
</template>
Then in the parent component:
<script setup>
const handleData = (param) => {
console.log("data passed was ", param);
}
</script>
<template>
<MyComponent #toggle="handleData()">
...
</MyComponent>
</template>
But also, you could just add the dark class to the body, and while it's outside the vue app instance, you could just handle the logic directly in the Navbar component and adding the class in vanilla javascript:
<!-- Navbar component, without emit -->
<script setup>
const toggle = () => {
if(document.body.classList.contains("dark")){
document.body.classList.remove("dark");
}else{
document.body.classList.add("dark");
}
}
</script>

Navigation bar (Mobile view) doesn't close after click - Vuejs

When I click nav link on navbar it does not collapse.
Vue version 2.6.10.
<template>
<div class="nav-wrapper">
<nav>
<ul>
<li v-for="(route, index) in routings" :key="index">
<router-link :to="route.url">{{route.name}}</router-link>
</li>
<li>
Blog
</li>
<li class="visible-xs">
<Button v-if="!isLoggedIn" :label="loginButtonLabel" :isFilled="true" :action="goToLogin"/>
<UserWidget v-else :email="setFirstName" :title="'administrator'" :isUserMenu="true" :action="gotoDashboard"/>
</li>
</ul>
</nav>
</div>
</template>
This is the navbar what i talk about
This is the header part of the code. When click on the hamburger icon class 'mobile-menu-wrapper visible-xs' this will change to 'mobile-menu-wrapper visible-xs expanded'. There for I think it will be change to previous class its solve the matter. Please advise me to find the issue.
<template>
<div class="header-wrapper">
<div class="header-container container">
<Logo/>
<Nav class="hidden-xs" :routings="routings"/>
<Button v-if="!isLoggedIn" class="hidden-xs" :label="isLoggedIn ? 'Console' : 'Login / Sign-up'" :isFilled="true" :action="goToLogin"/>
<UserWidget class="hidden-xs" v-if="isLoggedIn" :email="setFirstName" :title="'administrator'" :isUserMenu="true" :action="gotoDashboard"/>
<div class="mobile-menu-icon-wrapper visible-xs" #click="getMobileMenu">
<i v-if="isMenuExpanded" class="mobile-menu-icon close-icon"></i>
<i v-if="!isMenuExpanded" class="mobile-menu-icon expand-icons"></i>
</div>
<div class="mobile-menu-wrapper visible-xs" :class="{'expanded': isMenuExpanded}">
<div class="menu-overlay" #click="getMobileMenu"></div>
<Nav :routings="routings" :eventBus="eventBus" :adminDetails="adminDetails" :isLoggedIn="isLoggedIn"/>
<div class="mobile-menu-icon-wrapper" #click="getMobileMenu">
<i v-if="isMenuExpanded" class="mobile-menu-icon close-icon"></i>
</div>
</div>
</div>
</div>
</template>
Try to add an onclick event in your router link to close the navigation bar, I don't see the code that you're using to open/close the nav, but you can emit an event like this:
Let's listen for the event closeNav in the parent component, by adding #closeNav in the Nav component:
<template>
<div class="header-wrapper">
<div class="header-container container">
<Logo/>
<Nav class="hidden-xs" :routings="routings"/>
<Button v-if="!isLoggedIn" class="hidden-xs" :label="isLoggedIn ? 'Console' : 'Login / Sign-up'" :isFilled="true" :action="goToLogin"/>
<UserWidget class="hidden-xs" v-if="isLoggedIn" :email="setFirstName" :title="'administrator'" :isUserMenu="true" :action="gotoDashboard"/>
<div class="mobile-menu-icon-wrapper visible-xs" #click="getMobileMenu">
<i v-if="isMenuExpanded" class="mobile-menu-icon close-icon"></i>
<i v-if="!isMenuExpanded" class="mobile-menu-icon expand-icons"></i>
</div>
<div class="mobile-menu-wrapper visible-xs" :class="{'expanded': isMenuExpanded}">
<div class="menu-overlay" #click="getMobileMenu"></div>
<!-- here is part of the magic -->
<!-- alternative one, update isMenuExpanded directly -->
<Nav :routings="routings" :eventBus="eventBus" :adminDetails="adminDetails" :isLoggedIn="isLoggedIn" #closeNav="isMenuExpanded = false"/>
<!-- alternative two, update isMenuExpanded using the closeNavBar method -->
<!--<Nav :routings="routings" :eventBus="eventBus" :adminDetails="adminDetails" :isLoggedIn="isLoggedIn" #closeNav="closeNavBar"/> -->
<div class="mobile-menu-icon-wrapper" #click="getMobileMenu">
<i v-if="isMenuExpanded" class="mobile-menu-icon close-icon"></i>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
...
methods: {
// alternative using method
closeNavBar() {
this.isMenuExpanded = false;
}
}
...
}
</script>
The navbar component will emit the event once the user clicks on any router-link (you can add the event in any other link or button)
<template>
<div class="nav-wrapper">
<nav>
<ul>
<li v-for="(route, index) in routings" :key="index">
<!-- emit the event to close the navBar -->
<!-- emit directly in the tag -->
<router-link :to="route.url" #click="$emit('closeNav')">{{route.name}}</router-link>
<!-- emit by using a method -->
<!--<router-link :to="route.url" #click="closeNavBarFromChild">{{route.name}}</router-link>-->
</li>
<li>
Blog
</li>
<li class="visible-xs">
<Button v-if="!isLoggedIn" :label="loginButtonLabel" :isFilled="true" :action="goToLogin"/>
<UserWidget v-else :email="setFirstName" :title="'administrator'" :isUserMenu="true" :action="gotoDashboard"/>
</li>
</ul>
</nav>
</div>
</template>
<script>
...
methods: {
closeNavBarFromChild() {
this.$emit('closeNav') // Emit the event that the parent is listening
}
}
...
</script>
I wrote two ways to use events, but they have the same effect.

Dynamically Change image when navigating to different routes

I have a Banner component. I want to change the image in there when i am navigating to different routes. Its like using different banner images for separate inner pages. I want to use that banner component as a nested component in other components.
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav m-auto custom-nav">
<li class="nav-item">
<router-link to="/">home</router-link>
</li>
<li class="nav-item">
<router-link to="/about-Us">about us</router-link>
</li>
<li class="nav-item">
<router-link to="/characters">characters</router-link>
</li>
<li class="nav-item">
<router-link to="/our-comics">comics</router-link>
</li>
</ul>
</div>
Banner component
<template>
<section class="banner-outer">
<img src="../assets/banner.jpg" alt class="img-fluid" />
<div class="banner-content-outer">
<div class="container">
<div class="banner-content-inner">
<h1>EXPLORE THE UNIVERSE</h1>
<h5>Dive into the dazzling domain of all the classic characters you love ...</h5>
</div>
</div>
</div>
</section>
</template>
About Us Component, Contact us Component
<template>
<banner />
</template>
In each page component, pass the image in as a prop to the banner component...
<template>
<banner which-banner="//path/to/img.png"></banner>
<div>component page content...</div>
</template>
In the banner Component...
<script>
...
{
props: ['whichBanner']
}
..
</script>
<template>
<section class="banner-outer">
<img :src="whichBanner" alt class="img-fluid" />
<div class="banner-content-outer">
<div class="container">
<div class="banner-content-inner">
...
</div>
</div>
</div>
</section>
</template>
Vue Codeply
you can use beforeEach :
router.beforeEach((to, from, next) => {
// check current route to set the valid image
// in vuex or localstorage or even a global window variable
if(to === 'about-us') {
// using global variable
window.bannerImagePath = 'path/to/about-us/banner.png';
// localstorage
localStorage.setItem('bannerImagePath', 'path/to/about-us/banner.png');
} else if( ... ) { ... }
return next();
});
Then you can get it in BannerComponent inside mounted() or set a method for that
Example :
<img :src="getCurrentBannerImage()" alt class="img-fluid" />
methods: {
getCurrentBannerImage() {
// global variable example
return require(window.bannerImagePath) // or any storage you choose
// localStorage
let _item = localStorage.getItem('bannerImagePath');
return require(_item) // or any storage you choose
}
},

Hide Navigation Links in VueJs When Clicked

I tried everything to make the navigation links hide when I clicked but it didn't worked. Here my Header.vue file.
<template>
<nav class="navbar is-dark is-fixed-top">
<div class="container">
<div class="navbar-brand">
<router-link to="/" class="navbar-item">
<img src="../../assets/logo.png" width="">
</router-link>
<a role="button"
:class="{ 'is-active': ShowMenu }"
class="navbar-burger burger"
#click="toggleMenu()"
aria-label="menu"
aria-expanded="false">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div :class="{ 'is-active': ShowMenu }"
class="navbar-menu">
<div class="navbar-start">
<router-link to="/" class="navbar-item">Home</router-link>
<router-link to="/about" class="navbar-item">About</router-link>
</div>
<div class="navbar-end">
<div class="navbar-item">
<div class="field is-grouped">
<p class="control">
<router-link to="/login" class="button is-dark">
<span><i class="fa fa-lock"></i> Login</span>
</router-link>
</p>
<p class="control">
<router-link to="/register" class="button is-light">
<span><i class="fa fa-user"></i> Register</span>
</router-link>
</p>
</div>
</div>
</div>
</div>
</div>
</nav>
Here's the JS codes. Navigation are working when a click the links but the only problem I have is that it didn't automatically hide.
export default {
name: "Header",
data() {
return {
ShowMenu: false,
NavigationItems: true,
NavigationItems: false
}
},
methods: {
toggleMenu: function() {
this.ShowMenu = !this.ShowMenu
},
toggleNavItem: function() {
false
}
}
}
Try
<a v-if='!ShowMenu' role="button" ...
instead of using CSS
You shouldn't use v-if it will "kill" the element in the dom, but if you only want to toggle it use v-show width !ShowMenu like Steven explained.
And if you want to use a CSS class: do you have a class called is-active and is the default behavior of .burger display: none;? If you want to stay on this solution please provide us your CSS.

Vue 2.x authentication links not hiding until page refresh

I am new to Vue and created a basic authentication application.
AuthService.js
module.exports = {
isLoggedIn: function() {
if (localStorage.getItem("authUser") != null) {
return true;
} else {
return false;
}
},
Logout: function() {
localStorage.removeItem("authUser");
},
}
App.vue
<template>
<div id="app" >
<top-progress ref="topProgress"></top-progress>
<div class="nav is-light is-fixed-top">
<div class="container">
<span class="nav-toggle" v-on:click="toggleNav" v-bind:class="{ 'is-active': isActive }">
<span></span>
<span></span>
<span></span>
</span>
<div class="nav-right nav-menu" v-bind:class="{ 'is-active': isActive }">
<router-link v-ripple to="/" class="nav-item r-item"><i class="fa fa-home"></i>Home</router-link>
<router-link v-ripple to="faq" class="nav-item r-item"><i class="fa fa-file"></i>Features</router-link>
<router-link v-ripple to="dashboard" class="nav-item r-item"><i class="fa fa-dashcube"></i>Dashboard</router-link>
<router-link v-ripple to="faq" class="nav-item r-item"><i class="fa fa-quora"></i>Faq</router-link>
<a class="nav-item r-item" v-if="LoggedIn"><i class="fa fa-sign-out" #click.prevent="Logout"></i>Logout</a>
<div class="nav-item" v-if="!LoggedIn">
<p class="control">
<router-link to="login" class="button is-primary is-outlined">
<span class="icon">
<i class="fa fa-download"></i>
</span>
<span> Join Now</span>
</router-link>
</p>
</div>
</div>
</div>
</div>
<br>
<router-view></router-view>
<footer class="footer is-secondary">
<div class="container">
<div class="columns">
<div class="column">
<p>And this right here is a spiffy footer, where you can put stuff.</p>
</div>
<div class="column has-text-right">
<a class="icon" href="#"><i class="fa fa-facebook"></i></a>
<a class="icon" href="#"><i class="fa fa-twitter"></i></a>
</div>
</div>
</div>
</footer>
</div>
</template>
<script>
import {isLoggedIn,Logout} from "./service"
import miniToastr from 'mini-toastr'
import topProgress from 'vue-top-progress'
export default {
name: 'app',
components:{topProgress},
data:function(){
return {
isActive:false,
LoggedIn:false,
}
},
created(){
this.LoggedIn=isLoggedIn();
},
mounted(){
miniToastr.init()
this.$refs.topProgress.start()
setTimeout(() => {
this.$refs.topProgress.done()
}, 2000)
},
methods:{
Logout:function(){
Logout();
this.$router.push("login");
},
}
}
</script>
<style lang="sass">
..//
</style>
After successful login, I am using this.$router.push("home") to navigate to home component but the Login/Logout button not hiding/showing until I refresh the page.
The problem you are having is the created: hook is only called when App.vue is first created. Since this component holders the router-view it is always there as you move around the app — it's never destroyed, so it never needs to be created again. As a result your this.LoggedIn is only updated when you first load the app (or as you discovered, hit refresh).
You need to find a different way to update this.LoggedIn. One obvious possibility it to set it in the logih/logout methods.
Logout:function(){
Logout();
this.LoggedIn = isLoggedIn(); // or simply this.LoggedIn = false
this.$router.push("login");
},
It looks like users will login in a different component, so you will need to send an event from the child component to App.vue and trigger a method on App.vue to set this.LoggedIn when users login.
There are probably other possibilities that will come to mind now that you see why it isn't working.