How dynamic & async component in VueJS receive its props? - vue.js

While reading the excellent documentation of VueJS, I didn't understand how dynamic async component can get its props from its outer component.
Is that possible? How?
They do have a great example here.
What if my component has props like "something" need to be passes and render:
<component :is="my-component"></component>
Vue.component('my-component', {
template: '<div>{{something}}</div>',
props: { something: String }
})
Doing something like this will not work:
<component :is="my-component" :something="'text'"></component>
:something is specific name of prop, but the component not always known, so its props are also not known. This is the senario why using so it can by any component.

Related

Dynamic component inside a component that is rendered with render() function

I saw in the docs that you can have a dynamic component inside your VueComponent like this :
<component :is="componentName" v-bind="componentProps" #custom-event="doSomething" />
I am trying to have one of these dynamic components inside a dynamically rendered component (with the render() function, not with an HTML template). Without too much hope, I've tried this :
render(createElement: CreateElement) {
return createElement('component', props: {
'is': 'TestComponent'
});
}
but I got
[Vue warn]: Unknown custom element: <component> - did you register the component correctly?
So again, not hoping too much for a miracle, I tried to import Component and declare it as a component :
#Component({
components: {
Component,
TestComponent
}
})
export default class DynamicThingy extends Vue {
render(createElement: CreateElement): VNode {
return createElement('Component', {
props: {
'is': 'TestComponent'
}
});
}
}
But then I get
[Vue warn]: Do not use built-in or reserved HTML elements as component id: Component
Any idea how that could be possible ?
The first parameter of createElement() must be either
An HTML tag name,
component options,
or async function resolving to one of these.
https://v2.vuejs.org/v2/guide/render-function.html#createElement-Arguments
So in a render function, you can simply create a function* that returns one or another component's options based on your desired criteria, and let that be your first argument. *This function is identical to the function you'd write to determine what goes into the :is prop)
You only need the dynamic component <component /> and :is prop in a template where you don't have the possibility to do it programmatically.
You can use this smart-list component from the vue docs as an example.

vuejs - Async AND Dynamic component

What I want to achive is to combine vuejs's "Async Components" and its "Dynamic Components" (https://v2.vuejs.org/v2/guide/components-dynamic-async.html) to get a flexible way of using dynamic components.
Let's say, I have the following component:
<template>
<div>
some stuff..
<component :is="type"></component>
some stuff...
</div>
</template>
<script>
export default {
name: "mycomponent",
props: {
type: {}
}
}
</script>
I would use it like so:
<mycomponent type="myinput"></mycomponent>
To make it work, I would need to load the myinput component in the mycomponent and I will do it aync:
components: {
MyInput: () => import("./myinput")
}
That works!
The problem now is, that I want to make it dynamic and use it like so:
<mycomponent type="myinput"></mycomponent>
<mycomponent type="myselect"></mycomponent>
<mycomponent type="mytextarea"></mycomponent>
...
To get this up and running, I would need to import all of this components in the mycomponent, which is obviously not an good idea. Global import is as well, not the way to go.
This was just an example, but the real use case for this is getting an array of type's from an api and dynamically render a form with it.
So I have came up with I idea what I could not try yet.
Lets say you have a component for different types of inputs for the sake of simplicity you name them all with an 'Input' prefix.
As long as everyone follows the naming rules you can register all of these component globally.
For example in a BaseInputs.js
const components = require.context(path, subfolder, regexForInputComponentFileNames)
https://webpack.js.org/guides/dependency-management/#require-context
components.keys().forEach(element => {
const componentName = element.replace(/*Everything that is not the component name like .vue*/)
Vue.component(componentName, () => import(path + componentName)
})
Then you just import 'path/to/BaseInputs' at the beginning of your application.

Pass change to child components when data value in parent component is changed in vuejs

I want to pass down the changes made in parent component data values to its child components each time the value changes in parent how can i achieve it in vue.js. I am using 3 custom components that have to reflect the current value of the parent component each time. p.s i am new to vue.js
you just need to pass it as a prop. In your template:
<my-component :my-prop="myData" />
and in your script tag:
export default {
data() {
myData: 0,
}
}
Whenever you update this.data, the component will update its view, as the prop will have changed
Data is typically passed one-way from parent to child components via props. See the documentation on this here.
Example:
// register the child component
Vue.component('child', {
props: ['myProp'],
template: '<span>{{ myProp }}</span>'
})
// in parent component
<child :my-prop="hello"></child>

How to create a reusable component in VueJs?

I would like to create Side Panel as a reusable component in Framework7 with VueJS. Here is my code..
Card.vue
<f7-card>
<f7-card-header>Card header content</f7-card-header>
<f7-card-content><img src="https://wiki.videolan.org/images/Ubuntu-logo.png"></img></f7-card-content>
<f7-card-footer>Card footer content</f7-card-footer>
</f7-card>
Now i registered as a component like below,
import Vue from 'vue'
export default [
{
path: '/card/',
component: require('./Card')
},
]
In later vues i imported as,
import Card from './Card.vue'
and i try to access in another vues like,
Now i'm getting an error like
[Vue warn]: Unknown custom element: - did you register the
component correctly? For recursive components, make sure to provide
the "name" option.
Can anyone help me where have i mistaken?
Thanks,
It's not really clear from your code exactly what you are doing, but the error you are getting happens when you try to use a component as a child of another component without registering it in the parent's components setting like this:
<script>
import Card from './Card.vue'
export default {
data () {
return {
somedata: 'some value'
}
},
components: {Card: Card}, // <- you're missing this
// etc...
}
</script>
You can also register components globally. More here: https://v2.vuejs.org/v2/guide/components.html#Local-Registration
Are you showing us all of Card.vue? For a valid single-file vue component, I would expect to see <template>, <script> and <style> elements. The render function will be generated from whatever you put in the <template> element.
Make sure that the component that you want to reuse is wrapped inside a template tag
As follows
<template>
<div>
<component data/>
<div/>
<template/>
Then register it inside the parent
Like so
export default {
name: "Card",
components: {
Card
},
};

$refs is undefined when window.addEventListener('focus') is being fired

<template>
<div>
<input ref='commandLine' />
</div>
</template>
<script>
export default {
mounted () {
window.addEventListener('focus', this.pageFocused)
},
methods: {
pageFocused: () => {
console.log('pageFocused')
console.log(this)
this.$refs.commandLine.focus()
}
}
}
</script>
I want to set focus on commandLine input every time user get into my app. Unfortunately, when I try to use $refs in order to find my <input> object, it's null.
I suspect that it's because window.addEventListerer puts my function into different context, so this variable doesn't represent my component.
What is a clean way to solve it?
Do not define methods with arrow functions. In arrow functions this is bound lexically and will not point to the Vue.
methods: {
pageFocused(){
console.log('pageFocused')
console.log(this)
this.$refs.commandLine.focus()
}
}
See VueJS: why is “this” undefined?
I suspect that it's because window.addEventListerer puts my function
into different context, so this variable doesn't represent my
component.
Vue binds methods to the Vue object, so that particular code will work typically. You cannot however, bind an arrow function. Thus, your issue.