On scroll change class Angular - html

HTML
<ion-app>
<ion-content>
<div #scrolledToElement class="second-block" [ngClass]="flag ? 'red' : 'green' "></div>
</ion-content>
</ion-app>
CSS
.second-block {
margin-bottom: 500px;
height: 250px;
width: 100%;
}
.red {
background: red;
}
.green {
background: green;
}
TS
import { Component, VERSION, HostListener, ElementRef, ViewChild } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
name = 'Ionic 6.2 Angular ' + VERSION.major;
constructor() {}
flag = false;
#ViewChild("scrolledToElement", { static: false })
scrolledToElement: ElementRef;
#HostListener("window:scroll", ["$event"])
onScroll(event) {
if (window.scrollY > this.scrolledToElement.nativeElement.offsetTop) {
this.flag = true;
console.log("flag", this.flag);
}
else
{
this.flag = false;
}
}
}
How to change the class on scroll?
I want a solution for the latest Angular version
stackblitz : https://stackblitz.com/edit/ionic6-angular13-wsjtit?file=src%2Fapp%2Fapp.component.html
Any solution, please?
Working URL :
https://stackblitz.com/edit/angular-ivy-xhb4yw?file=src%2Fapp%2Fapp.component.ts,src%2Fapp%2Fapp.component.html,src%2Fapp%2Fapp.component.css,src%2Findex.html,src%2Fapp%2Fhello.component.ts,src%2Fapp%2Fapp.module.ts

#HostListener('window:scroll', ['$event']) works fine in the web browser. As you are using ionic you need to use their custom events provided in the documentation for ion-content.
<ion-content [scrollEvents]="true"
(ionScrollStart)="logScrollStart($event)"
(ionScroll)="logScrolling($event)"
(ionScrollEnd)="logScrollEnd($event)">
</ion-content>
Implement above methods in app.component.ts file. You can define your change class logic logScrolling method. Instead of window.scrollY use event.detail.scrollTop from the event provided by ionScroll.
logScrollStart(event) {
console.log("logScrollStart : When Scroll Starts", event);
}
logScrolling(event) {
console.log("logScrolling : When Scrolling", window.scrollY);
console.log("Offset", this.scrolledToElement.nativeElement.offsetTop);
if (event.detail.scrollTop > this.scrolledToElement.nativeElement.offsetTop) {
this.flag = true;
console.log('flag', this.flag);
} else {
this.flag = false;
}
}
logScrollEnd(event) {
console.log("logScrollEnd : When Scroll Ends", event);
}
Here is the forked stackblitz repository.

Related

ANGULAR - Cursor 'resize' on drag

I am writing, because I have a problem with my resizeable component.
I want have only cursor 'resize' instead of 'not-allowed' on drag.
Could you please for your help?
Component
resizeable.component.ts
import { Component, ContentChild, ElementRef, OnDestroy, ViewChild } from '#angular/core';
import { Subject } from 'rxjs';
#Component({
selector: 'app-resizeable',
templateUrl: './resizeable.component.html',
styleUrls: ['./resizeable.component.scss']
})
export class ResizeableComponent implements OnDestroy {
#ViewChild('line') line: ElementRef;
#ContentChild('content') content: ElementRef;
initHeight: number;
initPositionY: number;
private unsubscribe$: Subject<void> = new Subject<void>();
ngOnDestroy(): void {
this.unsubscribe$.next();
this.unsubscribe$.complete();
}
onDrag(event: DragEvent): void {
const height = this.initHeight + (event.clientY - this.initPositionY);
this.content.nativeElement.style.height = `${height}px`;
event.preventDefault();
}
onDragEnd(event: DragEvent): void {
event.preventDefault();
}
onDragStart(event: DragEvent): void {
event.dataTransfer.effectAllowed = 'move';
this.initHeight = this.content.nativeElement.getBoundingClientRect().height;
this.initPositionY = event.clientY;
}
}
resizeable.component.html
<ng-content></ng-content>
<div
#line
*ngIf="content"
(dragend)="onDragEnd($event)"
(dragstart)="onDragStart($event)"
(drag)="onDrag($event)"
class="break-line"
draggable="true"
>
<hr />
</div>
resizeable.component.scss
.break-line {
cursor: row-resize;
height: 0.5rem;
margin-top: 3rem;
width: 100%;
-webkit-user-drag: element;
-webkit-user-select: none;
}

How to change this template driven form to Reactive form in Angular?

How to change this template driven form to Reactive form? I want to change this template driven form to reactive form. What changes shall I do to change it to Reactive form? The code is complete no other modification is required? Can someone please help me with this, I am attaching all the required codes. What things we should keep in mind while changing to reactive form, also why reactive form is preferred over template driven form?
HTML code
<html>
<body>
<nav>
<div class = "navbar-header">
Image Change on clicking Enter in TextBox
<input class = "col" type = "text" readonly value ="{{imgNumber}}/3 {{cityImageId}}">
</div>
</nav>
<div class = "textarea" contenteditable #scrollDiv [scrollTop]="scrollDiv.scrollHeight" wrap="hard">
<img contenteditable="false" [src]="imagePath" width = "1090px" height = "440"/>
</div>
<form>
<div>
<input type = "text" class="col2" [(ngModel)]="pincode" (keyup.enter)="generatecityDetailArray()" maxlength="6" [ngModelOptions]="{standalone: true}"/>
</div>
</form>
<div>
<input type = "label" class = "col3" value = "Pin Code" readonly />
</div>
</body>
</html>
CSS code
nav {
background-color:black;
border : 0;
}
.navbar-header{
text-align: center;
}
.navbar-header{
color:white;
}
.col{
margin-left: 950px;
text-align: right;
border : 0;
background-color:rgb(160,0,0);
}
.textarea{
overflow: scroll;
height: 400px;
width:1090px;
background-color:white;
margin-left: 100px;
margin-top: 50px;
object-fit: none;
object-position: 1000px 200px;
}
.col2{
width:230px;
height: 30px;
margin-top: 20px;
margin-left: 950px;
}
.col3{
width:230px;
height: 30px;
margin-top: 20px;
margin-left: 950px;
}
TypeScript Code
import { Component, OnInit } from '#angular/core';
import { CityClassificationService } from 'src/app/service/city-classification.service';
#Component({
selector: 'app-city-classification',
templateUrl: './city-classification.component.html',
styleUrls: ['./city-classification.component.css']
})
export class CityClassificationComponent implements OnInit {
imgNumber : number =-1;
cityImageId : number = -1;
imagePath : string ='';
pincode:string='';
curImageNumber:number=0;
imageDetails:{imageName:string,cityImageId:number,imgNumber:number}[]=[];
cityDetailArray :{ pincode : string; cityImageId : number; imgNumber:number;}[] = [];
constructor(private cityService:CityClassificationService) { }
ngOnInit(): void {
this.imageDetails=this.cityService.getImageObject();
this.getNextImage(this.imageDetails[this.curImageNumber]);
}
getNextImage(imageObj:{imageName:string,cityImageId:number,imgNumber:number}):void{
this.imgNumber= imageObj.imgNumber;this.imagePath=`assets/images/${imageObj.imageName}.png`;this.cityImageId=imageObj.cityImageId;
}
generatecityDetailArray():void{
if(this.pincode=='' || this.pincode.toString().length>6){alert('Enter Valid PinCode');return;};
this.cityDetailArray.push(
{pincode:this.pincode, cityImageId:this.cityImageId, imgNumber:this.imgNumber}
);
this.pincode='';
this.curImageNumber++;
if(this.curImageNumber==this.imageDetails.length){this.submitForm();return;}
this.getNextImage(this.imageDetails[this.curImageNumber]);
}
submitForm(){
//TODO here....
this.cityService.getAPi(this.cityDetailArray);
}
}
Model class
export class CityClassification{
pinCode : string;
cityImageId : number;
imgNumber:number;
constructor(pinCode : string, cityImageId : number,imgNumber:number){
this.pinCode = pinCode;
this.cityImageId = cityImageId;
this.imgNumber = imgNumber;
}
}
Service class
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class CityClassificationService {
imageDetails:{imageName:string,cityImageId:number,imgNumber:number}[]=[
{imageName:'Ghazipur1',cityImageId:101,imgNumber:1},
{imageName:'Nashik2',cityImageId:102,imgNumber:2},
{imageName:'Noida3',cityImageId:103,imgNumber:3}
]
constructor() { }
getAPi(formBody:any){
//API TO SUBMIT FORM.....
console.log('INSIDE SERvice.......',formBody);
}
getImageObject():any{
//API HERE TO GET IMAGE
return this.imageDetails;
}
}
here is a simple code snippet for you,
Lets say you have component name as AppComponent,
import { Component } from '#angular/core';
import {
FormBuilder,
FormGroup,
FormControl,
Validators
} from '#angular/forms';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'stackoverflow-examples';
declare MultipleSelect: any;
textInputForm: FormGroup;
get textInputControl() {
return this.textInputForm.get('textInputControl') as FormControl;
}
constructor(
private fb: FormBuilder
) {
this.textInputForm = new FormGroup(
{
textInputControl: new FormControl('', [Validators.maxLength(6)])
}
);
}
ngOnInit() {
}
onClick(): void{
// Just to show you that form can read the values,
console.log(this.textInputForm.getRawValue());
}
}
Your Html can look like this below,
<form>
<label>
Input Name:
<input type="text" class="col2" [formControl]="textInputControl" maxLength="6"/>
</label>
</form>
<button (click)="onClick()">Click</button>

in dynamic div - on click highlight color

HTML
<div class="nav--small nodeLevel newColor" id="rowItem-{{i}}" *ngFor="let root of rootzTemplates; let i=index" (click)="nodeClickLevel1(root,i)">
<p style="padding: 19px 1px;color: #fff; text-align: center;">
{{root}}
</p>
</div>
CSS
.activeColor {
background-color: grey;
}
JavaScript
constructor(private el: ElementRef) { }
nodeClickLevel1(root, id){
this.myTag = this.el.nativeElement.querySelector("#rowItem-" + id);
this.myTag.classList.remove('activeColor');
this.myTag.classList.add('activeColor');
}
Now div is dynamic, say number of div element is 6, on click event i have to change particular clicked div background-color to grey and rest of color should remain same.
Now if I click on div say 2, only 2nd div has highlight with grey color, rest of the color should remain same and vice versa.
Change your function like this
nodeClickLevel1(root, id){
this.myTag = root
}
change your template code like this
[class.newColor]="root === myTag"
Hope it will solve your problem.
Your code can be much simpler, no need for troublesome ElementRef, no need for index ids, etc.
So here is the code:
//our root app component
import { Component, NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
#Component({
selector: 'my-app',
// templateUrl: "app.html",
template: `
<div class="nav--small nodeLevel newColor" [class.activeColor]="root === myTag" *ngFor="let root of rootzTemplates" (click)="nodeClickLevel1(root)">
<p style="padding: 19px 1px;color: #fff; text-align: center;">{{root}}</p>
</div>
`,
})
export class App {
name: string;
constructor() { }
protected myTag:any;
public rootzTemplates: any[] = ["first", "2nd", "3rd"];
nodeClickLevel1(root){
this.myTag = root;
}
}
#NgModule({
imports: [BrowserModule],
declarations: [App],
bootstrap: [App],
})
export class AppModule {}
and css:
.activeColor {
background-color: grey !important;
}
.nav--small{
background-color: black;
}
Here is the working PLNKR link:
http://plnkr.co/edit/oRZa3E5WtYpusKHd

How to add class on hover of multiple list in angular 8

Here I have some static list. I need to change the class on hover and mouseout of the list individually.But here class is getting changed for all list at a time. Here is code below
home.component.html
<div>
<ul>
<li [ngClass]="color" (mouseover)="changeStyle($event)" (mouseout)="changeStyle($event)">test1</li>
<li [ngClass]="color" (mouseover)="changeStyle($event)" (mouseout)="changeStyle($event)">test2</li>
<li [ngClass]="color" (mouseover)="changeStyle($event)" (mouseout)="changeStyle($event)">test3</li>
<li [ngClass]="color" (mouseover)="changeStyle($event)" (mouseout)="changeStyle($event)">test4</li>
</ul>
</div>
home.component.ts
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
constructor() { }
ngOnInit() {
/* First data */
console.log('hello');
}
color:string = 'red';
changeStyle($event){
this.color = $event.type == 'mouseover' ? 'yellow' : 'red';
}
}
css
.yellow{
border-bottom:1px solid;
}
.red{
background:red;
color:#FFF;
}
You can use $event.target.className. It work for current event class. Try the below solution It will work.
changeStyle($event){
$event.target.className= $event.target.className == 'red' ? 'yellow' : 'red';
}
or
changeStyle($event){
$event.target.className = $event.type == 'mouseover' ? 'yellow' : 'red';
}

Angular: How to make a time signal in

I need to make a traffic light that from 0 to 10 minutes is green from 10 to 20 yellow and from 20 to 30 red, time is by service
So far this is my code
This is the component
import {
Component,
OnInit,
Input
} from '#angular/core';
import {
TiempoService
} from "app/servicios/tiempo.service"
#Component({
selector: 'app-menu',
templateUrl: './menu.component.html',
styleUrls: ['./menu.component.css']
})
export class MenuComponent implements OnInit {
#Input() tiemposervice: TiempoService;
constructor() {}
ngOnInit() {
}
}
This is the HTML
<div class="row">
<div class="small-12 medium-6 columns">
<span>Tiempo transcurrido</span>
<h5>{{tiempoTranscurrido | date:'mm:ss'}}</h5>
</div>
</div>
This is the service
import {
Injectable
} from '#angular/core';
import Rx from 'Rx';
#Injectable()
export class TiempoService {
tiempoTranscurrido: number;
constructor() {}
ngOnInit() {
}
tiempoTotal() {
Rx.Observable.interval(1000).subscribe(segundos => {
this.tiempoTranscurrido = segundos * 1000;
})
}
}
I would greatly appreciate your help.
I suggest you need something like this:
Service:
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs';
#Injectable()
export class LightService {
getLight(interval): Observable<string> {
return Observable.interval(interval)
.timeInterval()
.map(time => {
if(time.value % 3 === 2) {
return 'green';
} else if(time.value % 3 === 0) {
return 'yellow';
} else if (time.value % 3 === 1) {
return 'red';
}
});
}
}
Component:
import { Component, OnInit } from '#angular/core';
import { LightService } from './light.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [ LightService ]
})
export class AppComponent implements OnInit {
light: string = "green";
constructor(private lightService: LightService) {}
ngOnInit() {
this.lightService
.getLight(10000) // 10 seconds interval
.subscribe(light => this.light = light);
}
}
Template:
<h1>
{{ light }}
</h1>
<ul>
<li *ngIf="light === 'green'" class="green"></li>
<li *ngIf="light === 'yellow'" class="yellow"></li>
<li *ngIf="light === 'red'" class="red"></li>
</ul>
Styles:
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
li {
width: 64px;
height: 64px;
border-radius: 50%;
border: 1px solid black;
}
.green {
background-color: green;
}
.yellow {
background-color: yellow;
}
.red {
background-color: red;
}
If you need to show lights only once add take operator:
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs';
#Injectable()
export class LightService {
getLight(interval): Observable<string> {
return Observable.interval(interval)
.timeInterval()
.map(time => {
if(time.value % 3 === 2) {
return 'green';
} else if(time.value % 3 === 0) {
return 'yellow';
} else if (time.value % 3 === 1) {
return 'red';
}
})
.take(2);
}
}