Angular 10: How to highlight element on navbar depending on scroll? - javascript

I am making a single page in Angular 10. It a simple page and I would like to highlight navbar depending on scroll. how can i highlight the element on navbar where i am currently, but make sure it is single page , so i am navigation to sections with id in my page.
here is my code:
HOME.COMPONENT.htmlstrong text
`
<!-- site header
================================================== -->
<header id="navbar" class="s-header" (Scroll)="onWindowScroll($event);">
<nav class="header-nav-wrap">
<ul class="header-main-nav">
<li><a class="smoothscroll" href='/home' title="intro">Intro</a></li>
<li><a class="smoothscroll" href='home#about' title="about">About</a></li>
<li><a class="smoothscroll" href='home#services' title="services">Services</a></li>
<li><a class="smoothscroll" href='home#works' title="works">Works</a></li>
<li><a class="smoothscroll" href='home#contact-us' title="contact us">Say Hello</a></li>
</ul>
</nav>
</header> <!-- end s-header -->
<!-- intro
================================================== -->
<section id="intro" class="s-intro target-section">
<div class="row intro-content">
<div class="column large-9 mob-full intro-text">
<h3>Hello, I'm xyz</h3>
<h1>
Full stack Developer <br>
and Dotnet Developer <br>
Based In somewhere.
</h1>
</div>
<div class="intro-grid"></div>
<div class="intro-pic" style="background-image: url(/assets/images/intro-pic.jpg);"></div>
</div> <!-- end row -->
</section> <!-- end intro -->
<section id="about" class="s-about">
hi about
</section>
<section id="services" class="s-services">
hi services
</section>
<section id="works" class="s-works">
hi works
</section>
<section id="contact-us" class="s-contactUs">
hi contacts
</section>`
HOME.COMPONENT.ts
import { Component, OnInit, HostListener } from '#angular/core';
import $ from 'jquery';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
/* sticky navbar on Scrolldown
* ------------------------------------------------------ */
#HostListener('window:scroll', ['$event'])
onWindowScroll(e) {
if (window.pageYOffset > 200) {
let element = document.getElementById('navbar');
element.classList.add('sticky');
} else {
let element = document.getElementById('navbar');
element.classList.remove('sticky');
}
}
}

Have a flag on the component and use it to set the class
export class HomeComponent implements OnInit {
menuSticky = false;
#HostListener('window:scroll', ['$event'])
onWindowScroll(e) {
if (window.pageYOffset > 200) {
this.menuSticky = true;
} else {
this.menuSticky = false;
}
}
}
and use it in the template
<header id="navbar" class="s-header" [ngClass]="{ sticky: menuSticky }" (Scroll)="onWindowScroll($event);">

Related

Modal does not open: TypeError: Cannot read property 'open' of undefined

I am trying to display a pop up that I tried to implement as modal, but I get the error:
TypeError: Cannot read property 'open' of undefined
I created the pop up as component:
import { Component, OnInit, ViewChild, ElementRef, Input } from '#angular/core';
import User from '../types/user'
#Component({
selector: 'app-modal',
templateUrl: './chat-user-profile.component.html',
styleUrls: ['./chat-user-profile.component.css']
})
export class ChatUserProfileComponent {
me: User;
ngOnInit() {}
#ViewChild('ChatUserProfile') modal: ElementRef;
open() {
this.modal.nativeElement.style.display = 'block';
}
close() {
this.modal.nativeElement.style.display = 'none';
}
}
<div #myChatUserProfile class="container">
<div class="content">
<p>Some content here...</p>
<div class="text-center mb-2">
<h4><span class="badge badge-pill">{{me?.username}}</span></h4>
</div>
<!-- <button (click)="save()">Save</button> -->
<button (click)="close()">Close</button>
</div>
</div>
Now I try to open it on clicking a button
#Component({
selector: 'app-nav',
templateUrl: './nav.component.html',
styleUrls: []
})
export class NavComponent {
isLoggedIn = false;
constructor(private amplifyService: AmplifyService, public router: Router) {
this.amplifyService.authStateChange$.subscribe(authState => {
const isLoggedIn = authState.state === 'signedIn' || authState.state === 'confirmSignIn';
if (this.isLoggedIn && !isLoggedIn) {
router.navigate(['']);
} else if (!this.isLoggedIn && isLoggedIn) {
router.navigate(['/chat']);
}
this.isLoggedIn = isLoggedIn;
});
}
public signOut() {
this.amplifyService.auth().signOut();
}
//Stuff for Profile Button
#ViewChild('app-modal') modal: ChatUserProfileComponent
openModal() {
this.modal.open();
}
}
<nav class="navbar navbar-toggleable-md navbar-inverse navbar-dark bg-dark fixed-top">
<a class="navbar-brand text-white" routerLink='/'>
<img src="../../assets/img/chat.png" width="30" height="30" class="d-inline-block align-top" alt="http://freepngimg.com/png/11489-chat-free-download-png">
<strong>ChatQL</strong>
</a>
<!--STUFF TO INTEGRATE THE POP UP-->
<app-modal #modal></app-modal>
<button (click)="openModal()">Open Modal</button>
<!------------->
<ul class="nav navbar-nav">
<li *ngIf="isLoggedIn" class="nav-item">
<button class="btn btn-primary" (click)="signOut()">Sign Out <i class="ion-log-in" data-pack="default" data-tags="sign in"></i></button>
</li>
</ul>
</nav>
I also tried adding the modal to the constructor but that gave me a No Provider error.
I am based on the chatQL project and using this as template for the pop up. I think something is wrong when initializing but I can not figure out where exactly.
In your HTML code, you have used template reference #modal
<app-modal #modal></app-modal>
So in typescript file you have to replace '#ViewChild('app-modal')' with '#ViewChild('modal')' like below
#ViewChild('modal') modal: ChatUserProfileComponent
Currently, you are using the wrong template reference so you are getting this undefined error because there is no template with reference 'app-modal'.

How can I configure my <li> items with Angular Routing so that it shows the relevant details in a new view?

I am building an Angular Movie DB, the two components I am working with are the "search-movie" component and the "single-view" component. The "search-movie" component displays a list of movies, the "single-view" component shows further details of a given movie.
I would like it so that when I click on a movie from the list in the "search-movie" component, the page renders the "single-view" component for that movie.
I have managed to set this up so that navigating to the "single-view" path with a movie id (i.e. /movie/tt4425200) directly from the URL, correctly loads up the info for that movie by it's ID, so that's all correctly set up.
I just can't seem to connect the clicking of a movie in the "search-movie" component, to then successfully navigate to the correct "single-view" path. So using the example above, clicking on the relevant movie loads up the "single-view" component with the URL path /movie/tt4425200.
I'm sure that this is a case of using #Input to communicate between the two components, but I just can't figure it out.
search-movie.component.ts:
import { Component, OnInit, Input } from '#angular/core';
import { FormControl } from '#angular/forms';
import { DataService } from '../data.service';
#Component({
selector: 'app-search-movie',
templateUrl: './search-movie.component.html',
styleUrls: ['./search-movie.component.css']
})
export class SearchMovieComponent implements OnInit {
searchControl = new FormControl('');
movieResults: any = [];
constructor(private data: DataService) { }
ngOnInit() {}
/* GET request */
getData(event) {
const film = event.target.value;
this.data.searchFilm(film)
.subscribe( (res) => {
res = this.movieResults = res;
console.log(res);
});
}
}
search-movie.component.html:
<div class="container">
<h1 class="is-size-3">Find your favorite movies...</h1>
<form (ngSubmit)="onSubmit()">
<input
type="text"
(keyup)="getData($event)"
placeholder="Start typing..."
[formControl]="searchControl" />
</form>
{{searchControl.value}}
</div>
<div class="container">
<ul>
<li id="list-item" *ngFor="let x of movieResults; let i = index;">
<img [src]="x.Poster" onerror="this.src='../assets/images/default-poster.jpg'">
<p id="movie-title" class="is-size-5">{{x.Title}} ({{x.Year}}) </p>
</li>
</ul>
</div>
single-view.component.ts:
import { Component, OnInit, Input } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import { DataService } from '../data.service';
#Component({
selector: 'app-single-view',
templateUrl: './single-view.component.html',
styleUrls: ['./single-view.component.css']
})
export class SingleViewComponent implements OnInit {
singleDetails: any = {};
constructor(
private data: DataService,
private route: ActivatedRoute) { }
ngOnInit() {
/** GENERATE FILM DETAILS BY movie/id where id is the imdbID */
const id = this.route.snapshot.paramMap.get('id');
this.data.moviebyID(id)
.subscribe( (res) => {
res = this.singleDetails = res;
});
}
}
single-view.component.html:
<div class="container singleDisplayContainer">
<div class="columns is-mobile">
<div class="column" id="poster-column">
<img id="poster" [src]="singleDetails.Poster" [alt]="singleDetails.Title" onerror="this.src='../assets/images/default-poster.jpg'">
</div>
<div id="info-column" class="column">
<div class="columns">
<div class="column is-three-fifths">
<h1 class="is-size-3">{{singleDetails.Title}} <span class="is-size-4">({{singleDetails.Year}})</span> </h1>
<p style="font-size: 14px"> {{singleDetails.Rated}} | {{singleDetails.Runtime}} | {{singleDetails.Genre}} | {{singleDetails.Released}} </p>
</div>
<div class="column">
<div class="columns">
<div class="column is-one-third">
<img id="star-rating" width="50px" src="../../assets/images/star-rating.png" alt="{{singleDetails.Title}}">
</div>
<div class="column">
<p style="font-size: 2em"> {{singleDetails.imdbRating}}<span style="font-size: 12px">/10</span></p>
<p>{{singleDetails.imdbVotes}}</p>
</div>
</div>
</div>
</div>
<br>
<p>Plot: {{singleDetails.Plot}} </p>
<br>
<p>Directed by: {{singleDetails.Director}} </p>
<br>
<p>Writers: {{singleDetails.Writer}} </p>
<br>
<p>Actors: {{singleDetails.Actors}} </p>
<br>
<p onerror="this.style.display='none'">Box office: {{singleDetails.BoxOffice}} </p>
</div>
</div>
</div>
In Your UL -> LI, add routerLink property and pass the movie id as the second param
[routerLink]="['/movie/,x.movieId]">
<ul>
<li id="list-item" *ngFor="let x of movieResults; let i = index;" [routerLink]="['/movie/,x.movieId]">
<img [src]="x.Poster" onerror="this.src='../assets/images/default-poster.jpg'">
<p
id="movie-title"
class="is-size-5">{{x.Title}} ({{x.Year}}) </p>
</li>
</ul>
Looks like you have everything set up, all you need to do is navigate to single-view on click of the movie.
search-movie.component.ts
showDetails(id : string) {
this.router.navigate(['movie',{ id }]);
}
search-movie.component.html
<!-- in showDetails you will pass id of the current movie while looping -->
<li id="list-item" *ngFor="let x of movieResults; let i = index;" (click)="showDetails(x.id)">
<img
[src]="x.Poster"
onerror="this.src='../assets/images/default-poster.jpg'"
>
<p
id="movie-title"
class="is-size-5">{{x.Title}} ({{x.Year}}) </p>
</li>
This will navigate to single-view page. is this what you want right?
or you need to load single-view in the same page as the list?

JQuery search limited to Angular component's DOM

I would like to use JQuery inside my Angular components for DOM manipulation, but I would like to limit JQuery searches to the component's markup it's used in.
I'm trying using Shadow DOM, so I have this component:
import { Component, OnInit, ViewEncapsulation } from '#angular/core';
import * as $ from 'jquery';
#Component({
selector: 'app-layout',
templateUrl: './layout.component.html',
styleUrls: ['./layout.component.less'],
encapsulation: ViewEncapsulation.Native
})
export class LayoutComponent implements OnInit {
constructor() { }
ngOnInit() {
}
toggleSidebar(): void {
$('.main-sidebar').toggleClass('active');
$('.content-wrapper').toggleClass('expanded');
}
}
Here's the HTML:
<div class="wrapper">
<header class="main-header">
Logo
<nav class="navbar">
<button type="button" id="sidebar-collapse" class="btn btn-info navbar-btn" (click)='toggleSidebar()'>
<i class="fa fa-align-left"></i>
</button>
</nav>
</header>
<aside class="main-sidebar">
<section class="sidebar">
Sidebar
</section>
</aside>
<div class="content-wrapper">
<section class="content">
Content
</section>
</div>
</div>
If I remove the encapsulation configuration, it works, but if I leave it in place, JQuery can't find the elements searched. I would like to know how can I make JQuery find those elements. Is there any other way of limiting JQuery searches apart from using Shadow DOM?
Why would you do menu toggling with jQuery?
It is not good practice to use it with Angular application. Let Angular do it.
You can do it with host binding
HTML
<nav class="navbar">
<button type="button" id="sidebar-collapse" class="btn btn-info navbar-btn"
(click)='toggleSidebar()'>
<i class="fa fa-align-left"></i>
</button>
</nav>
<aside class="main-sidebar" [ngClass]="{'menu_open': menuOpen}">
<section class="sidebar">
Sidebar
</section>
</aside>
Component
import { Component, HostBinding, OnInit } from '#angular/core';
export class LayoutComponent implements OnInit {
// set it closed by default
#HostBinding('class.menu_open') public menuOpen = false;
....
toggleSidebar() {
this.menuOpen = !this.menuOpen;
}
...
}

Angular: I can't seem to get JavaScript functions to work, but it's not giving me any undefined errors

My angular project isn't giving me any errors, but functions aren't working.
I'm doing a simple project trying to learn MEAN stack, and I've reached a point where my functions just aren't doing anything. I want the decideDetail() function to change the value of details so that the content displayed by productdetail.component.html is changed when the user clicks a certain element on the products.component.html template. I assume I'm linking my JavaScript file coorectly, because before I did that, it was telling me the function wasn't defined. Here are what I think are the relevant files (I've tried writing decideDetail() several different ways):
products.component.html
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css"
integrity="sha384-PsH8R72JQ3SOdhVi3uxftmaW6Vc51MKb0q5P2rRUpPvrszuE4W1povHYgTpBfshb" crossorigin="anonymous">
</head>
<body>
<div class="topnav" id="myTopnav">
Home
<a class="active" href="products">Products</a>
</div>
<div class="row">
<div class="col-xl-6" id="0" (click)="decideDetail(details, productList[0].productDescription)">
<a routerLink="detail" style="color: orange"> {{ productList[0]?.productName }} </a>
</div>
<div class="col-xl-6" id="product2">col-xl-6</div>
</div>
<div class="row">
<div class="col-xl-6" id="product3">col-xl-6</div>
<div class="col-xl-6" id="product4">col-xl-6</div>
</div>
<div class="row">
<div class="col-xl-6">col-xl-6</div>
<div class="col-xl-6">col-xl-6</div>
</div>
<div class="row">
<div class="col-xl-6">col-xl-6</div>
<div class="col-xl-6">col-xl-6</div>
</div>
<div class="row">
<div class="col-xl-6">col-xl-6</div>
<div class="col-xl-6">col-xl-6</div>
</div>
</body>
</html>
products.component.ts
import {Component, OnInit} from '#angular/core';
import {DataService} from '../data.service';
import {Product} from '../product';
import * as details from '../productdetail/productdetail.component';
declare var detailDecide: any;
#Component({
selector: 'app-products',
templateUrl: './products.component.html',
styleUrls: ['./products.component.css'],
providers: [DataService]
})
export class ProductsComponent implements OnInit {
productList: Product[] = [];
constructor(private dataService: DataService) {
}
getProduct() {
this.dataService.getproductList()
.subscribe(products => {
this.productList = products;
}
)
};
ngOnInit() {
this.getProduct();
}
decideDetail(a, b) {
detailDecide.decideDetail(a, b);
}
}
js.js
var detailDecide = (function (a, b) {
return {
decideDetail: function (a, b) {
a = b;
alert(b);
}
}
})(detailDecide || {})
productdetail.component.html
<html>
<head>
</head>
<body>
<div class="topnav" id="myTopnav">
Home
Products
<a class="active" href="#">Product Detail</a>
</div>
<p>
productdetail works!
</p>
<div id="product1" #product1> {{details}}</div>
</body>
</html>

Particles.js no particles are loaded in angular

I have added particles.js to an Angular 4 project like mentioned here
Json file is being loaded but I don't see particles on screen
In .ts component :
import { Component, Output, ViewEncapsulation, OnInit } from '#angular/core';
import { MnFullpageOptions, MnFullpageService } from 'ngx-fullpage';
declare var particlesJS: any;
#Component({
selector: 'app-root',
encapsulation: ViewEncapsulation.None,
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
title = 'app';
#Output() public options: MnFullpageOptions = new MnFullpageOptions({
autoScrolling: true,
controlArrows: false,
});
ngOnInit() {
particlesJS.load('particles-js', 'assets/particlesjs-config.json', console.log('callback - particles.js config loaded'));
}
constructor() { }
}
Html file :
<div id="particles-js" style="border:2px solid black; background-color:red">
<div class="menu-wrapper">
</div>
<div id="content-wrapper" [mnFullpage]="options" [mnFullpageNavigation]="true" [mnFullpageKeyboardScrolling]="true" [mnFullpageSlidesNavigation]="true" mnFullpageSlidesNavPosition="bottom">
<div class="section welcome-section fp-section fp-table ">
<div class="fp-tableCell ">
<div id="presentation" class="example-card" fxLayout="row">
<app-slide-presentation>
</app-slide-presentation>
</div>
</div>
</div>
<div class="section welcome-section fp-section fp-table">
<div class="fp-tableCell">
<div id="formation" class="example-card" fxLayout="row" fxLayoutAlign="center center">
<app-formation>
</app-formation>
</div>
</div>
</div>
<div class="section welcome-section fp-section fp-table">
<div fxLayout="row" class="fp-tableCell " style="height:100%; width:60%; overflow:hidden; margin:auto ; background-color:white ">
<div class="slide" >
<app-competences1>
</app-competences1>
<div class="slide" style="background-color:white">
>
</div>
<div class="slide">
</div>
<div class="slide">
</div>
<div class="slide">
</div>
</div>
</div>
</div>
</div>
</div>
In console I get callback message :
callback - particles.js config loaded
I have initiated a new project where everything is being working :
in ts component file :
import { Component, Input, Output, OnInit, ViewEncapsulation } from '#angular/core';
declare var particlesJS: any;
#Component({
selector: 'app-root',
encapsulation: ViewEncapsulation.None,
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
title = 'app';
ngOnInit() {
particlesJS.load('particles-js', 'assets/particlesjs-config.json', null);
}
}
in html :
<div id="particles-js"></div>
particles are loading perfectly.
I don't see the difference between 2 examples.
Adding "background-color" to 'particles-js' container worked for me.
#home.component.html:
<div id="particles-js"></div>
#home.component.scss:
#particles-js {
height: 100vh;
background-color: black;
}

Categories