angular 2 change position to fixed on scroll - css

I have a left sidebar with position fixed. what I want to achieve is that when I scroll like about 50 or 60 pixel the position of the left sidebar should be changed to fixed.
Left-sidebar.component.ts
import { Component } from '#angular/core';
#Component({
moduleId: module.id,
selector: 'left-sidebar',
templateUrl: 'left-sidebar.html',
styleUrls: ['left-sidebar.scss']
})
export class LeftSideBarComponent {
}
left-sidebar.html
<div class="col-sm-2 left-nav">
</div>
css
.left-nav {
position: absolute;
background: #424242;
height: 100%;
overflow: auto;
padding: 0;
z-index: 1;
}
How to change position of left sidebar from absolute to fixed on scroll?

I suggest you make use of the #HostListner decorator to listen to the scroll event just like this:
import { Inject, HostListener } from "#angular/core";
import { DOCUMENT } from "#angular/platform-browser";
#Component({
moduleId: module.id,
selector: 'left-sidebar',
templateUrl: 'left-sidebar.html',
styleUrls: ['left-sidebar.scss']
})
export class LeftSideBarComponent {
public fixed: boolean = false;
constructor(#Inject(DOCUMENT) private doc: Document) {}
#HostListener("window:scroll", [])
onWindowScroll() {
let num = this.doc.body.scrollTop;
if ( num > 50 ) {
this.fixed = true;
}else if (this.fixed && num < 5) {
this.fixed = false;
}
}
add the .fixed css to your scss file then in your template, you do the following:
<div class="col-sm-2 left-nav" [class.fixed]="fixed">
</div>

I'm using Angular 4 and that solution didn't worked out for me, I tried a different aproach, because num was returning 0 on scroll. ¯_(ツ)_/¯.
I hope this will work out for you as well.
import { Inject, HostListener } from "#angular/core";
#HostListener("window:scroll", ['$event'])
onWindowScroll($event:any) {
let top = window.scrollY;
if (top > 30) {
this.fixed = true;
console.log(top);
} else if (this.fixed && top < 5) {
this.fixed = false;
console.log(top);
}
}
.fixed {
#extend .bg-white;
position: fixed;
top: 80px;
z-index: 999;
}
<div class="container" [class.fixed]="fixed">
<div class="row">
<div class="col-12">
<div ngbDropdown class="dropdown custom-dropdown">
<a class="dropdown-toggle" id="dropdownBasic1" ngbDropdownToggle>Toggle dropdown</a>
<div ngbDropdownMenu aria-labelledby="dropdownBasic1">
<a class="dropdown-item">Action - 1</a>
<a class="dropdown-item">Another Action</a>
<a class="dropdown-item">Something else is here</a>
</div>
</div>
</div>
</div>
</div>

Related

How to change the sticky header background color on scroll in angular 11

Tried to change the background color on scroll to the sticky header but not working. How to do it? when I scroll to the bottom of the body I need to change the header background color. How to do it?
app.component.html
<div class="header sticky">
</div>
app.component.css
.sticky {
position: -webkit-sticky;
position: sticky;
top: 0px;
}
Demo: https://stackblitz.com/edit/sticky-header-hyibz9?file=app%2Fheader%2Fheader.component.css
You can use ngClass for this and HostListener to check if user scrolled at the buttom
html
<div class="header sticky" [ngClass]="isBottom ? 'bottom' : 'top'">
</div>
ts
import { Component, OnInit, HostListener } from '#angular/core';
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
isBottom: boolean;
constructor() {}
ngOnInit() {}
#HostListener('window:scroll', [])
onScroll(): void {
if (window.innerHeight + window.scrollY >= document.body.offsetHeight) {
this.isBottom = true;
} else {
this.isBottom = false;
}
}
}
css
.sticky {
position: -webkit-sticky;
position: sticky;
top: 0px;
}
.header {
height: 50px;
}
.top {
background-color: blue;
}
.bottom {
background-color: yellow;
}
import { Component, OnInit, HostListener } from '#angular/core';
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
isBottom: boolean;
constructor() {}
ngOnInit() {}
#HostListener('window:scroll', [])
onScroll(): void {
if (window.innerHeight + window.scrollY >= document.body.offsetHeight) {
this.isBottom = false;
} else if (window.scrollY) {
this.isBottom = false;
} else {
this.isBottom = true;
}
}
}

how to remove the height between these cards

The height of these cards are variable here I'm using angular material library and bootstrap
I need to reduce the horizontal space between the cards
you can see the cards iron throne and woman's image have taken too much space between them
this is the HTML of item-list component, I'm using Bootstrap and angular material
<div class="row">
<app-item *ngFor="let item of items" [item]="item"></app-item>
</div>
here's the ts code
import {Component, OnDestroy, OnInit} from '#angular/core';
import {Subscription} from "rxjs";
import {Item} from "../../models/item.model";
import {ItemsService} from "../items.service";
#Component({
selector: 'app-item-list',
templateUrl: './item-list.component.html',
styleUrls: ['./item-list.component.css']
})
export class ItemListComponent implements OnInit, OnDestroy {
items: Item[] = [];
isLoading = false;
totalItems = 0;
// itemsPerPage = 2;
// currentPage = 1;
// pageSizeOptions = [1, 2, 5, 10];
private itemsSub: Subscription;
constructor(private itemsService: ItemsService) {
}
ngOnInit(): void {
this.isLoading = true;
this.itemsService.getItems();
this.itemsSub = this.itemsService.itemsUpdateListener.subscribe(items => {
this.isLoading = false
this.items = items
})
}
ngOnDestroy(): void {
this.itemsSub.unsubscribe();
}
}
here's the HTML of ItemComponent
<div class="col-lg-3 col-md-4 col-sm-6">
<div class="card" style="width: 18rem;">
<a routerLink="">
<div class="card-img-wrap"><img class="card-img-top" [src]="item.imagePath" [alt]="item.title"></div>
</a>
<div class="card-body">
<span class="card-title">{{item.title}}</span>
<br>
<span class="card-text" style="margin-right: 3px">Rs. {{item.price}}</span>
</div>
</div>
</div>
in the ts of itemComponent there is only one property
#Input() item: Item;
and here's the css of ItemComponent
.card-img-wrap {
overflow: hidden;
position: relative;
}
.card-img-wrap:after {
content: '';
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(255,255,255,0.2);
opacity: 0;
transition: opacity .6s ease-in-out;
}
.card-img-wrap img {
transition: transform .6s ease-in-out;
width: 100%;
}
.card-img-wrap:hover img {
transform: scale(1.1) ;
}
.card-img-wrap:hover:after {
opacity: 0.5;
}

Angular: animation display card on top of another card

Im using angular animation builder for creating an animation. I have a grid list with a list of cards. When i click on a button ,i want another div to come on top of the initial card (float in from the left to cover the first card
) .As of now,the div comes in with the animation ,but is showing up on side of the initial card.I have made a stackblitz example to show the current progress.Here is my stackblitz:
https://stackblitz.com/edit/angular-ty4rfh
Also pasting the code here:
import { Component,OnInit,ElementRef } from '#angular/core';
import { trigger, state, style, transition, animate, AnimationBuilder, AnimationPlayer } from '#angular/animations';
export class Asset
{
constructor(public name:string,public description:string){};
}
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular';
assets:Asset[]=[];
cards=[];
private player: AnimationPlayer;
constructor(private animationBuilder:AnimationBuilder,
private elRef:ElementRef
){}
ngOnInit(){
this.setAssets();
this.setswitch();
}
setAssets(){
this.assets.push(new Asset("Asset1","Latest1"));
this.assets.push(new Asset("Asset2","Latest2"));
this.assets.push(new Asset("Asset3","Latest3"));
this.assets.push(new Asset("Asset4","Latest4"));
this.assets.push(new Asset("Asset5","Latest5"));
this.assets.push(new Asset("Asset6","Latest6"));
this.assets.push(new Asset("Asset7","Latest7"));
this.assets.push(new Asset("Asset8","Latest8"));
this.assets.push(new Asset("Asset9","Latest9"));
for(var i=0; i<this.assets.length;i++){
console.log(this.assets[i].name);
}
}
setswitch() {
for (let i = 0; i < this.assets.length; i++) {
let cardshow = {
id: i.toString(),
isShow : false
};
this.cards.push(cardshow);
}
console.log(this.cards);
}
animate(i){
this.cards[i].isShow=true;
let animationFactory;
animationFactory = this.animationBuilder
.build([
style({ width: '0' }),
animate(200, style({ width: 200 }))
]);
let elem:Element = document.getElementById("div"+(i));
console.log("Elament",elem);
console.log("INDEX",i);
this.player = animationFactory.create(elem);
this.player.play();
}
}
html:
<div>
<mat-grid-list cols="3" rowHeight="3:1">
<mat-grid-tile *ngFor="let asset of assets; index as i">
<div class="border">
<p>{{asset.name}} </p>
<p>{{asset.description}} </p>
<button (click)="animate(i)">click</button>
</div>
<div [ngClass]="!cards[i].isShow?'hide':''" id="{{'div'+i}}" class="border" >
<p>{{asset.description}} </p>
<button>click</button>
</div>
</mat-grid-tile>
</mat-grid-list>
</div>
css:
p {
font-family: Lato;
}
.border{
border:1px solid black;
padding-left: 20px;;
padding-right:20px;
}
.hide{
display:none;
}
EDIT: I need the other card to be completely hidden under the incoming card.Also after clicking on the button inside the incoming card, the animation should be undone(The card should retract back). Also what I'm doing now is increasing the width. What i expect is that the new card should come in from the left sort of like as we see in a drawer
check this stackblitz
app.component.css to be:
p {
font-family: Lato;
}
.border{
border:1px solid black;
padding-left: 20px;;
padding-right:20px;
background: #ffe6ea;
}
.hide{
display:none;
}
.borderPopUp{
padding-left: 20px;;
padding-right:20px;
position:absolute;
background:#d3d3d3d4;
animation: openLikeDrawer 800ms ease-in-out;
width:50%;
left:20%;
}
#keyframes openLikeDrawer{
from {left:0px; }
to { left: 20%; }
}
app.component.html to be :
<div>
<mat-grid-list cols="3" rowHeight="3:1">
<mat-grid-tile *ngFor="let asset of assets; index as i">
<div class="border">
<p>{{asset.name}} </p>
<p>{{asset.description}} </p>
<button (click)="asset.isShow = true">click</button>
</div>
<div *ngIf="asset.isShow" class="borderPopUp" >
<p>{{asset.description}} </p>
<button (click)='asset.isShow = false'>click</button>
</div>
</mat-grid-tile>
</mat-grid-list>
</div>
This is my final solution:
import { Component, OnInit } from '#angular/core';
import { LearningContentService } from '../../../service/learningcontent.service';
import { ActivatedRoute } from '#angular/router'
import { trigger, style, transition, animate, keyframes, query, stagger } from '#angular/animations';
export class Asset {
name: string;
description: string;
cardtoggle:boolean=false;
constructor(rawObj: any) {
this.name = rawObj.name;
this.description = rawObj.description;
this.cardtoggle = rawObj.cardtoggle;
}
}
#Component({
selector: 'app-catalogue',
templateUrl: './catalogue.component.html',
styleUrls: ['./catalogue.component.scss'],
animations: [
trigger('listAnimation', [
transition('* => *', [
query(':enter', style({ opacity: 0 }), { optional: true }),
query(':enter', stagger('50ms', [
animate('1s ease-in', keyframes([
style({ opacity: 0, transform: 'translateY(-75%)', offset: 0 }),
style({ opacity: .5, transform: 'translateY(35px)', offset: 0.3 }),
style({ opacity: 1, transform: 'translateY(0)', offset: 1.0 }),
]))]), { optional: true })
])
],
),
]
})
export class CatalogueComponent implements OnInit {
assets: Array<Asset> = [];
constructor(private route: ActivatedRoute,
private learningService: LearningContentService,
) {
}
ngOnInit() {
this.loadAssets();
}
loadAssets() {
this.learningService.assets().subscribe((res: any) => {
const datas: Array<any> = res;
datas.forEach(asset => this.assets.push(new Asset(asset)));
console.log(this.assets);
});
}
animate(asset) {
asset.cardtoggle = true;
}
close(asset) {
asset.cardtoggle = false;
}
}
html:
<div fxLayout="column">
<div fxLayout="row">
<p class="page-heading" fxFlex="80%">Catalogue</p>
<div class="page-content-filter" fxLayoutAlign="end">
<button mat-button class="search-btn"><i class="material-icons"> search </i></button>
<input class="form-filter" matInput placeholder="Search...">
</div>
</div>
<mat-grid-list gutterSize="20px" cols="3" rowHeight="3:1" [#listAnimation]="assets.length">
<mat-grid-tile *ngFor="let asset of assets">
<div class="full-width white">
<div class="padding20px" fxLayout="column" fxLayoutGap="15px">
<div fxLayout="row" fxLayoutGap="15px">
<img fxFlex="10" style="width:50px;height:50px;" src="../../../../assets/images/images.jpeg" mat-card-image>
<b fxFlex="100">{{asset.name}}</b>
<mat-icon fxLayoutAlign="end end" class="small-icon pointer" (click)="animate(asset)">spa</mat-icon>
</div>
<div fxLayout="row" fxLayoutGap="10px">
<mat-icon class="small-icon">person</mat-icon>
<p class="small-heading"> Mohit Harshan</p>
<mat-divider vertical="true"></mat-divider>
<mat-icon class="small-icon">play_arrow</mat-icon>
<p class="small-heading">Video</p>
<mat-divider vertical="true"></mat-divider>
<mat-icon class="small-icon">face</mat-icon>
<p class="small-heading">5 points</p>
</div>
<mat-progress-bar class="progress" mode="determinate" value="40"></mat-progress-bar>
</div>
</div>
<div class="pull-right" [ngClass]="{'show': asset.cardtoggle }" class="card2">
<div class="padding20px" fxLayout="column" fxLayoutGap="15px">
<div fxLayout="row" fxLayoutGap="15px">
<b fxFlex="100" class="small-heading">{{asset.name}}</b>
<mat-icon fxLayoutAlign="end end" class="small-icon pointer" (click)="close(asset)">clear</mat-icon>
</div>
<div fxLayout="row" fxLayoutGap="10px">
<p class="small">{{asset.description}}</p>
</div>
<div fxLayout="row" fxLayoutGap="10px" fxFLex="100" fxLayoutAlign="end end">
<button fxFLex="100" mat-button class="green-button" >View Details</button>
</div>
</div>
</div>
</mat-grid-tile>
</mat-grid-list>
</div>
css:
.card2{
position:absolute;
z-index: 20;
background: white;
padding-left: 0px;
padding-right:0px;
width:100%;
height:100%;
margin-left: 100%;
transition: margin-left .5s ease-in-out;
}
.show {
margin-left: 0%;
}
.green-button{
border:1px solid lightgreen;
border-radius: 10%;
font-size: 10px;
color:green;
}

maps are overlapping in view?

I have 2 components in my angular application each one having map to show from mapbox, one of the component is as shown below
Component
import { Component, OnInit } from '#angular/core';
import * as mapboxgl from 'mapbox-gl';
#Component({
selector: 'app-acs',
templateUrl: './acs.component.html',
styleUrls: ['./acs.component.css']
})
export class AcsComponent implements OnInit {
constructor() { }
ngOnInit() {
mapboxgl.accessToken = 'api-key';
let mapbx = new mapboxgl.Map({
container: 'mapbx',
style: 'styles',
zoom: 5,
center: [-80.118, 25.897]
});
}
}
component html
<div class="col-md-12 contentDiv">
<div class="row">
<h4 class="center subHeader">ACS</h4>
</div>
<div class="row">
<div class="mapArea">
<div id='map'></div>
</div>
</div>
</div>
and i have another component with similar code
global css
.contentDiv{
border: 1px solid #b1b0b0;
margin: 3px;
height: auto;
}
.subHeader{
border-bottom: 1px solid #b1b0b0;
margin: 2px 0px;
padding: 5px;
}
.region{
font-size: 16px;
}
.regionDropDown{
display: inline-block;
width: auto;
margin: 0px 10px;
}
.mapArea{
background: #e8e5e5;
margin: 10px;
height: 80vh;
}
#map {
width: auto;
height: inherit;
position: relative;
}
these maps are creating the canvas and if i make display:none of 1st canvas in chrome dev tools am able to see the hidden map.
how can i separately display 2 maps?
I believe you need to use different id:
<div class="col-md-12 contentDiv">
<div class="row">
<h4 class="center subHeader">ACS</h4>
</div>
<div class="row">
<div class="mapArea">
<div [id]="randomId"></div>
</div>
</div>
</div>
Generate random ID:
import { Component, OnInit } from '#angular/core';
import * as mapboxgl from 'mapbox-gl';
#Component({
selector: 'app-acs',
templateUrl: './acs.component.html',
styleUrls: ['./acs.component.css']
})
export class AcsComponent implements OnInit {
public randomId: string;
constructor() { }
ngOnInit() {
mapboxgl.accessToken = 'api-key';
this.randomId = Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5);
setTimeout(() => {
let mapbx = new mapboxgl.Map({
container: this.randomId,
style: 'styles',
zoom: 5,
center: [-80.118, 25.897]
});
}, 0);
}
}
Hope this will help you.
Try to give different ids for you selectors
component 1
<div class="col-md-12 contentDiv">
....
<div id='mapa'></div>
....
</div>
component 2
<div class="col-md-12 contentDiv">
....
<div id='mapb'></div>
....
</div>
as well in global css
#mapa {
width: auto;
height: inherit;
position: relative;
}
#mapb {
width: auto;
height: inherit;
position: relative;
}
Hope it helps

Dynamic styling not working in Angular2

Following is my working code, which is not giving any error in console and printing the array items and test heading as expected. BUT somehow dynamic background styling in not working, Let me know what I am doing wrong here.
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
template: `
<h1>{{name}}</h1>
<div class="one" *ngFor="let item of colArr" style="background: {{item}};">{{item}}</div>
`,
styles: [`
.one {
width: 100%;
text-align: center;
padding: 10px;
margin: 5px;
}
`]
})
export class HomeComponent {
public name = 'test';
public colArr = ['#111111', '#222222', '#333333', '#444444', '#555555', '#666666', '#777777', '#888888', '#999999'];
}
Following is the output I am getting -
Direct binding to style is discouraged (doesn't work well on all browsers). Use instead
<div class="one" *ngFor="let item of colArr" [ngStyle]="{background: item}">{{item}}</div>
or
<div class="one" *ngFor="let item of colArr" [style.background]="item">{{item}}</div>

Resources