Vue, change native event not working, input native does - vue.js

I have a question and maybe a Vue bugg.
I have a custom component that needs a #change.native event. But it does not trigger anything and I could not find anything about this issue myself.
So i tried some different stuff and like #click.native and #input.native does work. Even tho #input.native works and do the trick i want to, i still want to know why the change event does not work.
Anybody? Else I should report this.
Vue version: 2.5.2
<custom-input type="search"
placeholder="search"
v-model="search"
#input.native="change" />

If the <input /> inside the custom component is a child element of another element, then the event listener bound by the .native modifier will not be reached, since it is listening to the event of a different element.
custom-input.vue:
<template>
<div>
<input :value="someValue" />
</div>
</template>
<script>
export default {
props: ['value']
}
</script>
so if you have this scenario, then the #change.native will be bound on the <div> (the wrapper).
(sadly) You need to manually propagate the event manually.

Related

Vuetify custom v-text-field component is not updating the v-model

I’m following this documentation: https://v2.vuejs.org/v2/guide/components.html
I created custom v-text-field component which looks like that:
<template>
<div>
<v-text-field
:label="label"
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"></v-text-field>
</div>
</template>
<script>
export default {
name: "txtbox",
props: ['value', 'label'],
}
</script>
I implemented it in my main component almost succesfully:
<txtbox
label="Name"
v-model="eventName"
/>
I don’t think it is necessary to paste all the code, but if it is I will edit the post. Here is how it works:
I have a list, when i click on the list element the text-field displays content of it, this works fine. Sadly when I’m editing the content of text-field the v-model value is not updating. I can also add that it works fine with normal (like in the docs) instead of . Is there anything I can do to make it work, or should i use simple input ?
Thanks
When you want to $emit the new value, you just have to emit the $event, and not $event.target.value
<template>
<div>
<v-text-field
:label="label"
v-bind:value="value"
v-on:input="$emit('input', $event)"></v-text-field>
</div>
</template>
v-on:input can also be shortened to just #input

vue emit data back to parent when using a slot

I have input on custom component and when i click on the next button on the wrapper component i need to emit details to the parent component.
How is this possible in vue?
wrapper.vue
<template>
<div :id="contentId" class="mt-3">
<div>
<slot></slot>
</div>
<b-row class="float-right">
<b-col>
<button cssClass="e-outline" v-on:click="btnNext">{{nextButtonText}}</button>
</b-col>
</b-row>
</div>
</template>
parent.vue
<template>
<div>
<Wrapper contentId="1">
<CustomComponent1 />
</wrapper>
<Wrapper contentId="2">
<CustomComponent1 />
</wrapper>
</div>
</template>
customComponent1.vue
<template>
<div>
<input v-model="name" />
<input v-model="name2" />
</div>
</template>
code above is for illustrative purposes.
The problem is that the wrapper doesn't innately have access to data of the scoped component, therefore these links have to be created manually. There is no way to tell how many children or slots the component may have, so this kind of functionality is not part of the vue magic.
So in an example where you have parent App component, which holds a Wrapper that has a MyInput component in the slot...
MyInput
The MyInout component doesn't automatically update other components, so it needs to be setup to $emit the internal data.
This can be done using a watch, #change listener for the input, or some other way. You can emit multiple datum as they change, or use a single payload with all the data
this.$emit("input", myData);
App
The App needs to explicitly connect the data between MyInout and Wrapper
<Wrapper> <MyInput #input="onInput" slot-scope="{ onInput }" /> </Wrapper>
The magic/trick happens here, where we bind the input emit function of the input to the onInput function using slot-scope.
Wrapper
The wrapper then needs to listen to the events passed (via App) from Wrapper
<slot :onInput="onInput" />
where onInput is a method that would process the data
see example below
I would recommend the following reading
https://github.com/vuejs/vue/issues/4332 (specifically Evan's response why it's not possible)
https://adamwathan.me/renderless-components-in-vuejs/ Adam has a thoroughly documented way of using render functions and slots to abstract functionality from the UI. While it's not directly related, it's a worthwhile read and may provide more info on using slot-scope as well as some perspective on improving the structure of UI components.

What is the best "decoupled" way to give focus to an Aurelia component?

Let's say I've built some kind of Aurelia component. For this example, let's say I've built a hypothetical component called ui-money.
Let's say that the ui-money component comprises a text input element, and another element (eg. span) alongside the input that shows an exchange rate. In essence, something like:
<template>
<input value.bind="amountStr" ... >
<span>${exchange_rate}</span>
</template>
I then build an Aurelia view (page) which includes the <ui-money> element.
My question is this: let's say I want to put focus onto the "ui-money" element.
Practically speaking, I don't want to know the internal makeup of the ui-money element (white-box knowledge), nor should I want it. But clearly I need the focus to go to the INPUT element WITHIN the ui-money element.
So, it would seem that I need to ask the ui-money element to perform the act of setting focus, for me.
Now the most obvious first option would be to supply a ref to the ui-money element as such <ui-money ref="purchasePriceUx"> and have the ui-money view-model expose some kind of takeFocus() method. We could then invoke
purchasePriceUx.takeFocus().
But I'm interesting in knowing if there is a better way to achieve this, whilst still retaining the same level of decoupling.
You can use bindable properties and the focus attribute that ships with the standard configuration of the framework: https://gist.run/?id=7587f1453cb2632fa09b6fe542d9717c
The important stuff is here:
app.html
<template>
<require from="./some-element"></require>
<label for="hasFocus">Has Focus:</label>
<input id="hasFocus" type="checkbox" checked.bind="focus" />
<div>
Custom Element:
<some-element has-focus.bind="focus" text.bind="text"></some-element>
</div>
<div>
Regular text box:
<input type="text" value.bind="text" />
</div>
</template>
some-element.html
<template>
<input ref="textbox" type="text" value.bind="text" focus.bind="hasFocus" />
</template>
some-element.js
import {bindable, bindingMode} from 'aurelia-framework';
export class SomeElement {
#bindable({ defaultBindingMode: bindingMode.twoWay }) text;
// the bound property cannot be named focus as it interferes with
// the focus custom attribute
#bindable({ defaultBindingMode: bindingMode.twoWay }) hasFocus;
}

v-on:change does not work for vue-multiselect

I am using vue-multiselect component in my vue.js project, I am using v-on directive to execute a function on the change event ,
<multiselect v-model="selected" :options="projects" :searchable="false" :custom-label="customLabel" track-by="name" v-on:change="executeLoader">
<template slot="customLabel" slot-scope="{ customLabel }"><strong>{{ option.name }}</strong></template>
</multiselect>
I have example full code here: https://codesandbox.io/s/yjjon0vzxj
the v-on:change was working with <select> component but it stopped workigng with vue-multiselect ! I tried with v-on:click="executeLoader" but that too didnt worked either..
#click will not trigger the method executeLoader with vue multiselect. You can use #input - which is similar to v-on:change, #close, #select as in example below:
<multiselect placeholder="Pick at least one"
select-label="Enter doesn’t work here!"
:value="value"
:options="options"
:multiple="true"
:searchable="true"
:allow-empty="false"
:hide-selected="true"
:max-height="150"
:max="3"
:disabled="isDisabled"
:block-keys="['Tab', 'Enter']"
#input="onChange"
#close="onTouch"
#select="onSelect">
</multiselect>
In your case I would try #input="executeLoader"
In vue-multiselect, since it is a component you can't treat it to behave like a simple <select> element.
In components, when you expect them to behave and "listen" to click events just like other html tag, then you should add an event modifier called: .native.
So, you can do on any component:
<... #click.native="executeLoader" />
But that is not what you are looking for I think. You want to trigger a function when you add more and more tags, or in short: when the selected items increase.
for that, vue-multiselect exposes the #input event, so you can handle using:
<... #input="executeLoader" />
And now just call executeLoader and accept the arguments as:
methods: {
executeLoader(selectedItems) {}
}

Using $refs with Element UI's input component

Is it possible to use ref with el-input component from Element-UI? I am trying to use $refsto focus on the input when my Vue instance is mounted. Here is my code:
<div id="app">
<el-input type="text" ref="test" placeholder="enter text"></el-input>
</div>
And in my Vue instance:
new Vue({
el: "#app",
mounted(){
this.$refs.test.focus()
}
})
The focus method is not working at all, even if I move this.$refs.test.focus() into a method and try to trigger it through an event.
The $refs object stores Vue components and should be working fine. The problem is that you are attempting to invoke a focus method which doesn't exist in the component, but rather on an input somewhere inside the component's template.
So, to actually find the input you'd have to do something like this:
this.$refs.test.$el.getElementsByTagName('input')[0].focus();
Not the prettiest line of code ever made, right? So, instead of calling anything in your app's mounted method, if you want to autofocus on the input, just do this:
<el-input type="text" placeholder="enter text" autofocus></el-input>
This can be also solved your problem.
// Focus the component, but we have to wait
// so that it will be showing first.
this.$nextTick(() => {
this.$refs.inputText.focus();
});
Now you can use it like this
<div id="app">
<el-input type="text" ref="test" placeholder="enter text"></el-input>
</div>
this.$refs.test.focus();
https://element.eleme.io/#/en-US/component/input#input-methods