How to have nested routerLink in Angular - javascript

I have a project in angular 7
I have router links with <a> tag, and I have nested <a> tags that both have routerLink property,
the issue I am facing is , the inner <a> route doesn't work
<a [routerLink]="[ './comp1']">
Comp1
<a [routerLink]="['./comp2']">
Navigate to comp2 (Nested)
</a>
</a>
this is working if I separate it
<div>
<a [routerLink]="['./comp2']">
Navigate to comp2 (Not Nested)
</a>
</div>
Also I tried the below code and still same
<a [routerLink]="[ './comp1']">
Comp1
<a [routerLink]="['./comp2']" (click)="$event.preventDefault()>
Navigate to comp2 (Nested)
</a>
</a>
changing a tags to span also doesn't solve the issue
<span [routerLink]="[ './comp1']" >
Comp1
<span [routerLink]="['./comp2']" (click)="$event.preventDefault()">
Navigate to comp2 (Nested)
</span>
</span>
Here is the https://stackblitz.com/edit/angular-nested-router for it

In your stackblitz add the following function to your component class. It receives the event as parameter and calls the stopPropagation function on it.
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular';
stop(event: Event) {
event.stopPropagation();
}
}
In your template do
<router-outlet></router-outlet>
<a routerLink="/comp1">
Comp1
<a routerLink="/comp2" (click)="stop($event)">
Navigate to comp2 (Nested)
</a>
</a>
See my stackblitz fork.

Related

How to add a link to another website after clicking on Card in React JS

Below is my code for Cards.js file, right now it's a card that you can click on and it links to the Services page with path ='/services' from within the same website, I would like to add a link to another website, how would I go about doing that? would I need to add an a href= link to Cards.js?
import React from 'react';
import CardItem from './CardItem';
import './Cards.css'
function Cards() {
return (
<div className='cards'>
<h1>Check out my Programming Portfolio Projects!</h1>
<div className='cards__container'>
<div className='cards__wrapper'>
<ul className="cards__items">
<CardItem
src={`${process.env.PUBLIC_URL}/images/ReactSocialPosts.jpg`}
text='hello testing 123'
label='This is a card'
path ='/services'
/>
</ul>
</div>
</div>
</div>
)
}
export default Cards;
Below is CardItem.js if needed
import React from 'react';
import { Link } from 'react-router-dom';
function CardItem(props) {
return (
<>
<li className='cards__item'>
<Link className='cards__item__link' to={props.path}>
<figure className='cards__item__pic-wrap' data-category={props.label}>
<img
src={props.src}
alt='Travel Image'
className="cards__item__img"
/>
</figure>
<div className='cards__item__info'>
<h5 className='cards__item__text'>{props.text}</h5>
</div>
</Link>
</li>
</>
);
}
export default CardItem;
I'm not sure, but I think that you would only have to create a second CardItem with its attribute path = complete link to external website.
Example :
<CardItem
src={`${process.env.PUBLIC_URL}/images/OtherImage.jpg`}
text='External website'
label='A label'
path ='https://externalwebsite.com'
/>
If you just want to simply link to another website then you can simply use an anchor tag, if you want to declare a Route from react-router-dom for that link to follow, you need to look at this post
As per documentation React-Router understands only internal paths. Then an anchor tag is needed. I would do a wrapper component for Link that chose if render an anchor or the router link object. Then use it instead of "Link".
Something like (code not tested):
const MyLink = ({path, children, ...props}) => {
const comp = path?.trim().substring(0,4) === "http" ? <a href={path}> : <Link to={path}>;
return <comp ...props>{children}</comp>
};

Anchor links in GatsbyJS + React

I have been stuck on this problem for a while now. I created a GatsbyJS project after I made my project in a normal create-react-app. Everything worked fine until I made some big changes to the code. This ruined my navigation - BUT NOT COMPLETELY! The logo navigation still works and the links in the footer, but not the NavBar items. I'm using the gatsby plugin: 'gatsby-plugin-anchor-links' (https://www.gatsbyjs.com/plugins/gatsby-plugin-anchor-links/).
Here is my NavBarItem code (component):
import React from "react"
import "../../Bulma.css"
import { Link } from "gatsby"
function NavBarItem(props) {
return (
<Link
className={"pl-6 pr-6 has-text-black navbar-item " + props.class}
to={"/#" + props.location}
>
{props.text}
</Link>
)
}
export default NavBarItem
Here is my NavBar component:
import React from "react"
import NavBarItem from "./assets/NavBarItem"
import "../Bulma.css"
import "./NavBar.css"
import { Link } from "gatsby"
import logo from "../../static/dronarfoton_logo.png"
class NavBar extends React.Component {
constructor(props) {
super(props)
this.state = {
isActive: true,
}
}
toggle() {
this.setState({ isActive: !this.state.isActive })
}
render() {
return (
<nav
className="navbar has-text-white has-background-grey-lighter has-navbar-fixed-top is-fixed-top"
role="navigation"
aria-label="main navigation"
>
<div className="navbar-brand">
<a href="#Top" className="navbar-item">
<img
alt="Logga som det står DrönarFoton på. Det visar en drönare och text."
src={logo}
width="112"
height="28"
/>
</a>
<a
role="button"
className={
this.state.isActive
? "navbar-burger burger"
: "is-active navbar-burger burger"
}
aria-label="menu"
aria-expanded={this.state.isActive ? "false" : "true"}
data-target="navbarBasicExample"
onClick={this.toggle.bind(this)}
>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div
className={this.state.isActive ? "is-active navbar-menu" : "is-block"}
>
<div className="navbar-end">
<NavBarItem location="Top" text="Hem" />
<NavBarItem location="OmOss" text="Om oss" />
<NavBarItem location="Kontakt" text="Kontakt" />
<NavBarItem class="is-disabled" location="#" text="❌ Galleri ❌" />
</div>
</div>
</nav>
)
}
}
export default NavBar
Again, the 'navbar-brand' link WORKS but not the navbar items.
My thought was that it has something to do with how it's rendered, but I can't figure out how & why this is happening.
Another interesting part is that THE LINKS WORK IF I DISABLE JAVASCRIPT IN MY BROWSER
If someone has an idea of why this is happening. Please let me know.
Thanks //Gustav
You are using a prop location in your <NavBarItem> component but in the end, you are rendering a <Link>, that doesn't accept hashes (#) neither an anchor behavior. As you can see in <Link>'s API documentation (in-app navigation):
Neither <Link> nor navigate can be used for in-route navigation with a
hash or query parameter. If you need this behavior, you should either
use an anchor tag or import the #reach/router package—which Gatsby
already depends upon—to make use of its navigate function.
If you want to use an anchor link in your <NavBarItem>, you should use a regular <a> or using gatsby-plugin-anchor-links properly:
<AnchorLink
to="/about#team"
title="Check out our team!"
className="stripped"
stripHash
/>
Keep in mind that using a regular <a>, you will lose all the benefits on the #reach/routing and you will refresh the page completetly.

Vuejs toggle class to the body on button click in a components

I want to toggle a class to the body or to the root element("#app") if I click on the button inside the header component
Header.vue :
<template lang="html">
<header>
<button class="navbar-toggler navbar-toggler align-self-center" type="button" #click="collapedSidebar">
<span class="mdi mdi-menu"></span>
</button>
</header>
</template>
<script>
export default {
name: 'app-header',
data: {
isActive: false
},
methods: {
collapedSidebar() {
}
}
}
</script>
App.vue :
<template lang="html">
<div id="app" :class="{ active: isActive }">
...
</div>
</template>
! Please correct me if I'm in the wrong direction. I'm new in Vuejs :)
You can emit an event inside your header and maybe catch it in the mounted of app component like this:
In your sidebar or other component:
on_some_btn_click: function (){
this.$emit('toggle_root_class');
}
In your app component:
mounted: function(){
var _this = this;
this.$on('toggle_root_class', function(){
_this.active = !_this.active;
});
}
Vue may restrict event from being observed in sibling components. So I use EventBus in my projects to handle sending events easily.
the problem lies in your component scope. You tried to access data in Header.vue in App.vue which is impossible by the structure in showed in your code. Consider moving isActive data to App.vue or use Vuex.
You can use jquery to toggle class for an element which is not inside the Vue template.
You can call a function on click of a button and inside it, you can toggle class in body tag using jquery.
<template lang="html">
<header>
<button class="navbar-toggler navbar-toggler align-self-center" type="button" :class="{ active: isActive }" #click="activeLink">
<span class="mdi mdi-menu"></span>
</button>
</header>
</template>
<script>
export default {
name: 'app-header',
data: {
isActive: false
},
methods: {
activeLink() {
$('body').toggleClass('.class-name');
}
}
}
</script>

Angular Material 2 - Not rendering in full page

I am using Angular Material 2 for my Angular 2 app. My dashboard page is not rendering full page in the browser. Attached is the screenshot of the above mentioned issue.
AppComponent - Template file:
<router-outlet></router-outlet>
DashboardComponent - Template file :
<md-sidenav-layout>
<md-sidenav #sidenav mode="side" class="app-sidenav md-sidenav-over" (open)="list.focus()">
<ul #list>
<li> Item 1</li>
<li> Item 2</li>
<li> Item 3</li>
</ul>
</md-sidenav>
<md-toolbar color="primary">
<button class="app-icon-button" (click)="sidenav.toggle()">
<i class="material-icons app-toolbar-menu">menu</i>
</button>
<span class="margin-left10"> Angular Material2 Portal </span>
<span class="app-toolbar-filler"></span>
<button md-button router-active [routerLink]=" ['Index']">
Index
</button>
<button md-button router-active [routerLink]=" ['Home']">
{{ 'HOME.TITLE' | translate }}
</button>
<button md-button router-active [routerLink]=" ['About'] ">
{{ 'ABOUT.TITLE' | translate }}
</button>
</md-toolbar>
<div class="app-content">
<md-card>
Dashboard Content Goes Here..!!
</md-card>
</div>
<footer>
<span id="footerText">Dashboard Footer</span>
</footer>
</md-sidenav-layout>
DashboardComponent.ts:
import {Component, Inject, ElementRef, OnInit, AfterViewInit} from '#angular/core';
import {TranslatePipe} from 'ng2-translate/ng2-translate';
console.log('`Dashboard` component loaded asynchronously');
#Component({
selector: 'dashboard',
styles: [
require('./dashboard.component.css')
],
template: require('./dashboard.component.html'),
pipes: [TranslatePipe]
})
export class Dashboard implements {
elementRef:ElementRef;
constructor(#Inject(ElementRef) elementRef:ElementRef) {
this.elementRef = elementRef;
}
ngOnInit() {
console.log('hello `Dashboard` component');
}
}
Am I missing something here ?
Please refer :
Screenshot of my half-page rendered dashboard page
Appreciate your help.
You are missing the fullscreen attribute inside of the md-sidenav-layout tag.
This attribute will add these properties to the md-sidenav-layout:
[_nghost-oog-2][fullscreen] {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
It's not very well documented quite yet that such an attribute can be added to the md-sidenav-layout since it is still in alpha. But within this preview at ngconf they demonstrate some of what you can currently use from Material 2.

Angular2 Route events

I'm using Angular2 routing and I need to subscribe to an event when route is changed. (i.e. user clicked on one of the route links). The important thing is that the event should be when the new view HTML is inserted to DOM.
Are there any events like onNavigating and onNavigated, so I can subscribe to?
I've found a couple of examples on stackoverflow and tried to use them (see constructor below), but that didn't work. Any ideas?
/// <reference path="../../typings/tsd.d.ts" />
import {Component, View} from 'angular2/angular2';
import {RouteConfig, Router, RouterOutlet, RouterLink} from 'angular2/router';
#RouteConfig([...])
#Component({
selector: 'app'
})
#View({
directives: [RouterOutlet, RouterLink],
template: `
<div class="mdl-layout mdl-js-layout mdl-layout--fixed-header">
<header class="mdl-layout__header">
<div class="mdl-layout__header-row">
<span class="mdl-layout-title">Test</span>
<div class="mdl-layout-spacer"></div>
<nav class="mdl-navigation mdl-layout--large-screen-only">
<a class="mdl-navigation__link" [router-link]="['/routelink1']">routelink1</a>
</nav>
</div>
</header>
<main class="mdl-layout__content" style="padding: 20px;">
<router-outlet></router-outlet>
</main>
</div>
`
})
export class App {
constructor(private router: Router){
router.subscribe((val) => function(){...}); //here is I need to process HTML
}
}
I ended up with having base class for my routing components and it contains routerOnNavigate override.
import {OnActivate, ComponentInstruction} from 'angular2/router';
export class BaseView implements OnActivate {
routerOnActivate(next: ComponentInstruction, prev: ComponentInstruction) {
componentHandler.upgradeDom();
}
}

Categories

Resources