Vue check if "v-model.number" (Modifier) is being used - javascript

There is a way to know when it is being used v-model.number?
<component v-model.number="value" />
component.vue
...
onMounted(() => {
if (props.modelValue.isUsingModifierNumber()){
console.log('Yes')
}
})
...

In Vue 3, v-model modifiers are passed as a modelModifiers prop - see the docs
define a prop on your component
props: {
modelValue: Number,
modelModifiers: {
type: Object,
default: () => ({})
}
}
Test
created() {
if(this.modelModifiers.number)
{
// ....
}
}

Related

Vue 3 Render Function how to set up v-model and onClicks

Does anybody here have experience with Vue 3 Render Function? I don't know how to set up the v-model and on clicks, the documentation on Vue 3 somewhat kinda useless and lacks practical usage examples.
Maybe someone has a sample code?
If you want to emulate the v-model directive in the render function try something like :
h('input', {
value: this.test,
onInput:(e)=> {
this.test = e.target.value
}
})
which is equivalent to <input v-model="test" />
const {
createApp,
h
} = Vue;
const App = {
data() {
return {
test: "Test"
}
},
render() {
return h('div', {}, [h('input', {
value: this.test,
onInput:(e)=> {
this.test = e.target.value
}
}),h("h4",this.test)])
}
}
const app = createApp(App)
app.mount('#app')
<script src="https://unpkg.com/vue#3.0.0-rc.11/dist/vue.global.prod.js"></script>
<div id="app">
</div>
#Boussadjra Brahim
render() {
self = this; // Added this
return h('div', {}, h('input', {
value: this.test,
onInput(e) {
self.test = e.target.value // Change this.test to self.test
}
}))
}
Thank you for this, I don't know why onKeyUp didn't work but onInput did.

Vue mixin render HTML and append to $ref

I want to use a mixin to find a referenced Node and then append some HTML to it rendered using Vue, so I can pass data into it.
const Tutorial = guide => ({
mounted() {
this.guide = guide;
this.html = Vue.compile(`<p>Test</p>`).render;
guide['add-location'].forEach(step => {
this.$refs[step.ref].appendChild(this.html);
})
},
data: function() {
return {
guide: null,
html: null
}
}
});
export default Tutorial;
This is what I have at the moment, it gets the ref correctly, just can't append the HTML as I don't think i'm using Vue.compile correctly.
Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'
In my opinion, It's better if we can avoid mutate DOM directly. What about replace ref with v-html?
const tutorial = guide => ({
mounted() {
guide['add-location'].forEach(step => {
this[step.ref] += this.html;
})
},
data: function() {
return {
...guide['add-location'].reduce((result, step) => {
result[step.ref] = ''
return result
}, {}),
html: `<p>Test</p>`
}
}
});
const Foo = {
template: `
<div>
<div v-html='foo'></div>
<div v-html='bar'></div>
</div>
`,
mixins: [tutorial({
'add-location': [
{ ref: 'foo' },
{ ref: 'bar' }
]
})]
}
Another idea is using wrapper component to wrap target or if your target is a component then you create a wrapper as mixin too.
Using with html property:
<wrapper ref='foo'>
<div>Foo</div>
</wrapper>
const Wrapper = {
props: ['html'],
render(h) {
return h('div', [this.$slots.default, h('div', {
domProps: {
innerHTML: this.html
}
})])
}
}
...
this.$refs.foo.html = '<h1>Hello Foo</h1>'
Example
Or using with custom appendChild method:
const Wrapper = {
data: () => ({
children: []
}),
methods: {
appendChild(child) {
this.children.push(child)
}
},
render(h) {
return h('div', [
this.$slots.default,
...this.children.map(child => h('div', {
domProps: {
innerHTML: child
}
}))
])
}
}
...
this.$refs.foo.appendChild('<h1>Hello Foo</h1>')
this.$refs.foo.appendChild('<h1>Hello Bar</h1>')
Example
Or using with Vue.compile in case that html is not plain html:
const Wrapper = {
data: () => ({
template: '',
context: {}
}),
methods: {
setChild(template, context) {
this.template = template
this.context = context
}
},
render(h) {
let res = Vue.compile(this.template)
return h('div', [
this.$slots.default,
h({
data: () => this.context,
render: res.render,
staticRenderFns: res.staticRenderFns
})
])
}
}
...
this.$refs.foo.setChild('<h1>Hello {{ name }}</h1>', {
name: 'Foo'
})
Example

Pass params to mapGetters in Vuex

Good day.
I use modules in my vue.js project. Now i need to get filtered data from getter, but don't undestand how provide params.
I want provide 'name' parameter to Getter. How i can do it in Component.vue ?
/*State in vuex*/
state: {
tempMessageValues: [
{ name: 'RU', status: 'none', selected: false },
{ name: 'BY', status: 'none', selected: false },
{ name: 'KG', status: 'none', selected: false }
]
}
/*Getters*/
import * as types from '../types';
export default {
[types.GETTERS.TEMP_MESSAGE_VALUES]: state => {
return state.tempMessageValues.find(country => country.name === name);
}
};
/*Types*/
export const GETTERS = {
TEMP_MESSAGE_VALUES: 'shared/TEMP_MESSAGE_VALUES'
};
/*Code in Component.vue*/
import * as types from "./store/types";
import { mapGetters } from "vuex";
export default {
computed: {
...mapGetters({
getTempMessValues: types.GETTERS.TEMP_MESSAGE_VALUES
})
}
};
The docs suggest using currying to pass params to a getter;
export default {
[types.GETTERS.TEMP_MESSAGE_VALUES]: state => name =>
state.tempMessageValues.find(country => country.name === name)
};
See https://vuex.vuejs.org/guide/getters.html#method-style-access for their example. You're essentially making your getter return a function the first time it's called.
Does that make sense?
A way would be to return a function from the getter, which you can then use to pass a parameter in
export default {
[types.GETTERS.TEMP_MESSAGE_VALUES]: state => {
return (name) => state.tempMessageValues.find(country => country.name === name);
}
};
Now you can pass a parameter to your getter by calling your function:
this.getTempMessValues('YourValue')

Vue binding parent and child components

How to binding parent's model to child in Vue.js?
These codes below is works fine. if i fill the input manually, then child's model return it's value to the parent's model.
But the issue is, if the data set from AJAX request in a parent, the input doesn't automatically filled.
Can anyone help me on this?
Form.vue
<template>
<form-input v-model="o.name" :fieldModel="o.name" #listenChanges="o.name = $event"/>
<form-input v-model="o.address" :fieldModel="o.address" #listenChanges="o.address = $event"/>
</template>
<script>
import FormInput from '../share/FormInput.vue'
export default {
data () {
return {
o: {
name: '',
address: ''
}
}
},
components: { 'form-input': FormInput },
created: function() {
axios.get('http://api.example.com')
.then(response => {
this.o.name = response.data.name
this.o.address = response.data.address
})
.catch(e => { console.log(e) })
}
}
</script>
FormInput.vue
<template>
<input type="text" v-model='fieldModelValue' #input="forceUpper($event, fieldModel)">
</template>
<script>
export default {
props: ['fieldModel'],
data() {
return {
fieldModelValue: ''
}
},
mounted: function() {
this.fieldModelValue = this.fieldModel;
},
methods: {
forceUpper(e, m) {
const start = e.target.selectionStart;
e.target.value = e.target.value.toUpperCase();
this.fieldModelValue = e.target.value.toUpperCase();
this.$emit('listenChanges', this.fieldModelValue)
}
}
}
</script>
Things are more straightforward if you take advantage of v-model in components.
If you put v-model on a component, the component should take a prop named value, and should emit input events to trigger it to update.
I like to make a computed to hide the event emitting, and allow me to just v-model the computed inside my component.
new Vue({
el: '#app',
data: {
o: {
name: '',
address: ''
}
},
components: {
'form-input': {
template: '#form-input',
props: ['value'],
computed: {
fieldModelValue: {
get() {
return this.value;
},
set(newValue) {
this.$emit('input', newValue.toUpperCase());
}
}
}
}
},
// Simulate axios call
created: function() {
setTimeout(() => {
this.o.name = 'the name';
this.o.address = 'and address';
}, 500);
}
});
<script src="//unpkg.com/vue#latest/dist/vue.js"></script>
<div id="app">
Name ({{o.name}})
<form-input v-model="o.name"></form-input>
Address ({{o.address}})
<form-input v-model="o.address"></form-input>
</div>
<template id="form-input">
<input type="text" v-model='fieldModelValue'>
</template>
The mounted() hook is blocking subsequent updates from the parent.
Remove mounted and change v-model to 'fieldModel'
<template>
<input type="text" :value='fieldModel' #input="forceUpper($event, fieldModel)">
</template>
<script>
export default {
props: ['fieldModel'],
data() {
return {
fieldModelValue: ''
}
},
// mounted: function() {
// this.fieldModelValue = this.fieldModel;
// },
methods: {
forceUpper(e, m) {
const start = e.target.selectionStart;
e.target.value = e.target.value.toUpperCase();
this.fieldModelValue = e.target.value.toUpperCase();
this.$emit('listenChanges', this.fieldModelValue)
}
}
}
</script>
Demo CodeSandbox

Vue.js property undefined?

I've use this in my main component:
<contacts :corporation="corporation"></contacts>
contacts component:
export default {
props: {
corporation: {
default: () => []
}
},
data () {
return {
contacts: []
}
},
created() {
this.fetchContacts();
},
methods: {
fetchContacts() {
console.log(this.corporation.slug); // undefined!
CorporationService.users(this.corporation.slug)
.then(({data}) => {
this.contacts = data.contacts;
});
}
}
}
I'm trying to fetch contacts in the contacts component. The problem is that if I console.log(this.corporation.slug);in the method fetchContacts(); the corporation.slug is undefined!
But when I look into vue devtools the corporation prop is being set properly!
What could be going on? Already tried to change:
created() {
this.fetchContacts();
}
to
mounted() {
this.fetchContacts();
}
But that's not working.
Can you use a watch?
Something like this.
watch: {
'corporation.slug': function(slug) {
if(slug){
this.fetchContacts();
}
}
}
Now if parent component changes corporation.slug your child component will fetch contacts automatically.
Your prop default value is whether a value, or a function. But if it is a function, it HAS TO return something:
props: {
corporation: {
default () {
return []
}
}
},

Categories

Resources