Ember JS: Call component action from another component - javascript

I am new to ember JS and after looking through the doc I still have no idea or don't understand how to achieve the following.
I have a navbar component that includes a menu button component
//components/nav-bar.hbs
<nav>
<LinkTo class="btn-1" #route="contact"><span>Contact</span></LinkTo>
<LinkTo class="btn-1" #route="about"><span>About</span></LinkTo>
<MenuButton>Menu</MenuButton>
</nav>
When this button is clicked I would like to toggle another component which is not a parent nor a child of menu-button component, nor of the nav-bar component
//components/nav-aside.hbs
<div class="core_page_cover">
</div>
<aside class="core_menu_aside">
</aside>
//components/nav-aside.js
import Component from "#glimmer/component";
import { action } from "#ember/object";
export default class NavAsideComponent extends Component {
#action
toggle() {
//toggle expanded | retracted class
}
}
I have no idea how to call the toggle action when clicking on the button and I guess I am missing something...
The components are encapsulated like so
// .--------------navbar.hbs-------------- //
// <nav>
// link link link link link link toggle-button //
// </nav>
// <MenuAside/>
Thanks a lot.

The solution here is to move the state and the action to the common ancestor.
It seems you have 3 components:
navbar
nav-bar
nav-aside
Where basically navbar encapsulates both nav-bar and nav-aside:
so you have basically this in your navbar:
<NavBar />
<NavAside />
and inside the nav-bar you have a button that should toggle if something inside nav-aside is shown.
Then the solution is to keep that information on the wrapping navbar component:
class NavbarComponent extends Component {
#tracked showSomethingInAside = false;
#action
toggleShowSomethingInAside() {
this.showSomethingInAside = !this.showSomethingInAside;
}
}
And use it like this to call your components in navbar:
<NavBar #toggleSomethingInAside={{this.toggleShowSomethingInAside}} />
<NavAside #showSomethingInAside={{this.showSomethingInAside}} />
Then inside nav-bar you can use the action:
<button type="button" {{on "click" #toggleSomethingInAside}}>
show something in aside
</button>
And inside nav-aside you can use the boolean:
{{#if #showSomethingInAside}}
This can be toggled by the button in the other component
{{/if}}
So you see the solution is to always keep the state in the right place. If multiple components share a state (because one changes it and the other reads it) that state belongs in neither component but a common ancestor component.

Related

React.js NavBar: Is it possible to reference a different component's markup? (Trying to create a navbar that references to components in one route)

Basically I'm trying to make a navbar for a personal website application in which the navbar references content (About/Skills, etc.) all on single page (route). When making the navbar, I can easily reference markup with ids/classes BUT I would have to put all the html in one file.
I noticed that if I were to separate each content into its own react file (About.jsx, Skills.jsx, etc.) and import them, there didn't seem to be a way for me to reference the react component's markup.
I also noticed with react router, this wasn't feasible because each component would be on a separate route (which I don't want) rather than on a single route.
This is my current navbar file below; How exactly Can I import and reference the markup of the separate components?
import React from 'react';
import "../Styles/NavBar.scss";
import About from "./About.jsx"; (Not used)
import Skills from "./Skills.jsx"; (Not Used)
import Projects from "./Projects.jsx"; (Not used)
const NavBar = () => (
<div class="MainDivWrapper">
<div class="NavBarDiv">
<h1 class="NavBarH1">NavBar</h1>
<br/>
<nav>
About
Skills
Projects
</nav>
{/* <div id="AboutDiv">
<h1>About Me</h1>
<span>Just some text</span>
</div>
<div id="SkillsDiv">
<h1>Skills</h1>
<span>Just some text</span>
</div>
<div id="ProjectssDiv">
<h1>Projects</h1>
<span>Just some text</span>
</div> */}
</div>
<hr class="HeaderDivider"/>
</div>
)
You reference a JSX import like that:
/* Component have to start with a capital letter. file name can be anything (usually is the same as component) */
import MyComponent from "./MyComponent"
export default function MyApp() {
return (
<div>
/* other html/components here */
<MyComponent /> // selfing close tag
/* or */
<MyComponent> // with `children`
some content
</MyComponent>
</div>
)
}
Here is a codesandbox implementation of your code: https://codesandbox.io/s/stack-reactjs-navbar-is-it-possible-to-reference-a-different-components-markup-64oic?file=/src/App.js

passing props as classNames in next.js

I am trying to have the header of each of my app's pages change color based on the current page. How I am trying to achieve this:
<Header className="headerBitcoin"></Header>
What I want is the be able to have the header component present on all 4 pages, and then just change the className to another prop to change the background but not anything else.
And the header component itself
import styles from "../../styles/Home.module.css";
export default function Header(props) {
return (
<div >
<div className={props.className}>aaaaa</div>
<div className={styles.row}>
<div className={styles.tab}>a</div>
<div className={styles.tab}>a</div>
<div className={styles.tab}>a</div>
<div className={styles.tab}>a</div>
</div>{" "}
</div>
);
}
At the moment the styles for the tabs and row are working but the header is not getting its style applied.
I checked the console and found the header is getting the className headerBitcoin passed to it, however the row beneath it has the className of "Home_row__88lPM"
This is my first time working with next.js, and I know I am doing something wrong because this works in React. Any help would be appreciated.
don't do this:
<div className={props.className}>aaaaa</div>
try this instead:
<div className={styles[props.className]}>aaaaa</div>
I think this should works
I assume it's not being applied because you have the headerBitcoin styles defined in your CSS module.
If you want to apply a class that way (className="headerBitcoin"), you need to define the class in your global CSS instead.
If you meant to use the headerBitcoin defined in Home.module.css, then you'll want to change the className to use the scoped styles.
import styles from "../../styles/Home.module.css";
export default function Header(props) {
return (
<div >
<div className={styles[props.className]}>aaaaa</div>
// ...
</div>
);
}

Nuxtjs: How to call component inside another component?

I understand paradigm "Page-component" but what if I have a page that renders component, how do I call another component inside this component? Currently nuxtjs does not allow me do it. I can not stick to standart "page-component" scheme as I am bulding cart which calls cart-items.
Say If a cart component which is called by page looks like this, how would it call cart-item component inside it?
<!---- cart component called from index.vue --->
<template>
<div>
<Cart-item></Cart-item> < ---------- This doesn't work.
</div>
</template>
<script>
export default {
props: ['items']
}
</script>
I managed it the standard way:
<template>
<div>
<CartItem></CartItem>
</div>
</template>
<script>
import CartItem from '../components/Cart-item'
export default {
props: ['items']
}
</script>
Since nuxtjs auto-registers all components wonder if there is more graceful way.
EDIT: as promised, here is an example on how to pass some content to a component from another one thanks to slots. This is totally working in any Nuxt page ofc.
NestedContent.vue
<template>
<div>
<p>Here is the NestedContent component and below is a slot passed to ParentWithSlots' component</p>
<hr />
<parent-with-slots>
<!-- <template #default> // this one can be omit since we do use the default slot here -->
<p>This content is inserted into the component ParentWithSlots</p>
<!-- </template> -->
</parent-with-slots>
</div>
</template>
ParentWithSlots.vue
<template>
<div>
<p>xxxxxxxxxxx ParentWithSlots' content before slot xxxxxxxxxxx</p>
<slot>Default content in case none is provided</slot>
<p>xxxxxxxxxxx ParentWithSlots' content after slot xxxxxxxxxxx</p>
</div>
</template>
Here is how it looks
PS: you may also give a try to layouts, it can be useful for overall positioning of some of your components visually.
If your components are in the components directory, you can set components: true in your nuxt.config.js and have access to it pretty much anywhere without any additional step with the <cart-item></cart-item> syntax.
More details here: https://nuxtjs.org/blog/improve-your-developer-experience-with-nuxt-components/

use same component with same props name in on page not works vuecli

Well. i have a component called Logo and i am using it in nearly every views and even in other components. Logo component takes only 1 props: "size" and i use javascript to mack it responsive depend on its font size but => for example i have a landing:
in landing i have component renderd in landing: navbar that contains a "logo component" inside OF HIM. and same time i use logo component in my landing view as well:
LOGO COMPONENT
<template lang="html">
<div class="logoCon">
<a class="logo">Some name for Logo</a>
</div>
</template>
<script>
export default{
props: ['size'],
name: 'Logo',
methods: {
logoSizing(size){
// java script code for make the sizing right.
}
},
created(){
// calling logoSizing function.
this.logoSizing(this.size);
// for adding the font size.
document.querySelector(".logo").style.fontSize = (this.size + "px");
}
}
</script>
NAVBAR COMPONENT
<template lang="html">
<div class="navbarCon">
//some code for navbar. and inside the navbar we have logo component:
<logo :size="logoSize" />
</div>
</template>
<script>
export default{
name: 'Navbar',
data: () => ({
logoSize: "20"
})
}
</script>
and the last one LANDING COMPONENT
<template lang="html">
<div class="navbarCon">
// navbar component
<navbar />
// we have logo component:
<logo :size="logoSize" />
</div>
</template>
<script>
export default{
name: 'Landing',
data: () => ({
logoSize: "400"
}),
components: {
navbar,
logo
}
}
</script>
so now if i run the code the "logoSize" varible dont work for each in seperate ways and get only one of the logo components, mostly just the navbar and the logo component in landing it gets no style at all from my java script.
=>how can i use the logo component multiple times in one page and works for each in seprate ways
THIS ISSUE IS NOT ONLY FOR MY LOGO COMPONENT ALL OF MY COMPONENTS ARE HAVE THE SAME PROBLME PLEASE HELP ME SOLVE IT.... I WANT TO CRY
So considering that your logoSizing(size) doesn't change the size value (because you souldn't mutate props because when you do, you change it in the parent component as well and may lead to inconsistent changes), I would say that maybe your components are being renderes with the same id (which sound kinda weird).
To solve that "problem", (and again this shouldn't happen unless you're forcing it somehow) give to the components different key's like
<logo :size="400" :key="navbarLogo"/>
<logo :size="300" :key="appbarLogo"/>
This forces your components to have a different ID in DOM.
But a codepen would be really handy

In VueJS, how do I use load in a view based on what is populated in my JS?

I am new to Vue.JS and require a little help as I am stuck with some logic.
I have been given a project to building and as I am under NDA I can only show comparative code examples.
In one View (Bars), which is brought into the viewport of the application using the router, I have a simple for loop.
<ul class="bar-listings">
<li v-for="bar in bars">
<router-link to="{bar.barPage}">
<div class="item">
<div class="item-bd">
<h2>{{ bar.barName }}</h2>
</div>
</div>
</router-link>
</li>
</ul>
Then in my JS file conatining all my data, I have this (Only one object for now)
export default [
{
barName: "The Tropicana Bar",
barPage: "views/bars/Tropicana",
}
];
The title displays correctly on Bars so the loop is pulling the data correctly.
However, I will have a .vue file for each bar, which also uses the data from my JS file. See below:
<template>
<div class="content-wrapper">
<h1>{{ getBarByIndex({ bars, index }).barName }}</h1>
</div>
</template>
<script>
import bars from "./../../data/bars";
export default {
data() {
return {
bars: bars
};
},
methods: {
getBarByIndex({ bars = [], index = 0 }) {
return bars[index] || {}
}
}
};
</script>
So what I need to solve is how do I make the <a v-bind:href=""> load the view for this bar?
What I think you can do, is to have a child component inside your component, you can leverage this by using nested routes in your router-view, additionally, you can pass props as an object to your router components, parent or child, whatever you need.
Basically, you will have a main router view, but inside your component, you will have another router-view which renders child components.
See: Nested Routes
See: Passing Props to Route components

Categories