How to get $auth value in component outside of registered vue-router component - vue.js

I have a layout theme/default which has vue-router inside like this
<template>
<div id="app">
<component :is = "layout">
<router-view></router-view>
</component>
</div>
</template>
<script>
const default_layout = "theme";
export default {
computed: {
layout(){
return ( this.$route.meta.layout || default_layout) + '-layout';
}
},
};
</script>
And then the theme layout is like this:
<template>
<div class="app-home">
<nav-bar/>
<div class="container-fluid section">
<div class="left-fixed">
<side-bar/>
</div>
<div class="right-card">
<slot />
</div>
</div>
</div>
</template>
<script>
import NavBar from './Navbar'
import SideBar from './Sidebar'
export default {
data() {
return {
}
},
mounted(){
},
components: {
NavBar,
SideBar
}
}
</script>
Now I have to pass current auth user in Navbar and Sidebar for logout and current user role which can be obtained from vue-auth $auth but only inside router component. Can anybody help it to fix this.

Using vuex I had made a state which I call as computed property and I set whenever User logged in.

Related

Vue - Unable pass specific value to higher component

I am getting the following - Cannot read property 'free' of undefined.
I will be adding this button component on multiple pages and I have data object which will allow me to add text based on whatever page I want displayed on a page. For example if its on the homepage I would like to use <buttons :text="buttonText.free" /> and on about us page I would like to use <buttons :text="buttonText.spend" />
Template file
<template>
<main class="container">
<buttons :text="buttonText.free" />
</main>
</template>
<script>
import Buttons from '~/components/atoms/buttons.vue'
export default {
components: {
Buttons
}
}
</script>
Component file
<template>
<div>
<button class="button"">
<span>{{ buttonText }}</span>
</button>
</div>
</template>
<script>
export default {
props: {
text: String
},
data () {
return {
buttonText: {
free: 'free',
spend: 'spend',
now: 'now',
nowFree: 'now free'
}
}
}
}
</script>
Could you tell me what I am doing wrong?
You should define your data in your parent component's data property. All the variables that is used inside the template tag will be fetched from data, computed or props of the component. You are passing an undefined buttonText data to your buttons component.
<template>
<main class="container">
<buttons :text="buttonText.free" />
</main>
</template>
<script>
import Buttons from '~/components/atoms/buttons.vue'
export default {
data() {
return {
buttonText: {
free: 'free',
spend: 'spend',
now: 'now',
nowFree: 'now free'
}
}
},
components: {
Buttons
}
}
</script>
and in your buttons component, just accept the props passed by the parent component. In this case, you are using text as the props of the buttons component.
<template>
<div>
<button class="button"">
<span>{{ text }}</span>
</button>
</div>
</template>
<script>
export default {
props: {
text: String
}
}
</script>
template.vue
<template>
<main class="container">
<buttons :text="your customized text" />
</main>
</template>
<script>
import Buttons from '~/components/atoms/buttons.vue'
export default {
components: {
Buttons
}
}
</script>
buttons.vue
<template>
<div>
<button class="button">
<span>{{ text }}</span>
</button>
</div>
</template>
<script>
export default {
props: {
text: String
}
}
</script>
here is a simple solution to solve your problem
but you need to learn more fundamentals on vue components
vue component doc

How to access parents data value in vuejs with the template syntax

In my VueJS app I am using bootstrap-vue and want to use iframe inside a collapsable elements b-collapse. Because of some problems with iframe content and resizing (problem not related here) I found out that if I enable/disable b-embed with conditional rendering it works.
The parent component b-collapse has a data element called show which change its state if toggle is clicked. In my HelloWorld component I want that b-collapse can pass it's show value into the if check of b-embed.
My approach with this.$parent.$data.show isn't working and I am not sure if there is any better way to do so.
<template>
<div>
<b-btn v-b-toggle.logs>
<span class="when-opened">Close</span>
<span class="when-closed">Open</span>
Trace
</b-btn>
<b-collapse id="logs">
<b-embed :src="src" v-if="this.$parent.$data.show"></b-embed>
<div>Data: {{this.$parent.$data.show}}</div>
</b-collapse>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import { Prop, Component, Inject } from "vue-property-decorator";
#Component
export default class HelloWorld extends Vue {
src = "http://localhost:7681/";
}
</script>
Like this:
parent.vue
<template>
<Child :show="myShow"></Child>
</template>
<script>
import Child from './child'
export default {
data () {
return {
myShow: 'StackOverflow'
}
},
components: {Child}
}
</script>
child.vue
<div>
<b-btn v-b-toggle.logs>
<span class="when-opened">Close</span>
<span class="when-closed">Open</span>
Trace
</b-btn>
<b-collapse id="logs">
<b-embed :src="src" v-if="this.$parent.$data.show"></b-embed>
<div>Data: {{this.$parent.$data.show}}</div>
</b-collapse>
</div>
<script>
export default {
props: {
show: {
type: Number,
require: true
}
}
}
</script>
Or use vuex to do this.

render a Vue slot in a layout from component

I'm having problems with a named slot. This seems like it should work. In the code below I'm trying to use a named slot "sidebar". I would expect my sidebar slot content to show up between the Sidebar starts and Sidebar ends text but nothing shows up in that slot. Everything renders in the main slot.
Here's my code.
route...
{
path: "/test",
name: "test",
meta: {
layout: "test-layout"
},
component: () =>
import("#/pages/Test.vue")
},
and App.vue template...
<template>
<div id="app">
<component :is="layout">
<router-view />
</component>
</div>
</template>
and test-layout...
<template>
<div>
<div>
<h1>Sidebar starts</h1>
<slot name="sidebar"/>
<h1>Sidebar ends</h1>
</div>
<div class="container">
<h1>Content starts</h1>
<slot/>
<h1>Content ends</h1>
</div>
</div>
</template>
and page Test.vue...
<template>
<test-layout>
<span slot="sidebar">sidebar slot content {{forecast.todaySummary}}</span>
<div>main slot content {{forecast.currentSummary}}</div>
</test-layout>
</template>
<script>
import api from "#/js/web-services";
export default {
data() {
return {
forecast: null
};
},
created() {
api.getDailyForecast().then(response => {
this.forecast = response.data;
});
}
};
</script>
and the import in my main.js
import TestLayout from "./layouts/test-layout.vue";
Vue.component('test-layout', TestLayout);
Why isn't my sidebar slot working?
UPDATE
If I get rid of the two lines in main.js and add
import TestLayout from "#/layouts/test-layout.vue";
and
export default {
components: { TestLayout },
data() {...
to Test.vue then it works.
In your router file you are using layout: "test-layout" this means what ever comes in your vue component will be rendered in base test-layout.
There are two ways as far as I know to render the layouts.
Do not define layout in router file and on parent component define named slots like this<slot #header></slot><slot #body></slot> then every slot will be rendered within this (test-layout) layout, and then in your each component extend like this <test-layout><template header>Header content</template><template body>Body content</template></test-layout>.
Defining layout in router file like you did, you can not further use in slots in that layout, you can just import other components e.g <template><Component1><Component2> </template>

How to get refs element in scoped slot

If there are some refs in slot's template, how can I access these refs from the component? For example:
v-component.vue
<template>
<div>
<slot></slot>
</div>
</template>
<script>
export default {
created() {
console.log(this.$refs.ele)
}
}
</script>
app.vue
<template>
<v-component>
<template slot-scope="props">
<h1 ref="ele"></h1>
</template>
</v-component>
</template>
<script>
import VComponent from './v-component
export default {
components: { VComponent }
}
</script>
this.$refs.ele in v-compoent.vue output undefined. My question is how can I get this element?
Each element in named slot and scopedSlot has context.$refs.
Do not forget to check if object exists first.
<template>
<v-component>
<template slot-scope="props">
<h1 ref="ele">{{ props }}</h1>
</template>
</v-component>
</template>
<script>
import VComponent from './v-component'
export default {
components: { VComponent }
}
</script>
and
<template>
<div>
<slot demo="foo"></slot>
</div>
</template>
<script>
export default {
created() {
this.$nextTick(function() { // lazy
console.warn(this.$scopedSlots.default()[0].context.$refs)
});
}
}
</script>
Result:
This is considered as a bad idea by Vue developers: https://github.com/vuejs/vue/issues/7661
Btw, in my case in Vue3, the el entries of my slots retrieved by
this.$refs.myRef.$slots['my-slot']().el
is always null (as appContext)
On Vue 2 you can do this on mounted
mounted() {
console.log(this.$slots)
},
with more precision
You can do this
mounted() {
console.log(this.$slots.name_of_your_slot)
},

Vue.js v-if toggle for show/hide nav

I am trying to make a nav that you can show/hide toggle by clicking on an button. Can anyone tell me what I am doing wrong here? I am still learning Vue so any help would be appreciated. Thanks.
Here's the code from navigation.vue:
<template>
<div>
<nav v-if="seen">
<ul>
<li>front</li>
<li>contact</li>
</ul>
</nav>
<p><button v-on:click="seen = !seen">Toggle</button></p>
</div>
</template>
<script>
export default {
data: {
seen: true
}
}
</script>
Importing the navigation in App.vue:
<template>
<main>
<app-navigation></app-navigation>
<app-front></app-front>
<app-footer></app-footer>
</main>
</template>
<script>
import Navigation from './components/navigation.vue'
import Front from './components/front.vue'
import Footer from './components/footer.vue'
export default {
components: {
'app-navigation': Navigation,
'app-front': Front,
'app-footer': Footer
},
data () {
return {
}
}
}
</script>
With components, your data property needs to be a function.
data(){
return {
seen: true
}
}