Vuejs toggle class to the body on button click in a components - javascript

I want to toggle a class to the body or to the root element("#app") if I click on the button inside the header component
Header.vue :
<template lang="html">
<header>
<button class="navbar-toggler navbar-toggler align-self-center" type="button" #click="collapedSidebar">
<span class="mdi mdi-menu"></span>
</button>
</header>
</template>
<script>
export default {
name: 'app-header',
data: {
isActive: false
},
methods: {
collapedSidebar() {
}
}
}
</script>
App.vue :
<template lang="html">
<div id="app" :class="{ active: isActive }">
...
</div>
</template>
! Please correct me if I'm in the wrong direction. I'm new in Vuejs :)

You can emit an event inside your header and maybe catch it in the mounted of app component like this:
In your sidebar or other component:
on_some_btn_click: function (){
this.$emit('toggle_root_class');
}
In your app component:
mounted: function(){
var _this = this;
this.$on('toggle_root_class', function(){
_this.active = !_this.active;
});
}
Vue may restrict event from being observed in sibling components. So I use EventBus in my projects to handle sending events easily.

the problem lies in your component scope. You tried to access data in Header.vue in App.vue which is impossible by the structure in showed in your code. Consider moving isActive data to App.vue or use Vuex.

You can use jquery to toggle class for an element which is not inside the Vue template.
You can call a function on click of a button and inside it, you can toggle class in body tag using jquery.
<template lang="html">
<header>
<button class="navbar-toggler navbar-toggler align-self-center" type="button" :class="{ active: isActive }" #click="activeLink">
<span class="mdi mdi-menu"></span>
</button>
</header>
</template>
<script>
export default {
name: 'app-header',
data: {
isActive: false
},
methods: {
activeLink() {
$('body').toggleClass('.class-name');
}
}
}
</script>

Related

Why do these Vue props fail outside the main component?

I am working on a Vue 3 app. I have run into a problem working with a <Navbar /> component and one of its sub-components.
In App.vue:
<template>
<Navbar />
<Content title="Home" />
<Footer />
</template>
<script>
import Navbar from './components/Navbar.vue'
import Content from './components/Content.vue'
import Footer from './components/Footer.vue'
export default {
name: 'App',
components: {
Navbar,
Content,
Footer
}
}
</script>
Within the Content.vue component, I can display the title this way:
<h1>{{ title }}</h1>
<script>
export default {
name: 'Content',
props: {
title: String
}
}
</script>
But displaying buttons with their labels by the same pattern as above does not work:
// Button.vue component
<template>
<button class="btn btn-sm btn-generate">
{{ label }}
</button>
</template>
<script>
export default {
name: 'Button',
props: {
label: String
}
}
</script>
// Navbar.vue component
<template>
<div class="navbar">
<Button label="Button 1" />
<Button label="Button 2" />
</div>
</template>
<script>
import Button from './Button'
export default {
name: 'Navbar',
components: {
Button
}
}
</script>
The problem
As a result of the code above, inside <div class="navbar"> there is only one button with no label, instead of 2 buttons labeled "Button 1" and "Button 2".
Where is my mistake?
I think that naming your component just as the already existing HTML element is not a good idea. Try changing it to MyButton and use <my-button>... in the navbar component (you still want to use <button> in MyButton, as you want to build upon it).
Most probably browser still picks just a default button instead of yours.
The first essential rule mentioned in Vue docs is Use multi-word component names.
You need to bind them so :label="button 1"

Toggle Sidebar component with button from Navbar Component

I'm trying to learn Laravel with Vuejs (v3).
I have 3 components: App.vue, Navbar.vue, and Sidebar.vue
What I'm trying to do is, onclick of sidebar-btn:
Change value of variable isSidebarActive to !isSidebarActive ---- DONE
Change class of fontawesome (dependent on isSidebarActive). ---- DONE
Show Sidebar.vue (dependent on isSidebarActive)
I tried using props but error says I can't change the value, so I tried using emits but I still can't seem to get it right.
app.js
require('./bootstrap');
import { createApp } from 'vue'
import App from './App.vue'
import router from './routes'
// Partials
import Navbar from './components/Navbar.vue'
import Sidebar from './components/Sidebar.vue'
createApp(App)
.component('navbar', Navbar)
.component('sidebar', Sidebar)
.use(router)
.mount('#app')
App.vue
<template>
<navbar></navbar>
<sidebar v-bind:class="{ active: isSidebarActive }"></sidebar>
<router-view></router-view>
</template>
<script>
export default {
name: "App",
data() {
return {
isSidebarActive: false,
};
},
}
</script>
Navbar.vue
<template>
<nav class="navbar navbar-expand-md navbar-dark bg-dark shadow-sm sticky-top">
<div class="container">
<div class="navbar-brand" >
<span class="h4">
Hello World!
</span>
<!-- Button to toggle Sidebar -->
<span class="btn btn-outline-light btn-sm ms-2" id="sidebar-btn" style="border: 1px white" #click="toggleSidebar()">
<i v-bind:class="[isSidebarActive ? 'fas fa-arrow-left' : 'fas fa-bars']" title="Sidebar Menu"></i>
</span>
</div>
</div>
</nav>
</template>
<script>
export default {
name: "Navbar",
data() {
return {
isSidebarActive: false,
};
},
emits: ['isSidebarActive'],
methods: {
toggleSidebar:function () {
this.isSidebarActive = !this.isSidebarActive
this.$emit("isSidebarActive", this.isSidebarActive)
},
},
}
</script>
Please take a look at following snippet:
const app = Vue.createApp({
data() {
return {
isSidebarActive: false,
};
},
methods: {
handleSidebar() { // 👈 handle received event
this.isSidebarActive = !this.isSidebarActive
}
}
})
app.component('Sidebar', {
template: `<div>sidebar</div>`
})
app.component('Navbar', {
template: `
<div>Hello World!<button #click="toggleSidebar()">show/hide sidebar</button></div>
`,
methods: {
toggleSidebar() {
this.$emit("toggle") // 👈 emit event
},
},
})
app.mount('#demo')
<script src="https://unpkg.com/vue#3.2.29/dist/vue.global.prod.js"></script>
<div id="demo">
<!-- 👇 listen to event from child, call method -->
<navbar #toggle="handleSidebar"></navbar>
<!-- 👇 conditionaly show/hide component -->
<sidebar v-if="isSidebarActive"></sidebar>
</div>

Toggle modal dialog from parent component in VUE

So i want to toggle my modal dialog from parent component and i tried each step mentioned here Stack Overflow Question about same Topic , but still my Modal Dialog is not visible and it even has undefined value when i see from VUE console. and in Elements section the modal dialog div is not created.
MY MODAL DIALOG is not showing in elements section on webpage, but showing in Vue console with undefined prop value. But Click effect is working from Parent component. and modal is setting true when i click on div.
My Parent Code
<template>
<div class="collection">
<section class="section section-elements">
<div class="elements-outer" #click="openModal">
<CopyComponent v-bind:item="item"/>
</div>
</section>
<modal v-modal="modal"/>
</div>
</template>
<script>
import Modal from "../components/Modal.vue";
export default {
name: 'Collection',
components: {
Modal
},
data() {
return {
modal: false
}
},
methods: {
openModal() {
this.modal = !this.modal;
}
}
}
</script>
My Child Component
<template>
<div v-if="value" class="modal">
<div class="body">
body
</div>
<div class="btn_cancel" #click="modalToggle">
<i class="icon icon-cancel" />
</div>
</div>
</template>
<script>
export default {
name: "Modal",
props: ["value"],
methods: {
modalToggle() {
this.$emit("input", !this.value);
}
}
};
</script>
am i missing anything?
Please help, thanks.
Your prop is called value so you need to pass it from parent component, also assign event for toggle modal.
<modal :value="modal" #toggle="modalToggle"/>
And in your child:
<template>
<div v-if="value" class="modal">
<div class="body">
body
</div>
<div class="btn_cancel" #click="modalToggle">
<i class="icon icon-cancel" />
</div>
</div>
</template>
<script>
export default {
name: "Modal",
props: ["value"],
methods: {
modalToggle() {
this.$emit("toggle");
}
}
}
</script>
You misspelled v-model in <modal v-modal="modal"/>, it should be <modal v-model="modal"/>

How to pass a method from one component to another and use it onclick in Vue.js?

So in my App.vue component, I have two other components being rendered, and what I want to achieve is this, when the user clicks on the play button, animateRing() method from the component ProgressRing should be used, my code looks the following:
App.vue
<template>
<div id="app">
<ProgressRing>
<PlayButton
#click="animateRing(), active = !active"
:class="{active: active}"
/>
</ProgressRing>
</div>
</template>
PlayButton.vue
<template>
<button class="play-button" #click="$emit('click')">
...
some irrelevant code here
...
</button>
</template>
ProgressRing.vue
<template>
...some code...
</template>
<script>
export default {
methods: {
animateRing(){
console.log('I'm animated');
}
}
};
</script>
I can't seem to figure out the right way to do it. What is the best way to make the method to work in the App component? I'm relatively new to Vue and didn't really figure it out yet.
Here's one way you can accomplish this:
App.vue
<template>
<div id="app">
<ProgressRing ref="progressRing">
<PlayButton
#click="animateRing(), active = !active"
:class="{active: active}"
/>
</ProgressRing>
</div>
</template>
<script>
export default {
methods: {
animateRing(){
this.$refs.progressRing.animateRing()
}
}
};
</script>
I'm curious about the reason for PlayButton being a child of ProgressRing, but not defined in ProgressRing.vue.

How to trigger a method in Single File Component from another Single File Component VueJS

I have Three components I want to trigger the show() method that is located in overlay.vue component, from the about.vue component
I am a beginner so I wish if I found some help from you guys
first is overlay.vue
<template>
<div class="overlay"></div>
</template>
<script>
export default {
name: "overlay",
methods: {
show() {
document.querySelector(".overlay").style.display = "block";
}
}
};
</script>
second is about.vue
<template>
<section class="about">
<div class="container">
<div class="row video">
<div class="col-lg-6 order-lg-1 order-2">
<img
class="dots img-fluid"
src="../assets/images/dots.svg"
alt="dots"
/>
<div class="video-wrapper">
<div class="video-img">
<img
class="img-fluid"
src="../assets/images/video.png"
alt="#"
/>
</div>
<div class="video-i">
<!-- ***************************************************************
***** this is where i want to trigger the method using this below a tag*****
*************************************************** -->
<i class="fas fa-play"></i>
</div>
</div>
</div>
</div>
</div>
</section>
</template>
The third which is the parent app.vue where I import about.vue and overlay.vue
<template>
<div id="app">
<overlay></overlay>
<about></about>
</div>
</template>
<script>
import overlay from "./components/overlay";
import about from "./components/about";
export default {
name: "App",
components: {
about,
overlay
}
};
</script>
You can do something like this, in your app.vue set a variable to show your overlay.vue or not. And then in the overlay.vue set a props that change the style of your component. This solution is not using a dom manipulation.
app.vue
<template>
<div id="app">
<overlay :show="show_overlay"></overlay>
<about></about>
</div>
</template>
<script>
import overlay from "./components/overlay";
import about from "./components/about";
export default {
name: "App",
data(){
return {
show_overlay:false
}
},
components: {
about,
overlay
}
};
</script>
overlay.vue
<template>
<div class="overlay" :style="[(this.show) ? 'display:block' : 'display:none']"></div>
</template>
<script>
export default {
name: "overlay",
props:{
show:{
default:false,
type:Boolean
}
}
};
</script>
because the two components are siblings and not imported in each other I coulden't use $ref and the best choice is to use Store
this is my store code
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
showOverlay: false
},
mutations: {
//showing the overlay
TOGGLE_OVERLAY(state, payload) {
state.showOverlay = payload;
}
},
actions: {
//showing the overlay
toggleOverlay(context, payload) {
context.commit("TOGGLE_OVERLAY", payload);
}
},
getters: {
getStatus: state => state.showOverlay
}
});
and here where i dispatch it. I dispatch it from about.vue or any other component as well
<a #click.prevent="toggleOverlay" href="#"><i class="fas fa-play"></i></a>
methods: {
toggleOverlay() {
this.$store.state.showOverlay = !this.$store.state.showOverlay;
this.$store.dispatch(
"toggleOverlay",
this.$store.state.showOverlay
);
}
}

Categories

Resources