onActivated wont trigger in Quasar (vue3) component - javascript

For some reason the onActivated function in vue3 wont trigger and cannot figure out why. It is not the first time I am implementing this but for some reason nothing happens. I am using vue 3.0.0. Here is my code and component
Index.vue
<template>
<MyComp />
</template>
<script setup>
import MyComp from "../components/MyComp.vue";
</script>
MyComp.vue
<template>
<div>{{ el }}</div>
</template>
<script setup>
import { ref, onMounted, onActivated } from "vue";
const el = ref("Hello");
onMounted(() => {
console.log("onMounted");
});
onActivated(() => {
console.log("onActivated");
});
</script>

onActivated only triggers for components inside a KeepAlive tag, but you don't have any KeepAlive tags in the code you posted, so onMounted should be all you need. See https://vuejs.org/api/composition-api-lifecycle.html#onactivated

Related

Conditional template rendering with props in Vue3?

I'm trying to make a toggle button so that a hamburger menu opens when clicked.
I made the boolean "clicked" property in "App.vue", passed it down to "Navbar.vue", and now I want to be able to click in the navbar to toggle the "clicked" property to "true" or "false" to make the backdrop and drawer show or not show.
I tried to use an "emit", and it seems to work, but the template isn't responding to the "clicked" variable and is showing even though it's false.
In the code below, what part did I get wrong? How do you implement conditional rendering with props? Can someone help?
App.vue
<template>
<NavBar :clicked="clicked" #toggleDrawer="toggleMenu()" />
<BackDrop :clicked="clicked" />
<SideDrawer :clicked="clicked" />
<router-view></router-view>
</template>
<script>
export default {
name: "App",
components: { NavBar, BackDrop, SideDrawer },
setup() {
const clicked = ref(false);
const toggleMenu = () => {
clicked.value = !clicked.value;
};
return { clicked, toggleMenu };
},
};
</script>
NavBar.vue
<template>
<nav class="navbar">
/* MORE CODE */
<div class="hamburger_menu" #click="toggleEvent">
<div></div>
<div></div>
<div></div>
</div>
</nav>
</template>
<script setup>
import { defineEmits, defineProps } from "vue";
const props = defineProps({
clicked: Boolean,
});
const emit = defineEmits(["toggleDrawer"]);
const toggleEvent = () => {
console.log("toggleEvent running");
emit("toggleDrawer", !props.clicked);
};
</script>
Backdrop.vue
<template v-if="props.clicked">
<div class="backdrop"></div>
</template>
<script setup>
import { defineProps } from "vue";
// eslint-disable-next-line no-unused-vars
const props = defineProps({
clicked: Boolean,
});
</script>
SideDrawer.vue
<template v-if="props.clicked">
<div class="sidedrawer"></div>
</template>
<script setup>
import { defineProps } from "vue";
const props = defineProps({
clicked: Boolean,
});
</script>
Am I passing in the prop wrong? Does "props.clicked" not work in "v-if"'s or templates? How should I implement the "v-if" with the "clicked" property I have?
As #neha-soni said,
After running the code, it is working fine
Vue recommends to use kebab-cased event listeners in templates. Your toggleDrawer will auto-converted into kebab case when you use it in the parent component. So In app.vue you can use it like #toggle-drawer,
<NavBar :clicked="clicked" #toggle-drawer="toggleMenu()" />
From vue doc link
event names provide an automatic case transformation. Notice we emitted a camelCase event, but can listen for it using a kebab-cased listener in the parent. As with props casing, we recommend using kebab-cased event listeners in templates.
After running the code, it is working fine. I have a few feedbacks to remove unnecessary code which is creating confusion and then you can see its working.
Because props are immutable (read-only) in the child component that means their value will not be changed so there is no point to pass props value back (by doing emit("toggleDrawer", !props.clicked)) to the parent because the parent already has their original status.
Another point is, you are passing the data (props data) from the event by doing emit("toggleDrawer", !props.clicked) but not using it when calling the function #toggleDrawer="toggleMenu()" in App.vue, so better to remove this data passing code.
The clicked property is updating in the parent (App.vue) as well as inside the child components. Just console and print the clicked property in the child and parent template like {{ clicked }} at the top and you can see the updated status-
const toggleMenu = () => {
console.log('Before______', clicked.value)
clicked.value = !clicked.value;
console.log('After______', clicked.value)
};

How to add resize event handler to my vue code?

I am new to Vue. I am a react developer trying to update some legacy code from my work.
What I want to do is I want to have a screen resize event handler in my component.
I found some helpful code pen https://codepen.io/sandrarodgers/pen/porZbxW
The thing is I don't know how to add those in my existing component.
To give you the general idea. My component already got two script tags
When I try to copy paste from codeine it give me some error on this keyword
Component
<template>
<div :style="styles">
...
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import MultipleChoiceField from '../fields/MultipleChoiceField.vue';
import NumberField from '../fields/NumberField.vue';
export default defineComponent({
name: 'Questionnaire',
components: {
MultipleChoiceField,
NumberField,
},
});
</script>
<script setup lang="ts">
import {
defineProps,
defineEmits,
computed,
nextTick,
onMounted,
ref,
toRefs,
watch,
unref,
} from 'vue';
import {
handleQuestionLogicCalculator,
} from '../../lib/main';
import { typeformMarkdownToHtml } from '../../lib/processTypeformMarkdown';
import {
PrefilledAdditionalParameters,
QuestionnaireChoice,
} from '../../lib/types';
import localize from '../../lib/localization';
const props = defineProps<{
additions: PrefilledAdditionalParameters;
questionnaireConfig: QuestionnaireConfig;
styles: QuestionnaireStyles;
submitAnswers: ShowThankYouFunction;
showwelcomeScreen: () => void;
goBack: () => void;
}>();
const emit = defineEmits(['latestQuestionnaireIndex']);
//MORE CODE HERE
</script>

Vue.js composition API <script setup> - how to two-way bind props

I am struggling to find a way how to create two-way props binding between parent and child components using Vue.js3. Below you can find an example of my code. Unfortunately, the "emit" function does nothing at this point. Thank you for your help.
ParentComponent.vue
<template>
<child-component :loading="isChildLoading">
{{ isChildLoading ? 'Child component is loading' : 'Child component is NOT loading' }}
</template>
<script setup>
import {ref} from "vue";
import ChildComponent from 'ChildComponent';
const isChildLoading = ref(false);
</script>
ChildComponent.vue
<script setup>
import {defineProps, defineEmits, onMounted} from "vue";
const props = defineProps({
loading: Boolean
});
const emit = defineEmits(['update:loading']);
onMounted(() => {
emit('update:loading', true)
//After some kind of XMLHttpRequest request set loading to 'false'
setTimeout(() => {
emit('update:loading', false)
}, 5000);
});
</script>
The emit does nothing because you are not listening for the event. You need to do something like this:
<child-component :loading="isChildLoading" #update:loading="isChildLoading = $event">
You can also setup v-model binding, but it is probably not the correct way here:
https://vuejs.org/guide/components/events.html#usage-with-v-model
Btw.: You don't need to import defineProps or defineEmits since those are compiler macros and automatically available inside the <setup setup> block (https://vuejs.org/api/sfc-script-setup.html#defineprops-defineemits)

vuejs 3 composition API

Anyone know why the variable number doesn't display the latest value when click on it? I tried using onMounted, but didn't seem to do anything. When I clicked on the paragraph it always displays 1. I expect it to display the latest number added. Any ideas?
<script setup>
import TheWelcome from '#/components/TheWelcome.vue'
import { onMounted, ref } from 'vue'
import axios from "axios"
let number = 1;
function getCurrentNumber() {
number++;
console.log(number)
}
</script>
<template>
<main>
<TheWelcome />
</main>
<p #click="getCurrentNumber">Hello, this is a test to display {{number}}</p>
</template>
This is how it should be
<script setup>
import { ref } from 'vue'
const number = ref(1);
function getCurrentNumber() {
number.value++
console.log(number.value)
}
</script>
<template>
<p #click="getCurrentNumber">Hello, this is a test to display {{ number }}</p>
</template>
Here is a working example.

Creating a child component within a parent component in Vue.JS

I am trying to figure out how to make one component inside of another one in VueJS. For instance, something like this, which unfortunately does not work (the child component appears to do nothing):
http://www.webpackbin.com/NyI0PzaL-
I am equally interested in doing this using inline-templates as much as by using the .vue file extension method as shown above.
Here is the code from the non-working example above:
main.js
import Vue from 'vue'
import App from './App.vue'
import Child from './Child.vue'
new Vue({
el: 'body',
components: { App, Child }
})
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
</head>
<body>
<app></app>
<script src="main.js"></script>
</body>
</html>
App.vue
<template>
<div>
<h1>{{ parent_msg }}</h1>
<child></child>
</div>
</template>
<script>
export default {
data () {
return {
parent_msg: 'Hello From the Parent!'
}
}
}
</script>
Child.vue
<template>
<h1>{{ child_msg }}</h1>
</template>
<script>
export default {
data () {
return {
child_msg: 'Hello From the Child!'
}
}
}
</script>
Even though this above example is hosted on webpackbin.com, in the two projects where I would like to use this, I am using Laravel in one along with Laravel Spark in the other. In the plain Laravel app, I'm primarily using .vue files, and in the Laravel Spark app, I'm primarily using inline-templates. I'd be especially grateful for any working samples. Thanks!
UPDATE
Thanks to Linus for his answer below. It appears I need these changes to register the child component globally in my main.js file:
import Vue from 'vue'
import App from './App.vue'
import Child from './Child.vue'
Vue.component('child', Child);
new Vue({
el: 'body',
components: { App, Child }
})
Alternatively, in order to keep the child component local to be used within the parent, I could change the parent component (App.vue) as follows:
<template>
<h1>{{ parent_msg }}</h1>
<div>
<child></child>
</div>
</template>
<script>
import Child from './Child.vue';
export default {
components: {Child},
data () {
return {
parent_msg: 'Hello from the parent component!'
}
}
}
</script>
You registered the Child component locally in the main instance, so it is not available in App.vue
Remove it form the main instance and add it to App.vue:
App.vue
<template>
<div>
<h1>{{ parent_msg }}</h1>
<child></child>
</div>
</template>
<script>
import Child from './child.vue'
export default {
data () {
return {
parent_msg: 'Hello From the Parent!'
}
},
components: {child: Child}
}
</script>
..or register it globally with Vue.component('child', Child) in your main.js file. Then it's available everywhere.

Categories

Resources