Property or method "item" is not defined on the instance but referenced during render - vue.js

The application throws me an error in the console.
The property or method "logo" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option or for class-based components, by initializing the property
This is what HTML and script look like.
<template id="items-template">
<span class="items">
<img v-if="logo.name" src="/images/name.png"/>
</span>
</template>
#section scripts {
<script type="text/javascript">
Vue.component('items', {
props: ['logo'],
template: '#items-template'
});
</script>
}

Here's an example of how it should work:
<div id="app">
<items :logo="logo"></items>
</div>
<script type="text/x-template" id="items-template">
<div>
<span class="items">
<img v-if="logo.name" src="https://thumbs-prod.si-cdn.com/d4e3zqOM5KUq8m0m-AFVxuqa5ZM=/800x600/filters:no_upscale():focal(554x699:555x700)/https://public-media.si-cdn.com/filer/a4/04/a404c799-7118-459a-8de4-89e4a44b124f/img_1317.jpg"/>
</span>
</div>
</script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var itemComponent = {
template: "#items-template",
props: {
logo: Object
}
}
new Vue({
el: "#app",
data: {
logo: {
name: 'someName'
}
},
components: {
'items': itemComponent
}
})
</script>
In this example, div#app is parent, and it passes down logo to items-component logo prop.

Related

Vue.js component is not showing visually on the page

I have the following Vue component called TeamCard:
<template>
<div class="m-8 max-w-sm rounded overflow-hidden shadow-lg">
<!-- removed fro brevety -->
div class="text-gray-900 font-bold text-xl mb-2">{{ name }}</div>
<p class="text-gray-700 text-base"> {{ description }} </p>
<!-- removed fro brevety -->
</div>
</div>
</template>
<script>
export default {
name: "TeamCard",
props: {
name: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
}
};
</script>
<style scoped>
#import "https://unpkg.com/tailwindcss#^2/dist/tailwind.min.css";
</style>
I call the component in an HTML page (Spring boot template) the following way:
<teamCard v-bind:name="'Hawks'" v-bind:description="'Best team'" ></teamCard>
<script src="https://unpkg.com/vue"></script>
<script th:src="#{/TeamCard/TeamCard.umd.min.js}"></script>
<script>
(function() {
new Vue({
components: {
teamCard: TeamCard
}
})
})();
</script>
When I go to the page in the browser that has the second snippet, nothing is shown. There are no errors in the console. What am I doing wrong? How can I make the component be shown?
I've never seen Vue used this way but it looks like there is no mounting element for the app. Try this:
<div id="app">
<team-card v-bind:name="'Hawks'" v-bind:description="'Best team'"></team-card>
</div>
and
(function() {
new Vue({
el: '#app',
components: {
teamCard: TeamCard
}
})
})();

Only show slot if it has content, when slot has no name?

As answered here, we can check if a slot has content or not. But I am using a slot which has no name:
<template>
<div id="map" v-if="!isValueNull">
<div id="map-key">{{ name }}</div>
<div id="map-value">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
props: {
name: {type: String, default: null}
},
computed: {
isValueNull() {
console.log(this.$slots)
return false;
}
}
}
</script>
I am using like this:
<my-map name="someName">{{someValue}}</my-map>
How can I not show the component when it has no value?
All slots have a name. If you don't give it a name explicitly then it'll be called default.
So you can check for $slots.default.
A word of caution though. $slots is not reactive, so when it changes it won't invalidate any computed properties that use it. However, it will trigger a re-rendering of the component, so if you use it directly in the template or via a method it should work fine.
Here's an example to illustrate that the caching of computed properties is not invalidated when the slot's contents change.
const child = {
template: `
<div>
<div>computedHasSlotContent: {{ computedHasSlotContent }}</div>
<div>methodHasSlotContent: {{ methodHasSlotContent() }}</div>
<slot></slot>
</div>
`,
computed: {
computedHasSlotContent () {
return !!this.$slots.default
}
},
methods: {
methodHasSlotContent () {
return !!this.$slots.default
}
}
}
new Vue({
components: {
child
},
el: '#app',
data () {
return {
show: true
}
}
})
<script src="https://unpkg.com/vue#2.6.10/dist/vue.js"></script>
<div id="app">
<button #click="show = !show">Toggle</button>
<child>
<p v-if="show">Child text</p>
</child>
</div>
Why you dont pass that value as prop to map component.
<my-map :someValue="someValue" name="someName">{{someValue}}</my-map>
and in my-map add prop:
props: {
someValue:{default: null},
},
So now you just check if someValue is null:
<div id="map" v-if="!someValue">
...
</div

In Vue, anyway to reference to the element when binding attributes in template?

In template scope, are there variable referencing the element itself like a $this or $el?
Instead of,
<template>
<div #click="$emit('xxx')" :class="{active:mode=='xxx'}" something_for_xxx></div>
<div #click="$emit('yyy')" :class="{active:mode=='yyy'}" something_for_yyy></div>
<div #click="$emit('zzz')" :class="{active:mode=='zzz'}" something_for_zzz></div>
</template>
Can we write something like the following, to avoid forgetting to change one of the mode name?
<template>
<div mode="xxx" #click="$emit($this.mode)" :class="{active:mode==$this.mode}" something_for_xxx></div>
<div mode="yyy" #click="$emit($this.mode)" :class="{active:mode==$this.mode}" something_for_yyy></div>
<div mode="zzz" #click="$emit($this.mode)" :class="{active:mode==$this.mode}" something_for_zzz></div>
</template>
Workaround:
<template>
<div v-for"mode_ in ["xxx"] #click="$emit(mode_)" :class="{active:mode==mode_}" something_for_xxx></div>
<div v-for"mode_ in ["yyy"] #click="$emit(mode_)" :class="{active:mode==mode_}" something_for_yyy></div>
<div v-for"mode_ in ["zzz"] #click="$emit(mode_)" :class="{active:mode==mode_}" something_for_zzz></div>
</template>
In the event handlers, you can always access $event.target to access the element (see https://v2.vuejs.org/v2/guide/events.html#Method-Event-Handlers) but for inline binding (like :class) you cannot because the element has not been rendered yet.
I suggest you change how you cycle through each value
<div v-for="elMode in ['xxx', 'yyy', 'zzz']"
#click="$emit('click', elMode)" :class="{active:mode==elMode}"/>
That is the typical situation where you should build your elements in a v-for loop:
Vue.component('my-component', {
template: '#my-component',
props: {
mode: String,
},
data() {
return {
modes: ['xxx', 'yyy', 'zzz'],
};
},
});
new Vue({
el: '#app',
data: {
mode: 'xxx',
},
methods: {
log(event) {
this.mode = event;
console.log(event);
}
},
});
.active {
color: green;
}
.pointer {
cursor: pointer;
}
<script src="https://unpkg.com/vue#2"></script>
<div id="app">
<my-component
:mode='mode'
#click="log($event)"
></my-component>
</div>
<template id="my-component">
<div>
<div
v-for="currentMode of modes"
#click="$emit('click', currentMode)"
:class="{active:mode==currentMode}"
class="pointer"
>{{currentMode}}</div>
</div>
</template>

How to use same template on different components in vue js?

Currently I am using as
<template> ... </template>
<script src="test1.js"> </script>
Where all my business logics are written in test1.js. Now I need to use test2.js with same template. I need to reuse the template with different component.
My current code goes like this...
common.vue
<template>
<div>
{{ page }}
</div>
<template>
<script src="../scripts/test1.js"></script>
Where in test1.js
export default {
name: 'home',
components: {
test: test
},
data() {
return {
page: "test1",
}
}
}
But also i need to use common.vue in my test2.js. Which i am not able to import both the .js seperately.
In angular we can write the fallowing late bindig which binds .html and .js(in ui.router)
.state('home', {
url:'/',
templateUrl: 'templates/home.html',
controller: 'HomeController'
})
Is there something similar to this?
You can share the template through the id attribute.
Vue.component('my-comp1', {
template: '#generic',
data () {
return {
text: 'I am component 1'
}
}
})
Vue.component('my-comp2', {
template: '#generic',
data () {
return {
text: 'I am component 2'
}
}
})
new Vue({
el: '#app'
})
<div id="app">
<my-comp1></my-comp1>
<my-comp2></my-comp2>
</div>
<template id="generic">
<div>
<p>{{ text }}</p>
</div>
</template>
<script src="https://unpkg.com/vue"></script>

Reusable nested VueJS components

Is it possible to declare a component inside another component in Vue.JS?
this is what i'm trying to do:
<!-- this is declared inside some-component.vue file -->
<script>
export default {
components:{
'cmptest' : {
template:'#cmptest',
props:['mprop']
}
},
data : () => ({
val:'world'
})
};
</script>
<template>
<div>
<template id="cmptest">
{{mprop}}
</template>
<cmptest mprop="hello"></cmptest>
<cmptest :mprop="val"></cmptest>
</div>
</template>
I'd like to avoid globally registering the child component if possible (with Vue.component(...))
In other words, I'd like to specify child's <template> inside the parent component file (without doing a huge line template:'entire-html-of-child-component-here')
Sure.
Like this:
https://jsfiddle.net/wostex/63t082p2/7/
<div id="app">
<app-child myprop="You"></app-child>
<app-child myprop="Me"></app-child>
<app-child myprop="World"></app-child>
</div>
<script type="text/x-template" id="app-child2">
<span style="color: red">{{ text }}</span>
</script>
<script type="text/x-template" id="app-child">
<div>{{ childData }} {{ myprop }} <app-child2 text="Again"></app-child2></div>
</script>
new Vue({
el: '#app',
components: {
'app-child': {
template: '#app-child',
props: ['myprop'],
data: function() {
return {
childData: 'Hello'
}
},
components: {
'app-child2': {
template: '#app-child2',
props: ['text']
}
}
}
}
});