nuxt 3 triggers changes from other components - vue.js

I have a question regarding triggering other components in nuxt 3. In nuxt 2 I can use $root.$refs to trigger components, but what about nuxt 3?
Example :
in componentA I have a button that triggers a popup
<template>
<button #click="openModal">Open</button>
<div appear :show="isOpen">
<component-b />
test
</div>
</template>
<script setup>
const isOpen = ref(false);
function openModal() {
isOpen.value = true;
}
</script>
in componentB.vue I have a close button for popup in componentA
<button type="button" #click="closeModal">Close</button>
My goal is when the button from component B is clicked it can trigger the popup from component A to close.

You could use an emit to do so.
In your component B, define an emit like:
// Component B
<template>
<button type="button" #click="emit('close')">Close</button>
</template>
<script setup lang="ts">
const emit = defineEmits(['close'])
</script>
You can use this emit from your Component A to close the modal.
// Component A
<template>
<button #click="openModal">Open</button>
<div appear :show="isOpen">
<component-b #close="isOpen = false" />
test
</div>
</template>
<script setup>
const isOpen = ref(false);
function openModal() {
isOpen.value = true;
}
</script>

Related

VueJS: Template Refs binding from slot props?

I have a component with a slot (SlotComponent) like this for example
<template>
<slot :element="element"></slot>
</template>
<script setup lang="ts">
import { onMounted, ref } from "vue";
const element = ref<HTMLElement | null>(null);
onMounted(() => console.log(element.value));
</script>
However I can't seems to bind the element within the slot when using the component. The element is null on the onMounted lifecycle callback (above snippet).
<SlotComponent v-slot="{ element }">
<div ref="element">hello world</div>
</SlotComponent>
Question: how can I bind to the html element inside the slot?
use Function Refs
provide a setElement() function as a slot prop
<template>
<slot :set-element="setElement"></slot>
</template>
<script setup lang="ts">
import { ref, watchEffect } from "vue";
const element = ref<Element | null>(null);
function setElement(el: Element) {
element.value = el;
}
watchEffect(() => {
console.log(element.value);
});
</script>
usage
<SlotComponent v-slot="{ setElement }">
<div :ref="(el) => setElement(el)">Hello World</div>
</SlotComponent>

Vue3 (SFC api) event 'emit' is not propagated to parent

I have created a very basic sample to find out how to correctly send an event from child to parent.
app.vue:
<script setup>
import HelloWorld from './components/HelloWorld.vue'
function clicked() {
alert("clicked in parent") // never gets here
}
</script>
<template>
<header>
<HelloWorld msg="Click me!" #click_text="clicked" />
</header>
</template>
HelloWorld.vue:
<script setup>
const emit = defineEmits(['clickText'])
defineProps({
msg: {
type: String,
required: true
}
})
function click() {
// alert("clicked in child") // this works, so we got here
emit('clickText')
}
</script>
<template>
<button #click="click">{{ msg }} </button>
</template>
...but the event doesn't reach the parent - what have I missed?
You have a wrong.
<HelloWorld msg="Click me!" #click_text="clicked" />
In this line, you should not put _ for click_text, you should use - instead.
<HelloWorld msg="Click me!" #click-text="clicked" />

Access components method via template ref

When I have a child component like this:
<script setup>
import { defineExpose } from 'vue'
const validate = () => {
console.log('validate')
}
defineExpose({ validate })
</script>
<template>
hello
</template>
and parent component in which I use child:
<script setup>
import { ref } from 'vue'
const test = ref()
const validate = () => {
console.log('test', test.value)
}
</script>
<template>
<div ref="test">
<Child />
</div>
<button #click="validate">
click me
</button>
</template>
Is it possible to access validate method from the child component via template ref which is on the wrapper div in parent component?
EDIT:
I update my playground link in which I completed the task but I'm using parent instance instead of provide/inject:
https://sfc.vuejs.org/#eNqNU9FuozAQ/BWfXyBSYt4jqK463Un9hqOqKCypW7At29BWEf/eXcAkJVXaSEHszu4wnl0f+a0xou+A73nqSiuNZw58Z25yJVujrWdHZqFmA6utblmEpdEC/dO2nfMioYCYTvCdMp1f8DGaC0qtHCLUnhF9vMkVYyHvAR8Zizcsu2FHQqhS9EXTAT1lVXigliFXaTKpRr0YeGhNgyBFPh3lIXuWcyLIOaYZ/tJJWPKDMB2PNb6Gf/rYea8V+102snxBbpK7cI9J1sLUPJUilCaLNL7lkz+7tjDi2WmF3o+nzGfA5Xw/nZty6BjFOX/y3rh9kri6JBufndD2kOCbsJ3ysgUBrt09Wv3qwCJxzrdnHAkme7A7C6oCC/Ya56r0gpdo0fsBjxKmfm1/Kqilgr9vRjtYLVIY+TxVqdWttcU7Tv///QqDi5VgcQPnrUzXa6JN8PGUn3aN5NPnz7XFx+Vb2wtFA7ZdW7ZK9mGBXKNP+zPlP89/uQrXXDNW97JCJQfwfzqLw/B3aEehym9MXBlFmG5ANPoQR0uJJAm/oukSBQIZ+LMvPjr6hvpqFoc6YQqqEP7dgHh4UEWLrVnGItqKaPZ+XQyj11W4yMFgYTr3FAd931/un/s9fAD8ILMq
How to actually get rid of parent instance and use provide inject to achieve same result as in the playground from link above?
The ref needs to be on the actual Child element, not the parent div. The method is a property of test.value, so if the method is called "validate" you can run it with test.value.validate().
You also need to make sure the Child component is imported
Try this SFC Playground instead. The "click me" button will console.log the word "validate" which comes from the Child component.
<script setup>
import Child from './Child.vue'
import { ref } from 'vue'
const test = ref()
const childFunc = () => {
test.value.validate()
}
</script>
<template>
<div>
<Child ref="test" />
</div>
<button #click="childFunc">
click me
</button>
</template>

How to use template refs in Nuxt 3

In Nuxt2 there were template $refs that you could access in <script> with this.$refs
I would like to know what is the Nuxt3 equivalent of this is.
I need this to access the innerText of an element. I am not allowed to use querySelector or getElementById etc.
This is the way we write code. I can give html elements ref="fooBar" but I can't access it with this.$refs.fooBar or even this.$refs.
<script setup lang="ts">
import { ref, computed } from 'vue';
const foo = ref('bar');
function fooBar() {
//Do stuff
}
</script>
<template>
//Html here
</template>
With Options API
<script>
export default {
mounted() {
console.log('input', this.$refs['my-cool-div'])
}
}
</script>
<template>
<div ref="my-cool-div">
hello there
</div>
</template>
With Composition API
<script setup>
const myCoolDiv = ref(null)
const clickMe = () => console.log(myCoolDiv)
</script>
<template>
<button #click="clickMe">show me the ref</button>
<div ref="myCoolDiv">
hello there
</div>
</template>

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

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.