I currently have a Vue.js application in which I have used my own component. I want HTML DOM children components to be able know if they are contained in my component or just in the application itself. What would the best way to do it?
I tried it using props, but as it is all contained within another application that does not seem possible.
example: I want the si-button to be able to determine that it is contained in a si-dialog. How do I pass that information to the si-button?
<si-dialog ref="siDialogChildren" name="children">
<div>
<h1>Hello children dialog!</h1>
<p>Click outside the dialog to close this dialog.</p>
</div>
<si-button id="test" type="custom" :on-click="buttonPress">
Click
</si-button>
</si-dialog>
Yours sincerely,
Mirijam
You might want to use $parent as specified in the Vue documentation.
For example, you can get the name of the parent component by accessing to its "$options.name" property.
Example:
App.vue
<template>
<div id="app">
<ParentComponent>
<ChildComponent />
</ParentComponent>
</div>
</template>
<script>
import ParentComponent from './components/ParentComponent'
import ChildComponent from "./components/ChildComponent";
export default {
name: 'App',
components: {
ParentComponent,
ChildComponent
}
}
</script>
<style>
</style>
ParentComponent.vue
<template>
<div>
<p>I'm a parent component.</p>
<slot></slot>
</div>
</template>
<script>
export default {
name: "ParentComponent",
props: {},
computed: {}
};
</script>
<style scoped>
</style>
ChildComponent.vue
<template>
<div>
<p>Parent name: {{componentName}}</p>
<p>I'm inside a ParentComponent? {{componentName === "ParentComponent" ? "Yes!" : "No."}}</p>
</div>
</template>
<script>
export default {
name: "ChildComponent",
computed: {
componentName() {
// We get the parent name from the $options.name property of our parent
// component
return this.$parent.$options.name
}
}
};
</script>
<style scoped>
</style>
NOTE You can also access to other properties on the parent component by using the $parent property. Try it out!
Related
I am working on a Vue 3 app. I have run into a problem working with a <Navbar /> component and one of its sub-components.
In App.vue:
<template>
<Navbar />
<Content title="Home" />
<Footer />
</template>
<script>
import Navbar from './components/Navbar.vue'
import Content from './components/Content.vue'
import Footer from './components/Footer.vue'
export default {
name: 'App',
components: {
Navbar,
Content,
Footer
}
}
</script>
Within the Content.vue component, I can display the title this way:
<h1>{{ title }}</h1>
<script>
export default {
name: 'Content',
props: {
title: String
}
}
</script>
But displaying buttons with their labels by the same pattern as above does not work:
// Button.vue component
<template>
<button class="btn btn-sm btn-generate">
{{ label }}
</button>
</template>
<script>
export default {
name: 'Button',
props: {
label: String
}
}
</script>
// Navbar.vue component
<template>
<div class="navbar">
<Button label="Button 1" />
<Button label="Button 2" />
</div>
</template>
<script>
import Button from './Button'
export default {
name: 'Navbar',
components: {
Button
}
}
</script>
The problem
As a result of the code above, inside <div class="navbar"> there is only one button with no label, instead of 2 buttons labeled "Button 1" and "Button 2".
Where is my mistake?
I think that naming your component just as the already existing HTML element is not a good idea. Try changing it to MyButton and use <my-button>... in the navbar component (you still want to use <button> in MyButton, as you want to build upon it).
Most probably browser still picks just a default button instead of yours.
The first essential rule mentioned in Vue docs is Use multi-word component names.
You need to bind them so :label="button 1"
So in my App.vue component, I have two other components being rendered, and what I want to achieve is this, when the user clicks on the play button, animateRing() method from the component ProgressRing should be used, my code looks the following:
App.vue
<template>
<div id="app">
<ProgressRing>
<PlayButton
#click="animateRing(), active = !active"
:class="{active: active}"
/>
</ProgressRing>
</div>
</template>
PlayButton.vue
<template>
<button class="play-button" #click="$emit('click')">
...
some irrelevant code here
...
</button>
</template>
ProgressRing.vue
<template>
...some code...
</template>
<script>
export default {
methods: {
animateRing(){
console.log('I'm animated');
}
}
};
</script>
I can't seem to figure out the right way to do it. What is the best way to make the method to work in the App component? I'm relatively new to Vue and didn't really figure it out yet.
Here's one way you can accomplish this:
App.vue
<template>
<div id="app">
<ProgressRing ref="progressRing">
<PlayButton
#click="animateRing(), active = !active"
:class="{active: active}"
/>
</ProgressRing>
</div>
</template>
<script>
export default {
methods: {
animateRing(){
this.$refs.progressRing.animateRing()
}
}
};
</script>
I'm curious about the reason for PlayButton being a child of ProgressRing, but not defined in ProgressRing.vue.
I've got App.vue:
<template>
<div>
<p class="text">Hello World</p>
</div>
</template>
<script>
import ParentComponent from '../components/ParentComponent'
export default {
components: {
ParentComponent
}
}
</script>
And then I have ParentComponent:
<template>
<div>
<p class="text">Hello World</p>
<ChildComponent />
</div>
</template>
<script>
import ChildComponent from '../ChildComponent'
export default {
components: {
ChildComponent
}
}
</script>
<style>
.text {
font-size: 30px
}
</style>
ChildComponent:
<template>
<p class="text">Hello World</p>
</template>
<script>
export default {
}
</script>
<style>
</style>
Now, whatever styles I have in ParentComponent, I want the child component to have that style as well.
However, I don't want App.vue to have that style. Also if ChildComponent has any other components, then they should inherit the style of ParentComponent as well. Like ParentComponent is the style provider.
I really don't have any code to show. I just want to know if this is possible and how?
You can simply create an css class in the parent component with the style you want to have the children use. Then you simply use the class in a child.
The example you have is actually working as how you want it to be, as long as the child-component indeed nested as a child in the parent component.
What we do in our firm is that we always wrap components with a class with the same name as the component name. This makes it really obvious what you are styling if you are doing some weird parent type styling.
ParentComponent:
<template>
<div>
<p class="text">Hello World</p>
<ChildComponent />
</div>
</template>
<script>
import ChildComponent from '../ChildComponent'
export default {
components: {
ChildComponent
}
}
</script>
<style>
.some-class-name {
/*...*/
}
.text {
font-size: 30px
}
</style>
ChildComponent:
<template>
<div class="some-class-name">
<p class="text">Hello World</p>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
I open the popup in some root component like this:
import parentt from "./parentt.vue";
.
.
.
this.$showModal(parentt, {
fullscreen: true,
});
This is the content of parentt.vue:
<template>
<StackLayout>
<label text="parent" />
<!-- <child /> -->
</StackLayout>
</template>
<script>
import child from "./child.vue";
export default {
components: [child],
};
</script>
<style scoped>
</style>
This is the content of child.vue:
<template>
<StackLayout>
<label text="child" />
</StackLayout>
</template>
<script>
export default {};
</script>
<style scoped></style>
Whith <child /> commented out I get a popup with text parent in it.
with <child /> being there I get a white screen.
I'm using many components in different places in my code, it's only here in a popup that it doesn't work.
You have wrong bracket in components object in parentt.vue. Components is an object, thus use braces instead of the square brackets.
So, the correct script section looks like in parentt.vue:
<script>
import child from "./child.vue";
export default {
components: {
child
},
};
</script>
I recommend for detailed informations the official vue documentation
I just try to follow the example about the use of slot on the Vue official site. But it failed, I have made the code very short
parent component
<template>
<subMenuTemp>
<div class="text" >
parent content
</div>
</subMenuTemp>
</template>
<script>
import subMenuTemp from 'src/test/testChildren.vue'
export default {
data() {
},
components: {
subMenuTemp
}
}
</script>
children component another .vue file
<template>
<div class="content">
<slot>
old content
</slot>
</div>
</template>
<script>
export default {
}
</script>
although the code is very short, I still cannot find where is my fault
Make sure to include the two components in your main.js or some .js file that imports Vue. It should look like this:
import Vue from 'vue'
import App from './App'
import subMenuTemp from './test/testChildren.vue'
new Vue({
el: '#app',
template: '<App/>',
components: { App, subMenuTemp }
})
You don't need to register all components in the main file as pointed in other answers.
You just need to import the child component into the parent component just as you do.
See a here: https://codesandbox.io/s/vue-template-oy15j?fontsize=14
// App.vue
<template>
<div id="app">
<parent-component message="Hello Vue !"/>
</div>
</template>
<script>
import ParentComponent from "./components/ParentComponent";
export default {
name: "App",
components: { ParentComponent }
};
</script>
// ParentComponent.vue
<template>
<child-component>
<div class="test-parent">{{ message }}</div>
</child-component>
</template>
<script>
import ChildComponent from "./ChildComponent";
export default {
name: "ParentComponent",
components: { ChildComponent },
props: {
message: String
}
};
</script>
// ChildComponent.vue
<template>
<div class="test-child">
<slot>default content</slot>
</div>
</template>
<script>
export default {
name: "ChildComponent"
};
</script>
<!-- Result -->
<div id="app">
<div class="test-child">
<div class="test-parent">Hello Vue !</div>
</div>
</div>