ANGULAR - Cursor 'resize' on drag - html

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;
}

Related

On scroll change class Angular

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.

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

Implement Three Section header with sticky sections

I have to implement a 3 section sticky header. The first section is a header part, the second section is a hero component, the 3d part is a subheader. When the user starts to scroll the page, 2nd section (hero component) disappears behind the header. The 3d section sticks to the header. If the user continues scrolling and scrolled 30% of the page, the 3d section also starts to hide behind the header.
I have some questions:
1) How to better organize the code (split the header into components)
2) And how to implement the described logic using Angular 8?
Maybe there are some examples with Angular 2+
I have implemented a subheader that hides the hero part on scroll
HTML
<div class="subheader__wrapper">
<div class="subheader subheader__sticky"
[ngClass]="getSubheaderClassTop()"
>
<div class="row align-middle align-justify subheader-row-height u-grid-full-width">
<cc-breadcrumb class="columns"></cc-breadcrumb>
<a *ngIf="!noBackButton" (click)="onBack()"
id="form-dropdown-back-link"
class="columns small-1 mos-u-text-size--md mos-u-color-text--white"
>
<my-icon size="lg" icon="keyboard_arrow_left" theme="disabled-light" alt="Back"></my-icon>
<span class="anchor-icon-text-fix">{{ 'subheader.back' | translate }}</span>
</a>
</div>
</div>
</div>
<hero
*ngIf="isHeroVisible"
class="mos-c-position--relative"
[backgroundUrl]="heroImageURL"
[backgroundImage]="gradient"
blendMode="multiply"
backgroundPosition="top"
flexDirection="row"
minHeight="192">
<div *ngIf="!isBlendMode" class="subheader__gradient"></div>
<div class="subheader__content flex-child-grow">
<div class="row x-large-row c-position--relative">
<div class="column medium-8 small-12 u-color-text--white x-large-6">
<h2 class="o-subheader-2" data-id="subheader">
{{ heroSubtitle }} {{heroSubtitleDate}}
</h2>
<h2 class="mos-o-display-2" data-id="header">
{{ heroTitle }}
</h2>
<hr class="subheader__separator c-hero--separator">
</div>
</div>
</div>
</hero>
CSS
:host {
display: block;
}
.subheader {
width: 100%;
height: 52px;
background-color: color(sapphire, 500);
z-index: 100;
&-row-height {
height: 52px;
}
&__sticky {
position: fixed;
}
&__gradient {
pointer-events: none;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image: linear-gradient(to right, rgba(0,0,0,0.8) 0%, rgba(255, 255, 255, 0.2) 100%);
}
&__content {
z-index: 1;
width: 100%;
justify-self: center;
.subheader__separator {
margin-right: auto;
}
}
}
.circle-step-position {
position: absolute;
top: 0;
left: 0;
z-index: 2;
}
JS
import {
AfterViewInit,
Component,
EventEmitter,
Input,
NgZone,
Output,
ElementRef,
ChangeDetectorRef,
ChangeDetectionStrategy,
} from '#angular/core';
import { TranslateService } from '#ngx-translate/core';
import { pathOr } from 'ramda';
import { AutoUnsubscribe } from '../shared/auto-unsubscribe.decorator';
import { WindowRef } from '../services/api/aot-ref/windowRef';
import { fromEvent } from 'rxjs';
import { takeUntil, distinctUntilChanged, map, throttleTime, startWith } from 'rxjs/operators';
#Component({
selector: 'cc-section-subheader',
templateUrl: './subheader.component.html',
styleUrls: ['./subheader.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
#AutoUnsubscribe
export class SubheaderComponent implements AfterViewInit {
componentDestroy;
#Input() subheader: string;
#Input() header: string;
#Input() country: string;
#Input() noBackButton: boolean;
#Input() heroTitle: string;
#Input() heroSubtitle: string;
#Input() heroSubtitleDate: string;
#Input() heroImageURL: string;
#Input() isHeroVisible = false;
#Input() isSummary = false;
#Input() isFileUpload = false;
#Input() isValidateData = false;
#Input() isJobMatch = false;
#Input() isAggregateValidation = false;
#Output() back = new EventEmitter<void>();
adjustSubheader = true;
lastScroll = 0;
lastHeight: string;
isExpanded = false;
isBlendMode = false;
constructor(
private ngZone: NgZone,
private window: WindowRef,
private subheaderElement: ElementRef,
private translate: TranslateService,
private cdr: ChangeDetectorRef,
) {
this.isBlendMode = !!('backgroundBlendMode' in document.body.style);
}
get areButtonsDisabled() {
return true;
}
get gradient(): string {
return this.isBlendMode
? 'linear-gradient(to right, black 0%, white 100%)'
: null;
}
ngAfterViewInit() {
this.ngZone.runOutsideAngular(() => {
fromEvent(this.window.nativeWindow, 'scroll')
.pipe(
map(() => this.isHeaderVisible()),
distinctUntilChanged(),
takeUntil(this.componentDestroy())
)
.subscribe((isHeaderVisible: boolean) => {
this.ngZone.run(() => {
this.adjustSubheader = isHeaderVisible;
this.cdr.detectChanges();
});
});
});
this.ngZone.runOutsideAngular(() => {
fromEvent(this.window.nativeWindow, 'resize').pipe(
startWith(null),
throttleTime(200),
takeUntil(this.componentDestroy()),
)
.subscribe(() => this.updateWrappersHeight());
});
}
/**
* Since sub-header has position set as fixed it removes the element from the normal document
* flow. To properly align content under it we need to set sub-header's height equal to
* sub-header.
*/
updateWrappersHeight(): void {
const el = this.subheaderElement.nativeElement;
const headerHeight = this.window.nativeWindow.getComputedStyle(el.querySelector('.subheader')).height;
if (headerHeight !== this.lastHeight) {
this.lastHeight = headerHeight;
el.querySelector('.subheader__wrapper').style.height = this.lastHeight;
}
}
onBack() {
this.back.emit();
}
getHtmlElementOffset(element: HTMLElement, offset = 0): number {
if (!element.offsetParent) {
return offset;
}
return this.getHtmlElementOffset(
element.offsetParent as HTMLElement,
offset + pathOr(0, ['offsetParent', 'offsetTop'], element),
);
}
getElementOffset(element: ElementRef): number {
if (!element) {
return 0;
}
return this.getHtmlElementOffset(
element.nativeElement,
element.nativeElement.offsetTop,
);
}
isHeaderVisible() {
const scrollTop = this.window.nativeWindow.pageYOffset;
const down = scrollTop > this.lastScroll;
const top = this.getElementOffset(this.subheaderElement);
this.lastScroll = scrollTop;
return scrollTop <= top;
}
getSubheaderClassTop(): string {
return this.adjustSubheader
? ''
: 'subheader__sticky--fixed-to-top';
}
}

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);
}
}