How to add resize event handler to my vue code? - javascript

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>

Related

Pushing component one level down with Vue 3 and Ionic

Instead of mounting my component directly to #app, I'm trying to push my component one level down so I can pass props to it from the HTML file it lives in. However, nothing shows up and there aren't any console errors. I'm sure it's just me misunderstanding how Vue 3 and createApp works.
My HTML file:
<div id="app">
<my-component />
</div>
My main JS file:
import { createApp } from 'vue'
import MyComponent from './pages/MyComponent.vue'
import { IonicVue } from '#ionic/vue'
const app = createApp({
components: {
MyComponent: {
props: {
},
}
},
})
.use(IonicVue)
.mount("#app");
Thank you in advance!

Vue 3 TypeScript - Problem with `App.vue` in `main.ts` and Tests

I'm using TypeScript with Vue and I'm facing this error from my main.ts file.
Here's my shims-vue.d.ts file:
/* eslint-disable */
declare module "*.vue" {
import type { DefineComponent } from "vue";
const component: DefineComponent<{}, {}, any>;
export default component;
}
My App.vue is just a simple template without any script or style:
<template lang="pug">
router-view
</template>
I do not want to do the "noImplicitAny": false in tsconfig.js, so is there any solution to this problem apart from that?
Also, same thing happens in test cases,
import { shallowMount } from "#vue/test-utils";
import Layout from "#/plugin/layout/Layout.vue";
describe("Layout.vue", () => {
it("renders props.msg when passed", () => {
const wrapper = shallowMount(Layout);
expect(wrapper.text()).toMatch("sidebar");
});
});
Error is:
The reason for the error is that you named your vue file App.vue.js.
The solution: rename App.vue.js to App.vue

How to react to route changes on Vue 3, "script setup" composition API?

This is an example of routes I have in my application:
{
path: "/something",
name: "SomeRoute",
component: SomeComponent,
meta: {showExtra: true},
},
{
path: "/somethingElse",
name: "SomeOtherRoute",
component: SomeOtherComponent,
},
Then I have the following component, which as you will notice has two script tags, one with composition API, one without:
<template>
<div>
This will always be visible. Also here's a number: {{ number }}
</div>
<div v-if="showExtra">
This will be hidden in some routes.
</div>
</template>
<script setup lang="ts">
import type { RouteLocationNormalized } from "vue-router"
import { ref } from "vue"
const number = 5
const showExtra = ref(true)
const onRouteChange = (to: RouteLocationNormalized) => {
showExtra.value = !!to.meta?.showExtra
}
</script>
<script lang="ts">
import { defineComponent } from "vue"
export default defineComponent({
watch: {
$route: {
handler: "onRouteChange",
flush: "pre",
immediate: true,
deep: true,
},
},
})
</script>
This works correctly: when I enter a route with meta: {showExtra: false} it hides the extra div, otherwise it shows it.
What I want to do, however, is achieve the same by only using the composition API, in other words removing the second <script> tag entirely. I have tried this:
<script setup lang="ts">
import type { RouteLocationNormalized } from "vue-router"
import { ref } from "vue"
import { onBeforeRouteUpdate } from "vue-router"
// ...
// same as before
// ...
onBeforeRouteUpdate(onRouteChange)
</script>
But this won't take effect as expected when I switch route. I'm aware of the watch function I could import, but I'm unsure how to get the meta information about the route and how to appease the type checker.
You can convert your watcher to composition api by importing watch method from vue
<script lang="ts">
import { defineComponent, vue } from "vue"
import { useRoute } from "vuex"
export default defineComponent({
setup() {
const route = useRoute()
watch(route, (to) => {
showExtra.value = !!to.meta?.showExtra
}, {flush: 'pre', immediate: true, deep: true})
},
})
</script>

How to use <component :is=""> in vue 3 script setup

I am using the experimental script setup to create a learn enviroment. I got a selfmade navigation bar with open a single component.
I am having trouble using the <component :is="" /> method. This method is described in the docs under component basics -> dynamic-components
In the Vue 3 Composition API, it works as expected:
<template>
<NavigationBar
#switchTab="changeTab"
:activeTab="tab"
/>
<component :is="tab" />
</template>
<script>
import { ref } from 'vue'
import NavigationBar from './components/NavigationBar.vue'
import TemplateSyntax from './components/TemplateSyntax.vue'
import DataPropsAndMethods from './components/DataPropsAndMethods.vue'
export default {
components: {
NavigationBar,
TemplateSyntax,
DataPropsAndMethods
},
setup () {
const tab = ref('DataPropsAndMethods')
function changeTab (newTab) {
tab.value = newTab
}
return {
changeTab,
tab
}
}
}
</script>
My approach with the script setup fails:
<template>
<NavigationBar
#switchTab="changeTab"
:activeTab="tab"
/>
<component :is="tab" />
</template>
<script setup>
import NavigationBar from './components/NavigationBar.vue'
import TemplateSyntax from './components/TemplateSyntax.vue'
import DataPropsAndMethods from './components/DataPropsAndMethods.vue'
import { ref } from 'vue'
const tab = ref('DataPropsAndMethods')
function changeTab (newTab) {
tab.value = newTab
}
</script>
do you got any idea how to solve this with the script setup method?
It seems with <script setup>, tab needs to reference the component definition itself instead of the component name.
To reference the component definition, which does not need reactivity, use markRaw() before setting tab.value:
<script setup>
import DataPropsAndMethods from './components/DataPropsAndMethods.vue'
import { ref, markRaw } from 'vue'
const tab = ref(null)
changeTab(DataPropsAndMethods)
// newTab: component definition (not a string)
function changeTab (newTab) {
tab.value = markRaw(newTab)
}
</script>
demo 1
If you need to pass the component name to changeTab(), you could use a lookup:
<script setup>
import DataPropsAndMethods from './components/DataPropsAndMethods.vue'
import { ref, markRaw } from 'vue'
const tab = ref(null)
changeTab('DataPropsAndMethods')
// newTab: component name (string)
function changeTab (newTab) {
const lookup = {
DataPropsAndMethods,
/* ...other component definitions */
}
tab.value = markRaw(lookup[newTab])
}
</script>
demo 2
Tested with Vue 3.0.9 setup with Vue CLI 5.0.0-alpha.8

How I can make #Model and #Emit work together in VueJs with Typescript?

can anyone help me with decorators #Model and #Emit?
I'm trying to change order on click in my component and used documentation from here: https://github.com/kaorun343/vue-property-decorator.
Here is my code:
<template>
<button #click="onSortClick">Sort</button>
</template>
<script lang="ts">
import Vue from "vue";
import { Emit, Componet, Model } from "vue-property-decorator";
export default class MyButton extends Vue {
#Model("sort", { type: String, default: "none" }) readonly order!: string;
#Emit("sort")
onSortClick() {
const nextSortOrder = {
ascending: "descending",
descending: "none",
none: "ascending"
};
return nextSortOrder[this.order];
}
}
</script>
But when I click the button, the value of variable "order" is not changing. Am I doing something wrong?
Yes, you are. There are a few things wrong here.
You need to import vue like this import { Vue, Component, Model, Emit } from 'vue-property-decorator;
The class needs to have an #Component decorator like this
#Component({/* Additional data can go in here */})
export default class MyButton extends Vue {}
This isn't how vue intended emitting of events to work. You cannot alter the value of order because it is a readonly property within the same file. If you place your button in another component like this
// ParentFile.vue
<template>
<my-button #sort="order = $event"></my-button>
</template>
<script lang="ts">
import { Component, Vue, Watch } from 'vue-property-decorator';
import MyButton from '#/components/MyButton.vue';
#Component({
components: {
MyButton
}
})
export default class Home extends Vue {
order = 'Wow';
#Watch('order')
orderChanged(newVal: string) {
// eslint-disable-next-line no-console
console.log(newVal); // order will change here
}
}
</script>
and listen to the emitted event as above then the order variable in the parent component will change but not the child.

Categories

Resources