component not handling empty prop - javascript

I have a component data.table.vue and other components for eg abc.vue and xyz.vue.
inside this data.table.vue, a paragraph to render depending on the prop received by the it.. However, not both my components abc.vue and xyz.vue will send props.. only abc.vue needs to send props.. for eg:
in abc.vue:
<template>
<data-table
:isShown=true
<data-table>
</template>
and in xyz.vue no props
<template>
<data-table
</data-table>
</template>
and in data.table.vue
<p v-if="isShown"> hello world </p>
but I want this paragraph to be always shown for xyz component..
and only for abc.vue, i want this paragraph to render according to the props isShown.. However, even in xyz.vue , its being rendered depending on the props sent in abc.vue..
Please help ..

You can set a default prop like this.
export default {
props: {
isShown: {
type: Object,
default: true
}
}
}
Default will be taken when no props are passed.

For Vue3 with the composite API you can set default props like this:
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
props: {
isShown: {
type: boolean,
default: true
},
},
setup() {},
})
</script>
And with the script setup
<script setup lang="ts">
const props = withDefaults(
defineProps<{
isShown: boolean
}>(),
{
isShown: true
}
)
</script>

Related

Static props validation in Vue.js

When using props validation in Vue, it only shows errors during the runtime in the browser console.
But I want to get props validation to work during the static code analysis phase (linting).
For example, I have used the default Vue 2 project template:
HelloWorld.vue is the component that has msg prop and it's required:
<template>
<h1>Message: {{ msg }}</h1>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: {
type: String,
required: true,
},
},
};
</script>
App.vue is using HelloWorld component, but doesn't specify msg prop. Instead, it uses non-existent prop something:
<template>
<HelloWorld :something="somewhat" />
</template>
<script>
import HelloWorld from './components/HelloWorld.vue';
export default {
name: 'App',
components: {
HelloWorld,
},
};
</script>
I expect at least some of these requirements to be met when I run npm run lint:
it should say Error: required "msg" prop not found
it should say Warning: unknown "something" prop has been used
also, if I assign something other than String to msg prop, it should say Error: prop "msg" should be String, but received *NotString*
In other words, I want Vue templates to be lintable, like JSX templates in React.
Is there any way I can achieve this in Vue 2 or Vue 3? Perhaps, some eslint plugins?
If this can be solved using TypeScript - that would be super awesome.
A solution to this problem, which works in both Vue 2 and Vue 3 is to use JSX (TSX).
Here's a Vue 3 example:
HelloWorld.tsx:
import { defineComponent } from "vue";
export default defineComponent({
name: "HelloWorld",
props: {
msg: {
type: String,
required: true,
},
},
setup: (props) => () => <h1>{props.msg}</h1>,
});
App.tsx:
import { defineComponent } from "vue";
import HelloWorld from "./components/HelloWorld";
export default defineComponent({
name: "App",
render: () => <HelloWorld msg={"123"} />,
});
Here's Vue 2 example repo: https://github.com/Maxim-Mazurok/vue-2-tsx-example
And Vue 3: https://github.com/Maxim-Mazurok/vue-3-tsx-example

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.

How to change vue-cookie-law default Props

I am trying to change buttonText default value of the component vue-cookie-law with Props.
I can change the default value directly from the node_modules plugin source code, but I would like to change it from a Vue Single File Component.
vue-cookie-law - https://www.npmjs.com/package/vue-cookie-law
prop default type
buttonText: 'Got It!'
Since I haven't used Props before, I've been trying few things, below is my CookieLaw.vue component
<template>
<footer>
<cookie-law theme="base">
<div slot="message">
We use cookies to enhance your experience. By continuing to visit our site you agree to our use of cookies.
<router-link to="terms_and_conditions">View Policy</router-link>
</div>
</cookie-law>
</footer>
</template>
<script>
import CookieLaw from "vue-cookie-law";
export default {
props: {
buttonText: {
default: "Agree"
}
},
components: { CookieLaw }
};
</script>
The props are not changing the default of buttonText.
buttonText is one of the default props for the vue-cookie-law component as you know ... not the parent component (the one that you import it on ) so you have to bind them to the component it self :
<cookie-law theme="base" buttonText="Agree">
...
</cookie-law>
Or bind a dynamic value :
<script>
import CookieLaw from "vue-cookie-law";
export default {
data() {
return {
text: 'Agree'
}
}
components: {
CookieLaw
}
}; <
</script>
<cookie-law theme="base" :buttonText="text">
...
</cookie-law>

Vue: Set child-component data with props values not working

Simply, I have two components:
Parent component which passes a prop object called "profile"
Child component which receives the profile prop
The profile value is an object like this:
{
name: "Something",
email: "some#thing.com"
}
What happens?
The child component receives perfectly the profile value in the template, but it seems impossible to retrieve and set it to the component data.
What is the goal?
I want to initialise the value "email" with the profile email prop.
What did I expect?
export default {
props: ["profile"],
data() {
return {
email: this.profile.email
}
}
}
UPDATE
I haven't specified that email is a data value used as model.
I have just tried to remove it and simply print the value of email in the template and it doesn't work as well.
<!-- PARENT COMPONENT -->
<template>
<dialog-settings ref="dialogSettings" :profile="profile"></dialog-settings>
</template>
<script>
import Auth from "../services/apis/auth";
import DialogSettings from "../components/dialog-settings";
export default {
name: "app",
components: {
"dialog-settings": DialogSettings
},
beforeCreate() {
Auth.checkToken()
.then(profile => {
this.profile = profile;
})
.catch(err => {
});
},
data() {
return {
title: "App",
drawer: true,
profile: {},
navItems: []
};
}
}
</script>
<!-- CHILD COMPONENT -->
<template>
{{profile}} <!-- All the fields are passed and available (e.g. profile.email)-->
{{email}} <!-- Email is not defined -->
</template>
<script>
import Auth from "../services/apis/auth";
import DialogSettings from "../components/dialog-settings";
export default {
name: "dialog-settings",
props: ["profile"],
data() {
return {
email: this.profile.email
}
}
}
</script>
UPDATE 2
I have tried several things and I think that the problem is the asynchronous call to the API in the beforeCreate().
your child component email property should be a computed value
<!-- CHILD COMPONENT -->
<template>
<div>
{{profile}} <!-- All the fields are passed and available (e.g. profile.email)-->
{{email}} <!-- Email is not defined -->
</div>
</template>
<script>
import Auth from "../services/apis/auth";
import DialogSettings from "../components/dialog-settings";
export default {
name: "dialog-settings",
props: ["profile"],
data() {
return {
}
},
computed: {
email () {
return this.profile ? this.profile.email : 'no email yet'
}
}
}
</script>
That's because parent component property is set after rendering child component.
"Data" is not reactive, it's set once when component is created. Prop 'profile" is reactive so first when you render component you should see {} and after response from Auth is set.
If you still want to keep it in data, you could display child component like that:
<dialog-settings ref="dialogSettings" :profile="profile" v-if="profile.email"></dialog-settings>
But i wouldn't recommend that!

Passing data from parent to be rendered on component, data passage failure

I am trying to pass a first and last name to a child component to render as a custom element. Should be simple. But I am not able to link up my props for some reason. Here is the relevant parent code...
<div class="panel-body">
<full-name :userData.firstname="firstname"
:userData.lastname="lastname"></full-name>
</div>
<script>
import toggleSwitch from './components/toggleSwitch.vue';
export default {
data () {
return{
userData: {
firstname: '',
lastname: ''
}
}
},
components: {
'fullName': fullName
}
}
</script>
As you can see I call the element and pass it my two data props. Once there I simply output my data via string interpolation, and... nothing shows. Here is my output component
<template>
<div>
<p>{{firstname}} {{lastname}}</p>
</div>
</template>
<script>
export default{
props: ['firstname', 'lastname']
}
</script>
Am I missing something obvious? Thanks in advance.
It should be like this:
<full-name :firstname="userData.firstname" :lastname="userData.lastname"></full-name>
Syntax:
<comp :prop-name='value'></comp>

Categories

Resources