vue access valid data from parent component - vue.js

I can access method from parent vue component using ref and now I would like to access valid data from parent vue component using ref too
Parent.vue:
<v-btn #click="savenewcase()" dark text :disabled="!valid">Save</v-btn></v-toolbar-items>
<NewCaseDialog ref="NewCase"></NewCaseDialog>
<script>
methods: {
savenewcase() {
this.$refs.NewCase.save()
}
}
</script>
NewCaseDialog.vue
<template>
<v-card>
<v-form v-model="valid" ref="NewCaseForm" #keyup.native.enter="save()">
<v-container>
<v-text-field
:counter="64"
v-model="vsubject"
label="Subject / Judul"
prepend-icon="subject"
></v-text-field>
</v-container>
</v-form>
<v-btn #click="save()" :disabled="!valid" color="primary">Save</v-btn>
</v-card>
</template>
<script>
data: () => ({
valid: false,
}),
methods:{
save() {
//run save
}
}
</script>
Edit :
I'm using vuetify

You can try Props instead, it's much easier. From docs:
child-component.vue
Vue.component('blog-post', {
// camelCase in JavaScript
props: ['postTitle'],
template: '<h3>{{ postTitle }}</h3>'
})
parent.vue
<blog-post post-title="hello!"></blog-post>

Related

Pass click function with input v-model params

I have a btnSmall component with this props and click
<v-btn
class="white--text btn_main_product"
color="red darken-1"
#click="click"
>
<slot/>
</v-btn>
props: {
click: Function
}
I use this component like this in another component.
<template>
<v-card
class="pa-4"
>
<v-text-field
v-model="lname"
></v-text-field>
<v-btn :click="clickAccept(lname)">accept/v-btn>
</v-card>
</template>
<script>
import BtnSmall from "../buttons/btnSmall";
export default {
name: "editName",
components: {BtnSmall},
data() {
return {
lname: ''
}
},
props: ['clickAccept']
}
</script>
and use this component in the page.
after use <edit-name :click-accept="nameClickAccept"/> whit this method.
nameClickAccept(fname, lname) {
console.log(lname)
}
my method run with change text-field i cant use click.
i need run method with click on the btn.
The vue-approach would be to emit an event in the btnSmall component and react on that event in the parent component.. This: https://v3.vuejs.org/guide/component-custom-events.html#event-names shows you how you can do it.

Vue js - How to use props in data and methods

I am new in vue js , I am passing data from parent component to child one using props and I can use it in child normally but I can't use it in data of child component
parent
<template>
<div>
<show-question :qdata="question" v-if="question"></show-question>
<h1 v-if="!question"> some error </h1>
</div>
</template>
<script>
import ShowQuestion from './ShowQuestion';
export default {
created(){
axios.get(`/api/question/${this.$route.params.slug}`)
.then(res => {
this.question = res.data.data
})
},
data(){
return {
question : {},
}
},
components:{
ShowQuestion,
},
}
</script>
child
<template>
<v-container>
<v-card>
<div>
<v-card-title class="blue--text"
>{{ data.title }}
<v-spacer></v-spacer>
<v-btn color="teal white--text">5 Replies</v-btn>
</v-card-title>
<v-card-subtitle
> {{data.uid}} {{ data.user }} said {{ data.created_at }}</v-card-subtitle
>
</div>
<v-card-text>{{ data.body }}</v-card-text>
<v-card-actions v-if="own">
<v-btn icon text>
<v-icon color="orange">create</v-icon>
</v-btn>
<v-btn icon text>
<v-icon color="red">delete</v-icon>
</v-btn>
</v-card-actions>
</v-card>
</v-container>
</template>
<script>
export default {
props: ['qdata'],
data(){
return {
own: User.own(this.qdata.uid),
};
},
};
</script>
this.qdata.uid is always be undefined in console, although it supposed it have values and I can saw it from child template
enter image description here
Your show-questioncomponent is mounted early on because v-if="question" is true. When show-question is mounted, your api call hasn't had a chance to finish, so question is the same as the initial value {}, which is why uid is undefined.
I would change question : {} to question: null, then the child component will only be mounted when there's a question (after the api call).
This is simply because if you check the truthy of an object it will always return true even if the object is empty, which results in the component being rendered before the API call has finished.
Instead, you can check if it's empty or not by converting it to an array and check it's length value, i.e. Object.entries(question).length or simply use the lodash helper method: _isEmpty(question).
Also a quick side note: it's cleaner to use v-else after v-if when you want to render something or the other instead of explicitly negating the value in another v-if, though they're required to be direct siblings.

Vue Composition API createComponent child components

I'm simply trying to use a child component in a Nuxt/Composition API/TypeScript project using Vuetify. I've tried including the component before the setup method, but when I view the source I only see <!----> where the child component data should be.
This is the layouts/default.vue layout that should be displaying the "nested" component.
<template>
<v-app>
<v-app-bar clipped-left app color="indigo darken-2" />
<v-content>
<nuxt />
</v-content>
<v-bottom-navigation
v-model="bottomNav"
color="indigo darken-2"
absolute
class="hidden-sm-and-up"
>
<v-btn
value="search"
#click="dialog=true"
>
<span>Search</span>
<v-icon>mdi-magnify</v-icon>
</v-btn>
</v-bottom-navigation>
<v-dialog v-model="dialog">
<ListFilter
#closeDialog="closeDialog"
/>
</v-dialog>
</v-app>
</template>
<script lang="ts">
import { createComponent, ref } from '#vue/composition-api'
import ListFilter from '~/components/ListFilter.vue'
export default createComponent({
components: { ListFilter },
setup() {
const bottomNav = ref<string>()
const dialog = ref<boolean>(false)
const closeDialog = () => {
dialog.value = false
bottomNav.value = ''
}
return {
bottomNav,
dialog,
closeDialog
}
}
})
</script>
Here is the sample contents of the components/ListFilter.vue component to be nested, the contents of which matter little.
<template>
<v-card>
<v-card-title>
Search
</v-card-title>
<v-card-text>
Test Text
</v-card-text>
<v-card-actions>
<v-btn
#click="closeDialog"
>
Close
</v-btn>
</v-card-actions>
</v-card>
</template>
<script lang="ts">
import { createComponent } from '#vue/composition-api'
export default createComponent({
setup(_, { emit }) {
const closeDialog = () => {
emit('closeDialog')
}
return closeDialog
}
})
</script>
Problem is return closeDialog in setup function of ListFilter component. If you return a function from setup(), Vue expects it is a render function. Try return { closeDialog } instead...

Vuetify: Navigation drawer: communicate v-model changes to parent co

I have created a Sidebar component using Vuetify's navigation drawer. The code looks something like this:
<template>
<v-navigation-drawer persistent clipped v-model="isVisible" fixed app>
<!-- content of the sidebar goes here -->
</v-navigation-drawer>
</template>
<script>
export default {
name: 'Sidebar',
props: {
visible: Boolean,
},
data() {
return {
isVisible: this.visible,
};
},
}
</script>
Please note that I am duplicating the visible prop with the isVisible data. I tried using the prop directly in the v-model but every time the sidebar closed, I would get a warning in the console about changing props directly, as they would be overwritten when the parent re-renders.
In the parent view, I have a button on the toolbar that is supposed to change icon depending on the visibility of the toolbar.
<template>
<v-container fluid>
<sidebar :visible="sidebarVisible"/>
<v-toolbar app :clipped-left="true">
<v-btn icon #click.stop="sidebarVisible = !sidebarVisible">
<v-icon v-html="sidebarVisible ? 'chevron_right' : 'chevron_left'"/>
</v-btn>
</v-toolbar>
<v-content>
<router-view/>
</v-content>
<v-footer :fixed="fixed" app>
<span>© 2017</span>
</v-footer>
</v-container>
</template>
<script>
import Sidebar from '#/components/Sidebar.vue';
export default {
name: 'MainView',
data() {
return {
sidebarVisible: false,
fixed: false,
title: 'Title',
};
},
components: {
Sidebar,
},
};
</script>
The problem I have is that if I close the sidebar by clicking outside of it, the icon of the button on the toolbar does not change to chevron-left. Moreover, in order to bring the sidebar back, I need to click on the button twice.
Clearly this is because the sidebarVisible data in the main view is not updated when the sidebar closes. How do I make sure that sidebarVisible is updated when the sidebar closes?
I am use next construction...
in my component
<template>
<v-navigation-drawer v-model="localDrawer"></v-navigation-drawer>
</template>
...
<script>
export default {
props: { value: { type: Boolean } },
data: () => ({
localDrawer: this.value
}),
watch: {
value: function() {
this.localDrawer = this.value
},
localDrawer: function() {
this.$emit('input', this.localDrawer)
}
}
}
</script>
in parent layer
<app-drawer v-model="drawer"></app-drawer>
it's work for me
Use v-bind:value or :value to bind the drawer value from props.
Child component:
<template>
<v-navigation-drawer v-bind:value="drawer"></v-navigation-drawer>
</template>
<script>
export default {
props : ['drawer']
}
</script>
Parent component:
<template>
<app-side-bar :drawer="drawer"/>
<v-app-bar app clipped-left>
<v-app-bar-nav-icon #click.stop="drawer = !drawer"></v-app-bar-nav-icon>
</v-app-bar>
</template>
Vuetify navigation drawer issue fix:
Reset your browser window to default 100%
Here is the code,
Template:
<nav>
<v-toolbar flat app>
<v-toolbar-side-icon class="grey--text" #click="toggle"></v-toolbar-side-icon>
<v-toolbar-title class="text-uppercase grey--text">
<span class="font-weight-light">Repo</span>
<span>hub</span>
</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn flat color="grey">
<span>Sign Out</span>
<v-icon right>exit_to_app</v-icon>
</v-btn>
</v-toolbar>
<v-navigation-drawer app v-model="drawer" class="indigo">
<p>test</p>
</v-navigation-drawer>
</nav>
Script:
export default {
data() {
return {
drawer: false
};
},
methods:{
toggle(){
this.drawer = !this.drawer;
}
}
};

VueJS change v-model variable from child

I'm trying to change the v-model of a component by the parent component most I'm not getting.
In the parent component I have a showProgress variable, I want it when I change it to true the child v-model <progress-modal> switch to true.
ProgressModal.vue
<template>
<v-dialog v-model="show" persistent max-width="400">
<v-card :dark="($theme === 'dark')">
<v-card-title class="headline" v-text="title"></v-card-title>
<v-divider></v-divider>
<div class="text-xs-center mt-2">
<v-progress-circular indeterminate :size="100" :color="$color"></v-progress-circular>
<v-card-text v-text="text"></v-card-text>
</div>
</v-card>
</v-dialog>
</template>
<script>
export default {
name: 'progress-modal',
props: ['title', 'text'],
data: () => ({
show: true
}),
methods: {
}
}
</script>
I already tried to use
<progress-modal v-model="showProgress">
Instead of v-model in v-dialog but it does not work :(
Pass value prop as value to v-dialog component, and re-emit input from v-dialog component:
//CustomDialog.vue
<v-dialog :value="value" #input="$emit('input', $event)">
</v-dialog>
...
props:['value']
and add v-model to your parent (custom dialog)
//Parent.vue
<custom-dialog v-model="showProgress">
Example
To enable usage of v-model by the parent, you have to define a value prop in the child and use it.
<template>
<v-dialog v-model="value" persistent max-width="400">
...
</template>
<script>
export default {
name: 'progress-modal',
props: ['title', 'text', 'value'], // added 'value'
data: () => ({
...
</script>
This way, when you use:
<progress-modal v-model="showProgress">
...the value inside progress-modal will have the value of parent's showProgress.
Keeping it named show
To use other internal name instead of value you can declare the model option in the component.
<template>
<v-dialog v-model="show" persistent max-width="400">
...
</template>
<script>
export default {
name: 'progress-modal',
props: ['title', 'text', 'show'], // added 'show'
model: { // added model option
prop: 'show' //
}, //
data: () => ({
}), // in this case, remove show from data
...
</script>