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

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

Related

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,
},

Vuejs how to use repeated methods in single components

How would I use the same method across different components without rewriting the same method for reach component. I looked into mixins but the documentation says 'Use global mixins sparsely and carefully'. So I'm wondering if there is a more ideal way for this approach. Same with global computed.
<template>
<div class="wrapper">
...
Link on many templates
...
</div>
</template>
<script>
export default {
data() {
return {}
},
methods: {
goToPage(page) {
return this.$store.commit('page/push', {page:page});
}
}
}
</script>
Thanks
Global mixins are not the only type of mixin. See https://v2.vuejs.org/v2/guide/mixins.html
If you want to add a method or computed property to every component then you'd use a global mixin. This would affect all components, including those from third party libraries. You'd need to be careful when choosing a name to ensure you don't collide with anything else. There's also a small performance overhead from using a global mixin. As an example, Vuex uses a global mixin to ensure that the $store property is present on all components.
If you only need to add the method/property to a few components then you'd be much better off with a normal mixin. Typically that would have its own file and look something like this:
// my-mixin.js
export default {
methods: {
goToPage(page) {
return this.$store.commit('page/push', {page:page});
}
}
}
and then within your .vue files:
<script>
import myMixin from 'my-mixin'
export default {
mixins: [myMixin],
// ... all the other options
}
</script>
Given the example in the question seems to be a navigational link, an alternative to using a mixin might be to introduce a suitable component to handle those links. Rather than sharing code between components you'd just use the link component. It would depend on whether the method has uses beyond those links.
There are alternatives, such as sharing things globally across components using Vue.prototype, but for the example given in the question that doesn't seem a good fit.
I would also note that Vue 3 introduces some new alternatives to mixins via the composition API. However, it isn't immediately obvious that using composition would actually be an improvement in your specific use case. Vue 3 is also still in beta.

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 share variable with Nuxt.js from layout to pages?

I actually work on a project that consists of display data from Jsons on a Nuxt.js website using Vuetify. I have created a selector in my layout to choose which Json the user wants to display. I need to access this variable from all the different pages of my project.
Here is what my default.vue looks like :
<template>
<v-overflow-btn
:items="json_list"
label="Select an Json to display"
v-model="selected_json"
editable
mandatory
item-value="text"
></v-overflow-btn>
</template>
<script>
export default {
data() {
return {
selected_json: undefined,
json_list: [
{text: "first.json"},
{text: "second.json"},
],
}
}
}
</script>
The variable I would like to access from all my different pages is selected_json.
I see many things on the internet such as Vuex or a solution that consist to pass the variable with the URL. But I'm kind of newby in web programming (started Vue/Nuxt one week ago) and I don't really understand how to apply this in my project. So if there is a more easy way to do it or a good explaination, I'm interested!
Thanks in advance for your help :)
Using Vuex we can easily achieve what you want.
First of all create a file index.js in folder store (if you don't have a store folder then create it in the same directory where your pages, plugins, layouts etc folders are). Then paste this piece of code in index.js
//store/index.js
export const state = () => ({
selected_json: null
})
By doing this we set Vuex up. More precisely just state part of Vuex where if you don't know we store data accessible across your project.
Now we have to assign data from your default.vue to Vuex. We can achieve this by creating a mutation function through which we change state in Vuex. Add this to your index.js
//store/index.js
export const mutations = {
setSelectedJson(state, selectedJson) {
state.selected_json = selectedJson
}
}
Here function setSelectedJson takes two params, state which is automatically passed in by Nuxt.js and it includes all our Vuex state data. The second parameter selected_json we pass in ourselves.
Now in your default.vue we need to add a watcher for selected_json so we can update our Vuex when selected_json gets updated.
//layouts/default.vue
export default {
watch: {
selected_json(newValue) {
this.$store.commit("setSelectedJson", newValue)
}
}
}
We are almost done.
The last thing we need to do is to make a getter which is used to retrieve values from Vuex. A getter like this will do its job.
//store/index.js
export const getters = {
getSelectedJson(state) {
return state.selected_json
}
}
That's it.
Now you can access selected_json on any page you want by simply getting it from Vuex with this line of code.
this.$store.getters["getSelectedJson"]

What is the name of my Vue component?

I'm trying to use Vue for a little project.
I started with only client code. So when I did
const mv = new Vue({...});
I was able to access to the component from outside with a mv.
Now I'm using Vue.cli, so I define my component inside a mv.vue and then I have
export default {
data () {}
}
Here, how can I get the nme of my component?
Thanks for any reply or hint :)
You can get the name of the component , you can do this
this.$vnode.tag
If you want the parent component's name from its child do this
this.$parent.$vnode.tag
You can name your component like so:
export default {
name: 'mv',
data () {
return {}
}
}
But to access it you'd need to use the name that you import it with. For example:
import theVariableIWantItToBe from './mv.vue'
console.log(theVariableIWantItToBe)
To expand on the very good #vamsi-krishna answer, and update it, I've discovered that Vue now often puts a prefix on the $vnode.tag along the lines of vue-component-3-YourComponentName.
You can fix this by using the following code. And perhaps, just in case of a missing tag, fall back to the ID of the root element in the component.
Occasionally, Vue doesn't pass back a component at all in its errorHandler and warnHandler global events. So I've handled that scenario first.
if (!vm){
return '[unknown]'
}
if (vm.$vnode.tag) {
const res = vm.$vnode.tag
return res.replace(/vue-component-\d+-/i, '')
}
if (vm.$el.id) {
return vm.$el.id
}