how to pass a property from parent template to slot in vuejs - vue.js

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.

Related

Vue: Event does not emit several values. Is there something wrong with v-model?

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

How does a single file component pass context.data?

I loop functional components in the transition-group, and because I didn't pass a key reference to the root element of the tag component to the tag component.
But how does a single file component pass the context.data?
The sample link
https://codesandbox.io/s/rjjmpvwm4n/
https://github.com/vuejs/vue/issues/7777
The <tag> component needs a key to use as its child <span>'s id.
Since <tag> is a functional component, you will have to access to the data via the data. prefix.
So, since you are using <tag v-for="item in list" :key="item"></tag>, inside the <tag>'s template, you can access the key (of context.data) automatically using data.key:
Add :key="data.key" in tag.vue:
<template functional>
<span :key="data.key">tag content</span>
</template>
Demo CodeSandbox: https://codesandbox.io/s/wxmvxnojl?module=%2Fsrc%2Fcomponents%2Ftag.vue

Keep list components alive in Vue

I have a list of components that I render using v-for. Not all the components are shown simultaneously. I page the the array of rendered components by using slice.
These components shouldn't be rerendered, as some of them have user inputted data and some of them do network related tasks.
I tried to use <keep-alive>. However, this renders only the first component.
<keep-alive>
<component :is="component.type" :key="component.id" v-for="component in components">
</keep-alive>
How do I keep a dynamic list of components alive?
<div v-for="comp in compList" :key="'container'+comp.keyId" >
<keep-alive>
<component :is="comp.type" :key="comp.keyId"></component>
</keep-alive>
</div>
this above works for me . Pushing elements to compList correctly creates new instances of their respective components. Moving an element's index within the array , maintaining key, does not call destroy/create and maintains state within each component
Tested the answer above in a fiddle and doesn't work. https://jsfiddle.net/z11fe07p/680/
<div v-for="component in myComponents" :key="component.id" >
<keep-alive>
<component :is="component.type"
:name="component.name">
</component>
</keep-alive>
</div>
Also i would avoid using vue reserved words such as components because there is a components key in the vue instance which tells what components the instance is using.
I read source code of Vue's <keep-alive>, and I created new Component which works very well with list.
package name is vue-keep-alive-global. Here is a link, https://www.npmjs.com/package/vue-keep-alive-global
How to use :
<KeepAliveGlobal>
<YourComponent
:key="uniqueKey"
/>
</KeepAliveGlobal>
With Array,
<template v-for="(item, index) of array">
<KeepAliveGlobal :key="`blah-blah-${index}`">
<YourComponent
:item="item"
:key="`your-component-${index}`"
/>
</KeepAliveGlobal>
</template>
KeepAliveGlobal will cache component by key.
There's note at Vue docs about your use case
Note, <keep-alive> is designed for the case where it has one direct
child component that is being toggled. It does not work if you have
v-for inside it. When there are multiple conditional children, as
above, ` requires that only one child is rendered at a
time.
https://v2.vuejs.org/v2/api/#keep-alive
Try v-once directive instead.
https://v2.vuejs.org/v2/api/#v-once

Vue.js - 2 way binding not working. Data is not updating when changed in a component

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)

How to set default value for bindable properties in Aurelia HTML only element

Supposed I have the following html only element:
<template bindable='value: Math.random()'>
${value}
</template>
<!-- In another component {Main} -->
<template>
<require from='./that-element'></require>
<that-element></that-element>
</template>
The result is an empty string in main component. The question is how can I define a default value for html only element?
EDIT: Default value for element will not work if an 2 bindings need to have the same unique default value. I can make it unique myself but then I have to do it manually. Was looking for something like Math.random()
The contents of bindable attribute on <template> tag is handled as comma-separated list of strings. Therefore, you won't be able to set default values there.
I can think of two approaches:
Set default values in parent viewmodel class and use explicit binding. Considering above scenario, this will work for you.
<that-element value.bind="someVarFromParent"></that-element>
In some really simple cases, when default value should be a static string, you can use JavaScript expressions within an interpolation.
${value || 'default value'}
Gist demo: https://gist.run/?id=f0698d5b0066c3674c29c40d850217dc
Just putting my 2 cents in here...I think Marton nailed it on the head with the html only solution. I generally use the value.bind method because I usually always have a vm along with my view. So, to simplify JayDi's response (which is a valid response), I've created a GistRun for you.
Basically, you'll create a custom-elem html file and a custom-elem js file. In the html file, you would have something like this:
<template>
<h1>${value}</h1>
</template>
and in the js file, you'd have something like this:
import {bindable} from "aurelia-framework";
export class CustomElem {
#bindable value = "default value";
}
Finally, you'd just require it in your main parent file like so:
<template>
<require from="./custom-elem"></require>
<custom-elem></custom-elem>
<custom-elem value.bind="'myVal'"></custom-elem>
</template>
I just added a default value for the custom element. You can leave it undefined if you'd like. Also, you can add as many properties as you would like. This is the simplest way to tackle this in my opinion, unless your situation lets you get by with the html only method.
Also, in this case, I'm using a string of "myVal". If you wanted to use a variable that you have in your parent vm, you would just take the single quotes off and use that variable name.
Here's the running Gist so that you can fool around with it:
https://gist.run/?id=2eb14ecd2b0b859fd5d1a33b5ee229bd
You can use || statement in html-only element for default value:
<template bindable="param1, param2, param3">
<h1>${param1 || 'default 1'}</h1>
<h2>${param2 || 'default 2'}</h2>
<h3>${param3 || 'default 3'}</h3>
</template>