v-for vue wierd behaviour - vue.js

<template>
<v-app>
<v-app-bar
app
color="primary"
dark
>
<v-btn #click="func" ></v-btn>
</v-app-bar>
<v-main>
<router-view/>
<ul id="example-2">
<li :v-for="item in items">
{{ item.message }}
</li>
</ul>
</v-main>
</v-app>
</template>
<script lang="ts">
import { Vue, Component } from 'vue-property-decorator';
#Component
export default class App extends Vue {
links = ['/', '/login'];
items = [
{ message: 'Foo' },
{ message: 'Bar' }
]
value = 'text';
func() {
console.log(this.value)
}
}
</script>
I am trying to use v-for at any part of code on any component but it always give me an error on single item.

The correct syntax is v-for without the :
: Is a shorthand for Vue v-bind directive
Quote from the Vue docs:
The v-bind directive is a Vuejs directive used to bind one or more
attributes, or a component prop to an element. If that attribute is binded
to our data defined in Vuejs instance then dynamically changes can be
observed as data changes.

Related

Vue: Hand Over An Object To A Component For It To Use

In my app I have a list component which I use inside another component. Currently, it looks something like this:
<script setup>
const seed = [
{
key: value,
anotherKey: anotherValue,
},
// and so on...
];
</script>
<template>
<ul>
<li v-for="element in seed" :key="element.key" :anotherKey="element.anotherKey">
</ul>
</template>
My question is: Is it possible to somehow "hand over" an object inside the parent component which uses this list component instead of getting the object from within the list component's script tag?
You can use provide in your parent component to pass an object to your child components.
ParentComponent.vue (Untested code)
<script setup>
const seed = [
{
key: value,
anotherKey: anotherValue,
},
// and so on...
];
provide('seed', seed)
</script>
ChildComponent.vue
<script setup>
const seed = inject('seed')
</script>
<template>
<ul>
<li v-for="element in seed" :key="element.key" :anotherKey="element.anotherKey">
</ul>
</template>
You can read about provide in compositions.
https://vuejs.org/api/composition-api-dependency-injection.html

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.

Vuetify v-dialog do not show in spite of value attribute equal to true

I am using vuex store state to show/hide Vuetify v-dialog in my NuxtJS app. Following are the code excerpt:
Vuex Store:
export const state = () => ({
dialogOpen: false
});
export const mutations = {
setDialogToOpen(state) {
state.dialogOpen = true;
},
setDialogToClosed(state) {
state.dialogOpen = false;
}
};
export const getters = {
isDialogOpen: state => {
return state.dialogOpen;
}
};
Dialog Component:
<v-dialog
v-model="isDialogOpen"
#input="setDialogToClosed"
max-width="600px"
class="pa-0 ma-0"
>
...
</v-dialog>
computed: {
...mapGetters("store", ["isDialogOpen"])
},
methods: {
...mapMutations({
setDialogToClosed: "store/setDialogToClosed"
})
}
This all works fine but when I redirect from one page to another page like below it stops working.
this.$router.push("/videos/" + id);
I hit browser refresh and it starts working again. Using the Chrome Vue dev tools, I can see the state is set correctly in the store as well as in the v-dialog value property as shown below
In Vuex store
In v-dialog component property
Yet the dialog is not visible. Any clue what is happening?
I am using NuxtJS 2.10.2 and #nuxtJS/Vuetify plugin 1.9.0
Issue was due to v-dialog not being wrapped inside v-app
My code was structured like this
default layout
<template>
<div>
<v-dialog
v-model="isDialogOpen"
#input="setDialogToClosed"
max-width="600px"
class="pa-0 ma-0"
>
<nuxt />
</div>
</template>
Below is the code for index page which replaces nuxt tag above at runtime.
<template>
<v-app>
<v-content>
...
</v-content>
</v-app>
</template>
So, in the final code v-dialog was not wrapped inside v-app. Moving v-app tag to default layout fixed it
<template>
<v-app>
<v-dialog
v-model="isDialogOpen"
#input="setDialogToClosed"
max-width="600px"
class="pa-0 ma-0"
>
<nuxt />
</v-app>
</template>

How to set $ref to child component elements from parent component in vuejs?

This is the parent component:
<template>
<upload-block
:imSrc="LargeIcon"
inputName="LargeIcon"
:inputHandler="uploadAppIcon"
inputRef="LargeIcon"
:uploadClickHandler="handleUploadIcon"></upload-block>
</template>
<script>
export default class ParentCom extends Vue {
//all props for <upload-block></upload-block> component defined here
handleUploadIcon(event) {
const icon_type = event.currentTarget.getAttribute("data-type");
let appImgElem = this.$refs[icon_type];
appImgElem.click();
}
async uploadAppIcon(event) {
//code
}
}
</script>
And this is the child component:
<template>
<div class="upload-div" #click="uploadClickHandler" :data-type="inputName">
<img v-if="imSrc" :src="imSrc">
<div v-else class="upload-icon-block">
<span>
<font-awesome-icon class="upload-icon" icon="arrow-circle-up" size="lg"></font-awesome-icon>
<br>Click to upload
</span>
</div>
<!-- <spinner variant="primary" :show="true"></spinner> -->
<input style="display:none" type="file" :ref="inputRef" :name="inputName" #input="inputHandler">
</div>
</template>
<script>
#Component({
props: {
imSrc: String,
inputRef: String,
inputName: String,
inputHandler: Function,
uploadClickHandler: Function
}
})
export default class ChicdCom extends Vue {
}
</script>
The problem I am facing in the handleUploadIcon method in which I am not able to get the input element via ref.
It is showing Cannot read property 'click' of undefined in this line appImgElem.click();
But when I move the file input to the parent component, it's works fine. So can you plz help me how to set the ref to child component elements from parent as currently is it not setting.
Thanks
Well you could add a ref to upload-block in the parent component:
<upload-block ref="upload" ... >
Then in the handleUploadIcon you can acces your input: this.$refs.upload.$refs[icon_type]
But I would try to move handleUploadIcon to the child component if I were you.

How to access parents data value in vuejs with the template syntax

In my VueJS app I am using bootstrap-vue and want to use iframe inside a collapsable elements b-collapse. Because of some problems with iframe content and resizing (problem not related here) I found out that if I enable/disable b-embed with conditional rendering it works.
The parent component b-collapse has a data element called show which change its state if toggle is clicked. In my HelloWorld component I want that b-collapse can pass it's show value into the if check of b-embed.
My approach with this.$parent.$data.show isn't working and I am not sure if there is any better way to do so.
<template>
<div>
<b-btn v-b-toggle.logs>
<span class="when-opened">Close</span>
<span class="when-closed">Open</span>
Trace
</b-btn>
<b-collapse id="logs">
<b-embed :src="src" v-if="this.$parent.$data.show"></b-embed>
<div>Data: {{this.$parent.$data.show}}</div>
</b-collapse>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import { Prop, Component, Inject } from "vue-property-decorator";
#Component
export default class HelloWorld extends Vue {
src = "http://localhost:7681/";
}
</script>
Like this:
parent.vue
<template>
<Child :show="myShow"></Child>
</template>
<script>
import Child from './child'
export default {
data () {
return {
myShow: 'StackOverflow'
}
},
components: {Child}
}
</script>
child.vue
<div>
<b-btn v-b-toggle.logs>
<span class="when-opened">Close</span>
<span class="when-closed">Open</span>
Trace
</b-btn>
<b-collapse id="logs">
<b-embed :src="src" v-if="this.$parent.$data.show"></b-embed>
<div>Data: {{this.$parent.$data.show}}</div>
</b-collapse>
</div>
<script>
export default {
props: {
show: {
type: Number,
require: true
}
}
}
</script>
Or use vuex to do this.