Using v2.2.2. I have the following structure in my VueJS app. How can I access all of the Account components from a method on my Post component? The number of Accounts is dynamic - I want to grab all of the loaded Account components and iterate over them.
I know it's got something to do with $refs and $children, I just can't seem to figure out the right path.
<Root>
<Post>
<AccountSelector>
<Account ref="anAccount"></Account>
<Account ref="anAccount"></Account>
<Account ref="anAccount"></Account>
</AccountSelector>
</Post>
</Root>
https://v2.vuejs.org/v2/guide/components.html#Child-Component-Refs
Despite the existence of props and events, sometimes you might still need to directly access a child component in JavaScript. To achieve this you have to assign a reference ID to the child component using ref. For example:
<div id="parent">
<user-profile ref="profile"></user-profile>
</div>
var parent = new Vue({ el: '#parent' })
// access child component instance
var child = parent.$refs.profile
When ref is used together with v-for, the ref you get will be an array
or an object containing the child components mirroring the data
source.
Basically inside AccountSelector.vue you can do this.$refs.anAccount.map(account => doThingToAccount(account))
Edit
The above answer is for accessing a direct child.
Currently there is no way to access a non direct parent / child component with $refs. The best way to get access to their data would be through events https://v2.vuejs.org/v2/guide/components.html#Non-Parent-Child-Communication or by using Vuex (Which i would recommend).
Non direct parent - child communication is very tricky without 1 of these 2 methods.
You can access nested components data using $refs and if you want to access the refs inside of it you first have to target the first element of the first refs ([0])
example: parent.$refs[0].$refs.anAccount
Related
I'm Vue beginner and have tried setting up a simple app that takes in some user input to display a result on an extra page / component.
Component A has 2 sliders. I'd like to pass both values to Component C. Currently only one value is passed.
I spent hours on this and have already received super valuable support on another question by #RoboKozo, but this keeps me from progressing any further.
Please find my current code here.
Bind both props, and emits
<component
:is="selectedComponent"
:modelValue="value"
:modelValue2="value2"
#update:modelValue="value = $event"
#update2:modelValue2="value2 = $event"
>
</component>
The event name for updating the model value of modelValue2 should be update:modelValue2 (not update2:modelValue2):
// ComponentC.vue
this.$emit('update:modelValue2', this.local2)
Then to bind component.modelValue2 to App.value2, specify modelValue2 as the v-model binding argument:
<component v-model="value" v-model:modelValue2="value2">
Note you don't need to specify the binding argument for modelValue because that's the default.
demo
I am using a v-for over a custom component and passing the item as a prop. But the issue is that each component instance in the loop takes the same item prop. For e.g in the 1st loop a component field has text "abc", then the second looped component also will have the same "abc" text. If I change the text in the 2nd one, it changes in the 1st component too. Is there a way to make the prop unique for each loop ?
For e.g this is the code which calls the inner component:
<template v-for="(businesscase, index) in businessCase.fields">
<custom-case-freetext-field #field-changed="updateFields"
:key="index"
#field-removed="removeFields"
:fields="businessCase.fields"
:index="index">
</custom-case-freetext-field>
</template>
and inside this component I have a basic form
<sw-field :label="$tc('rma.modules.case.freetext.nameLabel')"
:placeholder="$tc('rma.modules.case.freetext.nameLabel')"
required
v-model="fields[index].name">
</sw-field>
<sw-single-select
labelValue="label"
valueProperty="label"
:options="fieldTypes"
:label="$tc('rma.modules.case.freetext.fieldType')"
:placeholder="$tc('rma.modules.case.freetext.fieldType')"
v-model="fields[index].type"
#input="changeType"
required>
</sw-single-select>
If I do :value instead of v-model, the entered value disappears as soon as the element loses focus.
If I use v-model, the data stays there, but then both (or as many are there in the loop) component instances, have data binding between them, so it defeats the purpose of having a loop for multiple components. As seen in the screenshot, I am typing in the 2nd component, but it changes the text for the first one too.
In the above example I am sending the whole array as prop, but I have also tried with individual field element instead of fields
Your are not using the businesscase variable inside your components. And since every component always works on the upper scope property, they will all change the same. Use the innerscope property. If you have problems with reactivity, because you try to mutate props directly work with events emitting the key and the changed value to the upperscope component.
i have a component A which wraps the component B using slot
component-A declaration
<component-A>
<slot></slot>
</component-A>
component-B Usage:
<component-A :some-prop="foo">
<component-B></component-B>
</component-A>
when i pass this prop (someProp) to component-A, is there any way to access it in component-B?
if you want to share information between the father and whatever have in your slot, Vue offers a slot props propertie, something like this:
<slot name="icon-order" :someProp="some-prop" :someProp2="some-prop2">
Once you inject something on component slot, you'll be able to access that propertie like:
<component-A :some-prop="foo">
<component-B slot-scope="slotProps"></component-B>
</component-A>
Then, inside component-B you'll have access to slotProps with every declared propertie set on component-A, just use: slotProps.someProp or slotProps.someProp2.
You can have a better look at Vue documentation:
https://v2.vuejs.org/v2/guide/components-slots.html#Scoped-Slots
hope that helps
If component-B needs to be passed some data, then it must receive it through a prop.
What you're asking is for component-B to also receive foo; just pass it via a prop in the same way you did for component-A, the slotting here makes no difference.
<component-A :some-prop="foo">
<component-B :some-prop="foo"></component-B>
</component-A>
However I suspect this isn't exactly your issue; if not please clarify how the slotting here is relevant.
I have a parent form that loads child forms into tabs.
The parent looks like this:
<div repeat.for="app of Apps">
<compose if.bind='app.Url.startsWith("modules/")' view-model="${app.Url}"></compose>
</div>
So each of the "compose" tags loads a different page based on URL.
How can I find the specific page and call a function from that page's ts file?
I have a temporary solution in place by, on the parent, declaring a variable with:
childPage: any;
and then on the activate event of the child, I do:
parent.childPage = this;
Then, on the parent page, I have can do:childPage.childFunction();
This of course doesn't give me intellisense and won't work with multiple children, but for now, it meets my needs.
I have a 'Builder' component and I am passing a variable named 'formula' to that component, but the changes made in this variable in 'Builder' component do not get updated in current component.
<builder :formula="formula"
:columns="columns"
:result_type="result_type">
</builder>
When I submit form the value for the 'formula' variable is same.
try this
<builder :formula.sync="formula"
:columns="columns"
:result_type="result_type">
</builder>
As in VueJS 2 .sync - 2 way binding has been deprecated, you have to handle it differently. https://v2.vuejs.org/v2/guide/migration.html#once-and-sync-Modifiers-on-v-bind-removed
You have to emit events like this.$emit('formulaChange', formula) etc. and listen to them in parent component with #formulaChange=yourHandler(formula)