Import vue component and extend template - vue.js

Isn't it possible to extend the template of an imported component installed via NPM?
I've tried this, but doesn't work.
import Foo from 'Foo'
export default {
extends: Foo,
template: `<p>foo</p>`
}

The .vue files export components definition only, so you are able to do something like this:
import Foo from 'Foo'
var Bar = {
// inherit everything from Foo
mixins: [Foo],
// rewrite the template
template: `<div>` + Foo.template + `</div>`
}
export default Bar
Keep in mind that Foo is just an object, it is just the definition of the component like the one you export in your own components, so you may feel free to use all it's options, but if you modify them you affect their usage in whole project. Think twice when doing things like:
Foo.template = `<div>${Foo.template}</div>`

Related

Vue 3 use dynamic component with dynamic imports

I use Vue 3 and I have a dynamic component. It takes a prop called componentName so I can send any component to it. It works, kind of.
Part of the template
<component :is="componentName" />
The problem is that I still need to import all the possible components. If I send About as a componentName I need to import About.vue.
Part of the script
I import all the possible components that can be added into componentName. With 30 possible components, it will be a long list.
import About "#/components/About.vue";
import Projects from "#/components/Projects.vue";
Question
It there a way to dynamically import the component used?
I already faced the same situation in my template when I tried to make a demo of my icons which are more than 1k icon components so I used something like this :
import {defineAsyncComponent,defineComponent} from "vue";
const requireContext = require.context(
"#/components", //path to components folder which are resolved automatically
true,
/\.vue$/i,
"sync"
);
let componentNames= requireContext
.keys()
.map((file) => file.replace(/(^.\/)|(\.vue$)/g, ""));
let components= {};
componentNames.forEach((component) => { //component represents the component name
components[component] = defineAsyncComponent(() => //import each component dynamically
import("#/components/components/" + component + ".vue")
);
});
export default defineComponent({
name: "App",
data() {
return {
componentNames,// you need this if you want to loop through the component names in template
};
},
components,//ES6 shorthand of components:components or components:{...components }
});
learn more about require.context

How to import multiple vue files as one

In other to avoid multiple imports into my vuejs app I created an index.js file and imported all the files in it like so:
import AddMember from "./AddMember.vue";
import EditMember from "./EditMember.vue";
export {
AddMember,
EditMember,
};
Then in my component compenent I imported them like so:
import * as Members from "../members/index.js";
export default {
name: "members-table",
components: {
AddMember: Members.AddMember
EditMember: Members.EditMember,
},
}
The EditMember Component is a dialog that opens up per the member clicked. But Anytime I click on a member on a the table I get and error that looks like this: even though the name prop was defined in all the components.
Unknown custom element: <edit-member> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
I resolved the problem my importing the EditMember.vue file itselfimport EditMember from './EditMember';. My question however, is there a way I can achieve this. Or better still what I'm I missing or did wrong.
well if it`s reusable components your trying to do so wouldnt it be better to create base components? and then you dont need to import them each time?
import { AddMember, EditMember } from "../members/index.js"; this should work like #Asimple said
Maybe you can try to import them separately?
Like this:
import { AddMember, EditMember } from "../members";
Update:
Changed import source, please, try it.
Working example here
Try this, you may need to create alias as:
components: {
'AddMember': Members.AddMember, // use single quotes
'EditMember': Members.EditMember,
},

Vue.js Create a helper class to call your methods globally

I have just started my first project with Vue.js, I have managed to do a lot of basic things and now I am trying to structure the project. I want to achieve the highest possible code reuse. One of the most frequent cases of my application is going to be showing messages of different types, confirmation, information, etc. For this reason, I want to create a mechanism that allows me to launch these messages globally, regardless of where I call them.
As far as I have been able to advance, I have opted for the following variant:
1- I have created a directory called classes in my src directory.
2- I have created a file called MessageBox.js inside classes directory with the following content:
import Vue from 'vue';
export default class MessageBox extends Vue {
confirm() {
return alert('Confirm');
}
information() {
return alert('Information');
}
}
I define it like this because I want to call these methods globally as follows:
MessageBox.confirm();
I am really new to Vue.js and I was wondering if there is any other way to achieve the results I am looking for in a more efficient way .... or .. maybe more elegant?
Thank you very much in advance..
There are at least 2 ways of going about this:
Event bus
Rely on Vue.js internals to create a simple EventBus. This is a design pattern used in Vue.js.
Create a file and add the following lines to it
import Vue from 'vue';
const EventBus = new Vue();
export default EventBus;
Create your component that takes care of displaying global dialogs. This is usually registered at the top of the tree, so it can cover the entire real estate.
Import the event bus import EventBus from 'event_bus' and then register for the new events
EventBus.$on('SHOW_CONFIRM', (data) => {
// business logic regarding confirm dialog
})
Now you can import it in any component that wants to fire an event like so
EventBus.$emit('SHOW_CONFIRM', confirmData);
Vuex
You can also use vuex to store global data regarding dialogs and add mutations to trigger the display of the dialogs.
Again, you should define a component that takes care of displaying and push it towards the top of the visual tree.
Note: in both cases you should handle cases in which multiple dialog need to be shown at the same time. Usually using a queue inside the displaying component works.
It's an antipattern in modern JavaScript to merge helper functions that don't rely on class instance into a class. Modules play the role of namespaces.
Helper functions can be defined as is:
messageBox.js
export function confirm() {
return alert('Confirm');
}
They can be imported and used in component methods. In case they need to be used in templates, they can be assigned to methods where needed one by one:
Some.vue
import { confirm } from './util/messageBox';
export default {
methods: { confirm }
}
Or all at once:
import * as messageBox from './util/messageBox';
export default {
methods: { ...messageBox }
}
Helpers can be also be made reusable as Vue mixins:
messageBox.js
...
export const confirmMixin = {
methods: { confirm };
}
export default {
methods: { confirm, information };
}
And used either per component:
Some.vue
import { confirmMixin } from './util/messageBox';
export default {
mixins: [confirmMixin]
}
Or globally (isn't recommended because this introduces same maintenance problems as the use of global variables):
import messageBoxMixin from './util/messageBox';
Vue.mixin(messageBoxMixin);

How to import multiple components with the same name in a Vuejs project?

I've inherited a Vue.js project that, among other things, has this:
import Multiselect from 'vue-multiselect';
<multiselect :multiple="true"
v-model="selectedTags"
:options="tagOptions"
label="title"
track-by="id"></multiselect>
Now, on the same page, we are also supposed to have a different multiselect object, imported from a different place, that looks like:
import Multiselect from './../../../../../../vendor/devcompany/scripts/vue/components/form/multiselect.vue';
<multiselect v-model="selectedTeacherIds"
:sortable="true"
:options="computedTeacherOptions">
<template slot="selected-option-value" slot-scope="{optionKey}">
{{teacherNames[optionKey]}}
</template>
Each of these works well individually, but I am supposed to somehow import both of them and use them both within the same component. Clearly this will not work without some sort of alteration to the code.
Is there some syntax to, perhaps, import as and thus change the name of one of the objects? Or do I need to go into the source code of one of them and change the naming there? The former (or some other solution not requiring changing the multiselect core files themselves) would be more desirable.
EDIT: This is what the code looks like more broadly.
import Multiselect from 'vue-multiselect';
import BbcodeEditor from './../elements/bbcode-editor';
import ApiVideoSelect from './api-video-select';
/* import other assets */
export default {
components: {ApiVideoClassDetail, ApiProgramCard, ApiUploader, Multiselect, Draggable, Datepicker, BbcodeEditor, ApiVideoSelect},
So I am wondering how to edit this syntax to add the other multiselect under a different name. I don't see how this could work:
import Multiselect from 'vue-multiselect';
import Multiselect from './../../../../../../vendor/frismedia/scripts/vue/components/form/multiselect.vue';
You do not have to change core files, just change the name while using the component:
import Multiselect from '....vue/components/form/multiselect.vue';
// your parent component
export default {
components: {
'my-custom-multiselect' : Multiselect
}
}
// in template:
<my-custom-multiselect> </my-custom-multiselect>
A simpler syntax: Change the name while importing
import MyCustomMultiselect from '....vue/components/form/multiselect.vue';
export default {
components: {
MyCustomMultiselect
}
}
// in template:
<my-custom-multiselect> </my-custom-multiselect>

Vue.js - How do I relocate computed properties into an external library file?

I'm new to Vue and was just assigned to an existing Vue project. I noticed the computed properties of one component were getting to around 200 lines. Can computed properties be relocated into an external .ts file and imported? If so, what would the import look like?
Everything I've seen has the computed properties located in the component itself. I'm not even sure it's 'allowed', and if it is I wouldn't know how to import it and then utilize it in the component.
I appreciate the help!
Well I don't know if it helps but you can create a mixin. Read here about them
So you have computed.js:
export const computed = {
computed: {
my_comp_prop() {
//some code
}
}
}
And then in your components:
import { computed } from './computed'
export default {
mixins: [computed],
//more code
}
In the end everything will merge in your component instance. Please don't forget to read about mixins and also about Custom Option Merge Strategies