looping through locally registered components in vuejs - javascript

I have a Vue component that imports and registers other components locally. I want to loop through components object and render them dynamically. I'm trying to achieve this like the following (inside .vue file):
<template>
<div v-for="component in components" class="component">
<component v-bind:is="component"></component>
</div>
</template>
<script>
import CarouselDefault from './carousel/CarouselDefault'
import AlertError from './alerts/AlertError'
import AlertInfo from './alerts/AlertInfo'
import AlertSuccess from './alerts/AlertSuccess'
import AlertWarning from './alerts/AlertWarning'
export default {
name: 'App',
components: {
CarouselDefault,
AlertError,
AlertInfo,
AlertSuccess,
AlertWarning
}
}
</script>
and I get this error message:
Property or method "components" 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.

The components property aren't avalibale in template builder of vue, you have to defien a computed or a property of data .
example:
computed:{
components(){
return [
CarouselDefault,
AlertError,
AlertInfo,
AlertSuccess,
AlertWarning
];
}
}
or
data(){
return {
components:[
CarouselDefault,
AlertError,
AlertInfo,
AlertSuccess,
AlertWarning
]
}
}

Related

How to import dynamic v-bind:is component with module system in Vue

Problem: I am trying to programmatically register a component to be used in a slot in my Vue/Nuxt site. The component name is included in the data of the parent index.vue file, in this instance the component is named Projects. I am including it in a v-for template as the various objects in the 'modules' data array are iterated over. I had assumed this would be possible/easy from the dynamic component documentation and example however I have not managed to get it working in my case.
What I expect to happen: I expected the component to be registered and 'slotted' into the Module component correctly.
What actually happens: While I can see on the rendered view that the component is 'there', it is not in the correct place (i.e. slotted into the Module component). I also get a vue/no-unused-components error saying: The "Projects" component has been registered but not used.
I have read the documentation about component registration in modular systems but these seem to be for more complex cases than what I am trying to achieve. Any advice would be really helpful as I am totally stuck!
index.vue
<template>
<div>
<template v-for="module in modules">
<Module
:title="module.title"
:to="module.link"
/>
<component v-bind:is="module.slot" />
</Module>
</template>
</div>
</template>
<script>
import Module from '~/components/module/Module.vue'
import Projects from '~/components/module/slots/Projects.vue'
export default {
components: {
Module,
Projects
},
data () {
return {
modules: [
{
title: 'Work',
slot: 'Projects'
},
{
...
}
]
}
}
}
</script>
Edit: As a side note, I get the same error when registering the component with import like so:
components: {
Module,
'Projects': () => import('#/components/module/slots/Projects')
}
Module.vue
<template>
<div>
<h2>
{{ title }}
</h2>
<slot />
</div>
</template>
<script>
export default {
props: {
title: {
type: String,
default: ''
}
}
}
</script>
Projects.vue
<template>
<div>
<h3>Projects</h3>
</div>
</template>
<script>
export default {
name: 'Projects'
}
</script>
You use the self closure tag in your Module component.
This prevents your Projects component to be rendered within the slot.
Just replace:
<Module
:title="module.title"
:to="module.link"
/>
with:
<Module
:title="module.title"
:to="module.link"
>
and it should work.

Vue.js - append variable to component

I am currently using Algolia instantsearch for Vue, which is working fine. However, I am using multiple indexes, so I would like to be able to set a custom Title to each of my indexes.
This is my files:
Home.vue:
<ais-index :appId="angoliaAppId" :apiKey="angoliaAppKey" indexName="contacts" :query="query">
<search-results></search-results>
</ais-index>
<ais-index :appId="angoliaAppId" :apiKey="angoliaAppKey" indexName="users" :query="query">
<search-results></search-results>
</ais-index>
import SearchResults from "../search/Results";
export default {
data() {
return {
query: '',
angoliaAppId: process.env.MIX_ALGOLIA_APP_ID,
angoliaAppKey: process.env.MIX_ALGOLIA_SECRET,
};
},
components: {
SearchResults
}
};
And my component file, looks like this:
../search/Results:
<template>
<ais-results class="ais-Hits__root" v-if="searchStore.query.length > 0" :data="category">
<template slot-scope="{ result }">
<div>
<ais-highlight :result="result" attribute-name="name"></ais-highlight>
</div>
</template>
</ais-results>
</template>
import SearchResults from "../search/Results";
import {
Component
} from "vue-instantsearch";
export default {
mixins: [Component]
};
Now, as said, I would very much like to be able to set a custom title name to each of my <search-results> components, like this:
<search-results :title="My Contacts"></search-results>
Which would then for example add this in the component file:
<h1>{{ title }}</h1>
Seems like you'll have to use props
https://v2.vuejs.org/v2/guide/components.html#Passing-Data-to-Child-Components-with-Props

Extend imported component in Vue

I'm using single file components and I'd like to know is there any way to extend imported component
For example I have Products.vue and Filter.vue component. Products.vue component contains string with table name it gets data from. Filter.vue to work should know table name it filters. Normaly I should pass that data with props from Products.vue to Filter.vue. But the problem is that there is multiple filters that becomes repetitive and I'd like to avoid it.
Will be good if there is some construction for extending imported component like:
Products.vue:
<template>
...
</template>
<script>
import Filter from './Filter.vue'
export default {
components: {
// something like
'extendedFilter': Filter.extend({ data() { return { table: this.table_name } } })
},
data() {
return {
table_name: 'test_table'
}
}
}
</script>

Multiple components, but only first one rendered

I'm trying to create simple ToDo app using Ractive.js and Redux, but I ran into a problem with rendering more than one component on my page.
Javascript code:
import Ractive from 'ractive';
import template from './Home.html';
import './Home.less';
import { AddToDoForm, ToDoList } from '../';
export default Ractive.extend({
template,
data: {
message: 'This is the home page.',
},
components: {
AddToDoForm,
ToDoList
}
});
HTML of the component:
<AddToDoForm store={{store}} />
<ToDoList store={{store}} />
But only the first component is rendered. The store parameter I'm passing is the Redux store, but it doesn't work even without it.
I would add to verify defaults as a
...
components:{
AddToDoForm: AddToDoForm,
ToDoList: ToDoList
}
...
syntax examples (answer/31096635)

Vue how to call filter from parent

How can I be able to call filter of parent using single file component. Below are my code.
app.js
import computed from '../vue/mixins/computed.js';
import filters from '../vue/mixins/filters.js';
import methods from '../vue/mixins/methods.js';
const app = new Vue({
el: '#app',
mixins:[
computed,
filters,
methods
],
mounted: function() {
}
});
home.vue
<template>
<div class="home-content">
<h3>{{home | uppercase}}</h3>
</div>
</template>
<script type="text/javascript">
export default {
data: function() {
return {
home: 'home'
}
},
mounted: function() {
this.$parent.$options.methods.makeConsole();
}
}
</script>
It's giving me this warning in console "Failed to resolve filter: uppercase"
You should just make the filter global available before starting the root instance with
Vue.filter('uppercase', uppercase);
Where uppercase can be a simple function like
function uppercase(str)
return str.uppercase();
}
That would be the most simple and reliable way to use the filter on all vue components;
If you import your filters to your parent via mixins why don't you use that mixin in the child?
Please do not use the this.$parent-method as it makes your child component statical dependend of that parent.
To use the $parent approach you may need to declare the filter function from the parent as a filter in the child:
filters:{
uppercase: this.$parent.$options.filters.uppercase
}
There is no point. Just include your mixin in the child as well. A component should ideally be autonomous, and not aware of where it is in the hierarchy of components (at least not the ones above or on the same level.

Categories