Custom vue directive (like v-model) for using getter/setter without computed property [duplicate] - vue.js

This question already has answers here:
Pass data to a directive?
(2 answers)
Closed 1 year ago.
I am creating a component system that will let other developers write vue applications with the components to quickly get up and running with simple forms.
My components are very general, and expect plain values to be bound to their value property, and will emit plain values with their input events.
The data we want the components to control is complex. I've read that you cannot use classes as vue data, because vue expects plain javascript objects for data. So each piece of data is an object like
{
_value: ...
setVal(): ...
getVal(): ...
}
And we are binding like
<my-component
:value="dataObject.getVal()"
#input="dataObject.setVal($event)"
/>
I thought it might be possible to write a vue directive to shorthand those properties, like how v-model is a shorthand for :value and #input normally, so that I could write
<my-component v-my-directive="dataObject" />
and it automatically binds the right thing to :value and the right thing to #input, but it doesn't seem to be that simple. I've found tutorials that mention twoway for Vue v1 directives, but that was removed in Vue v2, which recommended using a wrapper component as a replacement. But we have a large library of components, writing and maintaining a wrapper for each one seems out of line for just creating a shorthand like what already exists. Is there any other way?

vue2 only allows v-model directive to be bound to :value/#input. So you need to use both v-bind and #on directives for 2 way binding.
vue3 combines these using a convention that allows for multiple v-model bindings
You create a prop called 'foo' and emit and event called 'update:foo' with the value you want to assign to it.
The parent component uses v-model:foo to bind to it.

Related

What means the "element-update" in Shopware 6?

I try to learn how i can create custom element for Shopware 6
although I cannot understand why we have to use the methods:
this.$emit('element-update', this.element);
in all SW Blocks?
All CMS element components should use the cms-element mixin. The mixin has a model for the property element which is bound to the element-update event. By emitting this event with the value you update the property, as if you were using a child component with the form input binding v-model. Since mutating props directly is considered an anti-pattern, this is a way to properly update it.

Vue - Is it better to keep all props in one large mixin

I have a component library where i would like to standardize the props, component etc.
Thoughts on combining them props/methods/other mixins/etx into one larger mixin
All property names would be the same
Remove duplicated code on refactoring to adjust components from local props/methods/computed/ to "global"
Not all components would have need for every piece of data contained within the mixin - point 4
Would tree shaking remove the unused code on Rollup?
Is this a good idea?
If your component library is not constrained to using Vue 2 you might want to take a look at Vue Composition API to share functionality (methods + reactive state) between different components.
Mixins might not be what you really want to be using because you kind of lose information as to what features/props/methods really will be put inside your component without re-checking the mixin code. You also might run into issues when component options get merged by Vue at runtime. Check out these posts for more information:
https://css-tricks.com/how-the-vue-composition-api-replaces-vue-mixins/
https://reactjs.org/blog/2016/07/13/mixins-considered-harmful.html
As for sharing props: What I've seen just yesterday (but not yet tried!) in a talk by John Leider - creator of Vuetify - is create a function that returns the props you want to reuse between components. Then you just call said function inside your props definition and use the spread operator.

Angular update parent data from child component

Yes, this old chestnut.
I'm making an editor for a large object tree, and it seemed sensible to make components for each of the property types at a vertex in the tree in order to remove clutter from the main component. However, this has created the problem that the main JSON object isn't being updated beause the editor is implemented in child components (#Input).
Using #Output and EventEmitter seems infeasible because:
how on earth do you get a component to call the emitter very time a change is made to the data it's editing, and
it seems really stupid to have to write an update function to handle the event because the UI should be just automatically bound to the JSON object it's editing -- that's the point of this observable malarkey.
The only solution I can think of is to not use components and just wirte a massive monolithic editor.
Is there a better way?
The way you describe is pretty standard. An alternative though would be to use a template # variable to access your child properties.
<hello #childcomponent name="{{ name }}"></hello>
<div>
{{ childcomponent.name }} - Parent component
</div>
You can use this to access your child component through the typescript as well.
#ViewChild('childcomponent') childcomponent;
Stackblitz

Using Intertiajs with Element UI

I am using Inertiajs
with Laravel and also trying to use Element UI components but as i use Menu component i am having following error in console, I just used example as given in Element Ui Components as i was testing.
I see 2 different errors in there, both of them are with props.
I assume your component is taking the route as a prop, and you are also using the route as a method, which you might have put inside methods: {} which is not allowed. Make sure you rename your method route to something else.
Note: As a matter of fact you can't have any data coinciding with each other. your props, data, computed props and methods all should have unique names.
You are trying to use v-model on the props directly which won't work in Vue. if the prop is a primitive (Number, String, Boolean etc). but you can pass Object or an Array which can hold a reference to the data. This is because reactivity in Vue can't keep track of props when passed as primitives.
More on prop mutations here: https://v2.vuejs.org/v2/guide/components-props.html#One-Way-Data-Flow

setting model values from a vuejs 2.0 directive

I'm using a Vue 2.0 directive to apply a Twitter Typeahead to the input. I've been able to get it to apply the value back to the Vue model in a way that feels like a bit of a hack, by looping through the context, finding the parent object and calling my method setAutocmpleteValue()
HTML setup for Vue Custom Directive
<input class="typeahead" type="text" placeholder="Search" name='typeahead'
v-typeahead="getFieldValues(part.fieldName)"
v-model="part.value" v-bind:value="part.value"
v-on:change="updateTest()" #input="onValidChange()" />
Custom Directive
Vue.directive('typeahead', {
inserted: function(el_, binding,v) {
// this feels like a hack, is there a better way?
v.context._self.parent.setAutocmpleteValue('test');
}
})
Within a directive $emit is not available to pass an event, is there a better way to call setAutocmpleteValue()?
In Vue 2, directives are intended for DOM manipulation.
Note that in Vue 2.0, the primary form of code reuse and abstraction
is components - however there may be cases where you just need some
low-level DOM access on plain elements, and this is where custom
directives would still be useful.
They are not intended for setting data values and attempts to do so will rely on hacks like you are using.
Not only that, but this is a very fragile approach. The directive in the question is dependent on a method in the parent of the current context. What if the input element was two levels down or more?
You're much better off implementing a component.
However, given you are already hacking, $emit is available from the context.
v.context.$emit("some-event", someData)
The context is the Vue or Vue component containing the element to which you have attached the directive, so you would want to listen to it from the parent of that component.