Access vue components passed via a slot Vue 3 - vue.js

Problem desription
I am trying to access Vue child components passed in a slot.
I do it with the following approach:
this.$slots.default()
I receive the components and I can even access and call methods of a component using the following approach:
this.$slots.default()[1].type.methods.methodName
The problem is that within the child component this keyword has now changed to another type where you can only access methods defined in that component and restricted variables. And so for example you can't access this.$refs (which I actually need) or this.$el or anything else except defined methods and some variables.
What I've tried
I've tried assigning this.$refs to a variable within the onmount function and then trying to access it when calling a method from the parent component, but you can't access that variable.
In Vue2 you have full access to the child component and this would work.
Is there a way to fix it in Vue3?

Related

What happens if I don't pass a ref to a RN component using forwardRef?

I have a subcomponent using forwardRef to get a ref from the parent component, however, I'm curious as to what happens if I didn't pass in a ref from the parent component. I tested other parent components that are also using this subcomponent, but aren't passing in a ref and they seem to work perfectly fine. Help is appreciated!
The reason why forwardRef is implemented is to have access to some functions or state properties of that subcomponent. If you do not pass that ref to it, you simply cannot access those from your parent component; most likely where the ref is not passed, there are not used any functions/state properties of the subcomponent, that's why it works fine. (If you take a look at the time when classes were used instead of functional components, you'd see that the ref was a property present to each class by default. However, it is not recommended to use forwardRef (only if it's an overhead to do otherwise), as they also say in the documentation, since it is an anti pattern)

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

vue2 get component instance from selector?

I've some dynamic (v-for) non-parent-child component and I'd like to access their methods from a non-parent parent, I know about events and ref, but wondering if there's a way to access component instances from a given selector (found nothing about in the documentation).

Vue.js 2.0 - creating reusable components

I am trying to create fully reusable component using Vue.js 2 and single file components, and right now my approach seems to be impossible to realize.
The goal is to create component for creating forms for a complex, nested JSON structure. This structure is supposed to be edited and then sent to the server. The component itself displays a header and submit button but the fields along with their placing is entirely the responsibility of the user of my component. (front-end engineer)
The MyForm component (implementation is not relevant here) is passed the JSON data and url to post them to.
The form is supposed to be reusable by many other users and the contents of the form itself is supposed to be not relevant. It may have a mix of html/inputs/custom components as children.
Let's imagine a simple scenario without data nesting with the following data:
var mymodel={ name : "My name", surname : "My surname" }
And a form i would like to create using my component:
<MyForm :model="mymodel" :url="http://localhost/post">
<div>
<MyTextInput v-model="model.name" label="Name"/>
<MyPanel>
<MyTextInput v-model="model.surname" label="Surname"/>
</MyPanel>
</div>
</MyForm>
Therefore:
MyForm gets passed a model to submit, stores it in data
MyTextInput is a custom component for displaying input with label
Second MyTextInput is the same component but created in another component contained called 'MyPanel' since this field needs to be placed differently.
As we can see there are many problems with passing variables and composition itself:
Composition:
If i put a <slot></slot> in the tempplate of MyForm for displaying the fields it would be compiled in parent scope, therefore all children (including MyTextField) would not have access to the "model"
If i try to use <MyForm inline-template> i cannot automatically display the form header and footer since all content is being replaced. Additionally when using single file components the compiler will look for all components inside the inline-template which means that i would have to import MyTextInput and MyPanel into MyForm which is not practical. I do not know in advance all components that will never end up in my form!
Passing variables:
If i use the variables directly from "model" (in first TextInput) i receive warning that i am modifying a variable from parent and it will be overwritten on next render (but in this case it will not be overwritten since i am INTENTIONALLY modifying the parent)
I cannot pass the model into second MyTextInput without passing it to MyPanel first. Actually i would have to pass it into EVERY custom component in between. And i do not know in advance how many custom components will there be. Which means that i would have to modify the code of every component that would ever be put into MyForm and require users to pass the data for each custom component they include.
If i would try to properly inform the parent about changes i would need to add v-on: event to every textinput and every custom component in between in order for the event to reach MyForm.
As i have said the component was supposed to be simple and easilly reusable. Requiring users of this component to modify code of every child they put into it and requiring them to add v-on: to every component inside does not seem practical.
Is my idea solvable using Vue.js 2.0 ? I have designed the same component before for AngularJS (1.5) and it was working fine and did not require to add modifications to each child of the form.
I've been using a ui framework based on vue 2.0 and you may get some ideas from its implementation. Based on its implementaion and my little experience with it, I think it's the person who uses your framework's responsibility to assemble the form-model. Also, for a form, we can always easily get all the data to be sent by using fields' value props without v-model's help.
The framework's doc on form element may also be helpful but it's currently only available in Chinese except for the code samples.
I suggest you to use Form Input Components using Custom Events to pass variables in your form.
Mutating a prop locally is now considered an anti-pattern, e.g.
declaring a prop a and then set this.a = someOtherValue in the
component. Due to the new rendering mechanism, whenever the parent
component re-renders, the child component's local changes will be
overwritten. In general, in 2.0 you should treat props as immutable.
Most use cases of mutating a prop can be replaced by either a data
property or a computed property.

Mutations using Relay Environment

I'm using Relay with React Native and have a problem during login & logout.
After login or logout, Relay keeps the store from the previous user. To solve this I use Relay.Renderer and Relay.Environment. As in, in each Renderer I put singleton object of Environment.
The problem is that I previously did a mutation on object of Relay.Store, as in
Relay.Store.commitUpdate(new CreateProfile(), callback).
Now it doesn't work. I guess this is because Relay.Store doesn't know anything about server endpoints. But Relay.Environment does.
And now I'm using something like this this.props.relay.commitUpdate(new CreateProfile(), callback). It works pretty well when the parent component is wrapped as Relay.Container, so it has relay object in props.
But what should I do in components which are not Relay.Containers and don't have Relay object in props?
Relay.Store is a globally accessible singleton instance of Relay.Environment and Relay.Store.commitUpdate() updates data in that global environment. But since you're using your own instance of Relay.Environment, to update it you need to use this.props.relay.commitUpdate(), as you noted. This updates the environment the container was rendered with.
If need to make mutations from child components of containers, that are not wrapped in a Relay.Container, there are two ways to do that. You could simply pass the relay prop to them, so in the render function of your container you would have:
<Child relay={this.props.relay} />
However, since those plain components are not in a Relay container, they don't currently need to know anything about Relay. If you want to keep them that way, you could write the method that does the update in your container component like this:
onCreateProfile = () => {
this.props.relay.commitUpdate(new CreateProfile());
};
and only pass a callback to your child component in render:
<Child onCreateProfile={this.onCreateProfile} />
If you need to make a mutation from a component that does not have a Relay.Container above it in the component hierarchy at all, you could create the Relay.Environment in a shared root component higher up and pass it down using props (or pass a callback using the strategy shown above).