Vue3 Transparent component wrapper not working - vue.js

I am testing out vue3 and wanted to make a transparent wrapper component (something I will use fairly often) with the new version. With the new syntax it should be as simple v-bind="attrs". This does not seem to be working for me however and there is not much documentation as of yet. Anyone know what the problem could be? See codepen for more details as to how I am implementing it as well.
https://codepen.io/sumcoding/pen/mdJqwgj

I don't know if codepen is a good place to reproduce this since I don't know how to make an import -> import { reactive } from "vue"; so your myValue would be reactive.
Anyway I have got it working using <input v-model="attrs.modelValue">.
Here is codepen
BTW
Since you have registered props, you don't need to return them in a setup method ;-)

The transparent wrapper component pattern for Vue.js 3 final can be implemented like this
<template>
<label>{{ label }}</label>
<input
type="text"
:value="modelValue"
v-bind="$attrs"
#input="$emit('update:modelValue', $event.target.value)"
/>
</template>
<script>
export default {
name: 'InputWrapper',
props: {
modelValue: {
type: String,
default: ''
},
label: {
type: String,
default: ''
}
},
emits: ['update:modelValue']
};
</script>
You can view an example as well as another variation of the pattern for Vue.js 3 here.

Related

How to change the language of whole application from the dropdown in Navbar component in vue

I created a language selection dropdown in my Navbar component. So here is my navbar component:
<div>
<h6>{{ translate("welcomeMsg")}} </h6>
<select name="lang" v-model="lang">
<option value="en">English</option>
<option value="de">Deutsch</option>
</select>
</div>
<script>
export default {
mixins: [en, de],
data() {
return {
lang: "en",
};
},
methods: {
translate(prop) {
return this[this.lang][prop];
}
}
}
</script>
So the parent of this component is an Index.vue which is main component in my application.
<div id="app">
<Topnav/>
<Navbar/>
<router-view></router-view>
<Footer/>
</div>
Currently, I am able to change the language in my Navbar component. So according to the selected value in the dropdown in Navbar component, welcomeMsg is changing. What I am trying to do is I want to put this pieve of code to TopBar "{{ translate("welcomeMsg")}} ", and according to the value of the dropdown in Navbar component, I want to change this value.
Can you help me with this or can you give me an idea how to do it?
If I understand you correctly, you want to use translate method inside Topnav component.
This method is however defined in Navbar, so it's not accessible in Topnav.
To use it elsewhere you could create a mixin with this method to import it to any component. I don't recommend this solution though as mixins are making the code messy.
Another solution is to create a component with translate method defined inside. Let this component do just that: translate a message passed by prop and render it inside some div:
<div>
{{ translatedMessage }}
</div>
<script>
mixins: [en, de],
props: {
message: {
type: String,
default: ''
},
language: {
type: String,
default: 'en'
}
},
computed: {
translatedMessage() {
return this[this.language][this.message];
}
}
</script>
You can reuse this component anywhere in the application. You would still need to pass a language prop somehow, possibly the solution would be to use vuex store to do this, since language is probably global for entire application.
For easier and more robust solutions I would use vue-i18n, which #Abregre has already suggested in his comment: https://stackoverflow.com/a/70694821/9463070
If you want a quick solution for a full-scale application and you don't have a problem with dependencies, you could try to use vue-i18n.
It's a plugin for vue that does exactly this for multi-locale websites/apps in Vue.
https://www.npmjs.com/package/vue-i18n
EDIT
Then in order to use it globally in your app, you should use vuex.
Keep the language selection state there and then wherever you want to use it, you make a computed function with the state.language getter.
The translate function should be a global registered filter
https://v2.vuejs.org/v2/guide/filters.html

Creating components with optional arguments/optional props

I am trying to create my first own components and wishes a simple solution how to create optional arguments, so I mean arguments which can be, but not needed to be used.
E.g. I can decide on usage wether I want to use
<my component :name="name" :description="description">
or only
<my component :name="name">
So in my view I just want to import the component "my component" regularly.
How should my component look like?
I've tried something like:
<template>
<input
:id="name"
:name="name"
type="text"
:description="description"
/>
</template>
<script>
export default {
name: "adsInputText",
props: {
name: String,
description: null
},
</script>
This is only a simplified abstraction of my problem. I have already played through several variants, but just couldn't get it right.
Do you know a simple approach to this?
Thanks a lot
Matthias
If you wish to add an optional prop then you should indicate a type and might want to add a default value for it:
props: {
name: String,
description: {
type: String,
default: null
}
},
That way if you don't indicate description prop when using a component you'll get null from this.description instead of undefined.

How to combine vue-multiselect with vue-treeSelect?

I'm working with Vue.js and I need a "smart" search bar.
I've ended up with vue-multiselect, but I need to have nested menus in the dropdown.
Apparently, there's something called treeSelect that can help me with that, but I don't know how to combine them together.
The code is pretty basic.
<template>
<div>
<multiselect v-model="value" :options="options" placeholder="Pick a value" style="width:600px;"></multiselect>
</div>
</template>
<script lang="ts">
import { Multiselect } from 'vue-multiselect'
#Component({
components: {
Multiselect,
},
})
export default class Income extends Vue {
public Multiselect= Multiselect;
data () {
return {
value: '',
options: ['first','second','third','forth','fifth']
}
}
}
I need the "search-select" bar to be able of searching, nesting and showing disabled options.
I would really need some help, and why not, some advice and guidance :)
Thanks
You can refer this.https://codepen.io/anon/pen/pGqXGa
for more information visit - https://vue-treeselect.js.org/#disable-item-selection
The problem is that I'm trying to use treeselect, but I'm also using typescript.
So, after some research, I found that these two are not compatible.
I have to start looking for an alternative for TreeSelect; a dropdown that supports nesting

How to extend a Vuetify component and keep the ref?

I'm currently using a v-textarea like this:
# Main.vue
v-textarea(ref="myTextArea")
I would like to put a transparent wrapper around it so I can use the same customized version throughout my app. I'm doing this:
# CustomTextarea.vue
<template>
<v-textarea v-bind="$attrs" v-on="$listeners"></v-textarea>
</template>
And I'm using it like this:
# Main.vue
CustomTextarea(ref="myTextArea")
The problem is that now my ref no longer points to the actual <textarea> (it points to the custom component) so something like this no longer works:
mounted() {
this.$nextTick(() => {
this.$refs.myTextarea.focus();
});
}
I don't understand the magic that Vuetify is using, but it does work in v-textarea. Is there a way to do the same in my customized component?
Okay, I think I found my answer here.
I just have to create the method and call it manually:
# CustomTextarea.vue
<template>
<v-textarea
v-bind="$attrs"
v-on="$listeners"
ref="input" //- <= add this
></v-textarea>
</template>
<script>
export default {
name: 'BaseTextarea',
methods: {
focus() {
this.$refs.input.focus(); //- <= call it here
},
},
};
</script>
I wonder if there is any way to automate this, but it works for now.

VueJS functional components (SFC): how to encapsulate code?

I wrote a simple template-substitution component in VueJS as a single-file component. It doesn't have many features: just one prop, and I also made a computed property to encapsulate some tricky transformations that are done to that prop before it can be used in the template. It looks something like the following:
<template>
...some-html-here...
<a :href="myHref">...</a>
...
</template>
<script>
export default {
name: 'MyComponent',
props: {
href: { type: String, required: true },
},
computed: {
myHref() {
let result = this.href;
// several lines of complicated logic making substitutions and stuff
// ...
return result;
}
}
};
</script>
Now I think this should really be a functional component, as it has no state, no data, no reactivity, and so lunking around a whole instance is wasteful.
I can make this functional just by adding the 'functional' attribute to my <template>. In a functional component, of course, there are no such things as computed properties or methods or whatever. So my question is: where can I put my several lines of complicated logic? I don't want to have to embed this directly into my template, especially as it is used in multiple places. So where can I put code to transform my input props and make them ready to use in my template?
Great question.I was trying to find the same answer and i ended up with the following which i don't know if it is a good way to do though.
The "html" part:
<template functional>
<div>
<button #click="props.methods.firstMethod">Console Something</button>
<button #click="props.methods.secondMethod">Alert Something</button>
</div>
</template>
The "js" part:
<script>
export default {
props: {
methods: {
type: Object,
default() {
return {
firstMethod() {
console.log('You clicked me')
},
secondMethod() {
alert('You clicked me')
}
}
}
}
}
}
</script>
See it in action here
Make sure to read about functional components at docs
NOTE: Be aware using this approach since functional components are stateless (no reactive data) and instanceless (no this context).