I just want to use an independant component many times like this :
<main-component>
<other-component />
<other-component />
</main-component>
I have a problem with variable in my other-component.
In the code bellow I use show var to display or not content according button click. I want to display only the paragraph of the current component clicked
import otherComponent from '../../otherComponent'
// main component
export default {
name: 'main-component',
components: {
otherComponent
},
data () {
return {
}
},
}
<template>
<div>
<other-component />
<other-component />
</div>
</template>
// other component
export default {
name: 'other-component',
data () {
return {
show: false
}
},
methods: {
toggle(){
this.show = !this.show
}
}
<template>
<div>
<button #click="toggle">Toggle</button>
<p v-show="show">1</p>
</div>
</template
When I click in button the two p are displayed. Why ?
If you nest components inside one another, you need to use slots: https://v2.vuejs.org/v2/guide/components-slots.html#ad.
For the following code to render correctly:
<main-component>
<other-component />
<other-component />
</main-component>
Your main-component component needs to have <slot /> in it's template:
<template>
<div>
<slot />
</div>
</template>
Then <slot /> will be replaced by ...
<other-component />
<other-component />
...when it renders. Which means main-component does not need to import or have any reference to otherComponent.
I have an example on CodeSandbox of this working: https://codesandbox.io/embed/vue-template-gblx0.
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"
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!
Writing in NativeScript-Vue for Android, I am trying to render a component based on button taps. I am using this this plugin to wrap the app in a global SideDrawer for quick navigation. I use buttons within the SideDrawer for viewing components. Here is what my App.vue looks like:
<template>
<Frame>
<Page actionBarHidden="true">
<GlobalDrawer>
<template slot="content">
<Label class="drawer-header" text="Drawer"/>
<Button class="drawer-button" text="Home" #tap="currentComponent = 'Home'" />
<Button class="drawer-button" text="Info" #tap="currentComponent = 'InfoPage'" />
<Button class="drawer-close-button" #tap="$drawer.close()">Close</Button>
</template>
<template slot="frame">
<ContentView>
<component v-for="component in pagesArray" v-show="component === currentComponent" :is="component" v-bind:key="component" />
</ContentView>
</template>
</GlobalDrawer>
</Page>
</Frame>
</template>
<script>
import Home from './pages/Home.vue';
import InfoPage from './pages/InfoPage.vue';
export default {
data () {
return {
pagesArray: ['Home', 'InfoPage'],
currentComponent: 'Home'
};
},
components: {
Home,
InfoPage
}
}
</script>
Here is the code in Home.vue, the default component I try to render:
<template>
<Page>
<navigation-bar />
<GridLayout>
<Label class="info" horizontalAlignment="center" verticalAlignment="center">
<FormattedString>
<Span class="fa" text.decode=" "/>
<Span :text="message"/>
</FormattedString>
</Label>
</GridLayout>
</Page>
</template>
<script>
import NavigationBar from '../components/NavigationBar.vue';
export default {
computed: {
message() {
return "Test Homepage";
}
},
components: {
NavigationBar
}
};
</script>
If I directly use the <home /> component within <ContentView /> it displays fine, but when trying to display it dynamically, I get a blank page; no errors. Any thoughts on this?
I run the app on a connected Samsung Galaxy S7 using the NativeScript CLI. NativeScript-vue version: ^2.4.0.
Edit [01.20.20]: Detailed explanation on how I solved it.
Read about it here: https://nativescript-vue.org/en/docs/routing/manual-routing/
In Application.vue, my GlobalDrawer looks like this:
<GlobalDrawer >
<template class="global-drawer" slot="content">
<ScrollView orientation="vertical" scrollBarIndicatorVisible="true" height="100%">
<StackLayout orientation="vertical">
<Label class="drawer-header" text="Menu"/>
<Button class="drawer-button" text="Home" ref="homeButton" #tap="homePageTap"/>
<Button class="drawer-button" text="System Oversight" #tap="infoPageTap" />
<Button class="drawer-button" text="Companies" #tap="companiesPageTap" />
<Button class="drawer-button" text="Calendar" #tap="calendarPageTap" />
<Button class="drawer-close-button" #tap="$drawer.close()">Close</Button>
<Label class="drawer-footer" text="By Bouvet" />
</StackLayout>
</ScrollView>
</template>
<template slot="frame">
<frame-hub />
</template>
</GlobalDrawer>
The methods-section contains the #tap-methods:
methods: {
homePageTap(args) {
this.$navigateTo(Home, { frame: "main-frame" });
this.$drawer.close();
},
infoPageTap(args) {
this.$navigateTo(InfoPage, { frame: "main-frame" });
this.$drawer.close();
},
companiesPageTap(args) {
this.$navigateTo(CompaniesPage, { frame: "main-frame" });
this.$drawer.close();
},
calendarPageTap(args) {
this.$navigateTo(CalendarPage, { frame: "main-frame" });
this.$drawer.close();
}
},
The < frame-hub > is a component (FrameHub.vue), looking like this:
<template>
<Page actionBarHidden="true">
<Frame id="main-frame">
<home />
</Frame>
</Page>
</template>
<script>
import Home from './../pages/Home';
import InfoPage from './../pages/InfoPage.vue';
import CompaniesPage from './../pages/CompaniesPage.vue';
import CalendarPage from './../pages/Calendar.vue';
export default {
components: {
Home,
InfoPage,
CompaniesPage,
CalendarPage
}
}
</script>
The #tap-methods in Application.vue changes the components that are renderered within the"main-frame"-element in FrameHub.vue. This way the GlobalDrawer is always on top, while the user is free to switch between pages.
I hope this helps anyone having the same issue. Also I'm sure this solution can be improved. Though I'm not currently working on this, but please let me know about improvements.
Creator of nativescript-vue-global-drawer plugin here.
The frame slot of GlobalDrawer contains a Frame element (here) to control navigation inside the drawer as stated here, which means the slot accept only Page elements.
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 was read some tutorial about this. They told me should using ref to do that.
But It's very general.
Here is my problem:
Basically in Header component include NavBar, SearchBar and ResultSearch component.
const Header = () => {
return (
<header className="ss_header">
<Navbar />
<SearchBar />
<ResultSearch />
</header>
);
};
And In SearchBar component. Whenever I focused on input text. It emit an event and display ResultSearch component by any way (changing style, or ...).
class SearchBar extends Component{
render() {
return (
<div className="search_bar">
<section className="search">
<div className="sub_media container">
<form method="GET" action="" id="search_form">
<Icon icon="search" />
<span className="autocomplete">
<input
className="search_input"
autoCorrect="off"
autoComplete="off"
name="query"
type="text"
placeholder="Search for a movie, tv show, person..." />
</span>
</form>
</div>
</section>
</div>
);
}
}
Style in ResultSearch component. I was set display: none.
.results_search { display: none; }
I think ResultSearch will receive an event from SearchBar and set back display: block for ResultSearch component. Is possible?
How can I handle that?
My Code here: https://codesandbox.io/s/3xv8xnx3z5
only you should convert Header component like following:
class Header extends Component {
state = {
focus: false
};
handleInputFocus = () => {
this.setState({ focus: true });
};
handleInputBlur = () => {
this.setState({ focus: false });
};
render() {
return (
<header className="ss_header">
<SearchBar
onFocus={this.handleInputFocus}
onBlur={this.handleInputBlur}
/>
{this.state.focus ? <ResultSearch /> : null}
</header>
);
}
}
and also in SearchBar component add following attributes to your input:
onFocus={this.props.onFocus}
onBlur={this.props.onBlur}
also, you should remove your CSS about result box.
And, you can see the updated code on the following sandbox:
https://codesandbox.io/s/mmj46xkpo9
Still not sure what you're trying to achieve.
This is the way you can handle visibility of result of the search. Let me know if this isn't what you're looking for.
https://codesandbox.io/s/7jvz31xr66