Angular material input number spinner scrolling problem - html

In Chrome, when the mouse is in the input number field in Material, I can scroll the value with my mouse.
I uploaded the code to stackblitz: https://stackblitz.com/edit/angular-bpj321, and I found in Chrome I cannot scroll when the mouse is in the field, but in Firefox, I can scroll.
I do not want to scroll, so how can I prevent this?

I've added these lines in my app.component.ts
#HostListener('mousewheel', ['$event']) onMouseWheelChrome(event: any) {
this.disableScroll(event);
}
#HostListener('DOMMouseScroll', ['$event']) onMouseWheelFirefox(event: any) {
this.disableScroll(event);
}
#HostListener('onmousewheel', ['$event']) onMouseWheelIE(event: any) {
this.disableScroll(event);
}
disableScroll(event: any) {
if (event.srcElement.type === "number")
event.preventDefault();
}
It works.

You could disable the scrolling event on the input manually:
Find the input element:
const input = document.getElementById("your-input");
And disable the wheel default functionality:
input.addEventListener("wheel", function(event) {
event.preventDefault();
});

Related

Custom HTMLElement not bubbling click event

I am dabbling with customerElements:
customElements.define('state-button',
class extends HTMLElement {
constructor(...args) {
super(...args);
this.state = 0;
let o=this;
this.t = {
0:"<button class='btn btn-info'>"+(o.innerHTML)+"</button>",
1:"<button class='btn btn-warning'>Are you sure???</button>",
2:"<button class='btn btn-danger'>Last chance....</button>"
};
this.addEventListener("click", this.handleClick,{capture:false});
}
connectedCallback() {
this.setAttribute("data-toggle", "modal");
this.setAttribute("data-target", "#confirmModal");
this.setAttribute("data-jc_id", this.getAttribute("data-id"));
this.render();
}
render() {
console.debug("state", this.state);
this.innerHTML=this.t[this.state];
}
handleClick(event) {
this.state = (this.state+1) % 3;
this.render();
}
setState(state) {
this.state = state;
this.render();
}
}
);
This is just me testing how it works. The button is supposed to change state AND open modal Bootstrap4 window. But the modal never gets triggered.
If I add super.click(); inside handleClick() it will change state twice (as the event is triggered again).
If I do not addEventListener the Bootstrap 4 modal window triggers just fine. So it appears my event is stopping other events.
return true; at the end of handleClick has no effect.
What am I missing?
I found a way around it to the same effect. But I am sure it is not the correct way of doing it.
When I add the eventlistener this.addEventListener("click", this.handleClick,{once:true}); it will be removed once triggered. This will cause the bootstrap 4 modal window to trigger as well.
Then at the end of handleClick I just add the click event as above again.
As I said - it is a workaround.
I am still interested in why my event stops other click events....

Parent component should be active when angular material dialog is open

I have implemented angular material dialog in my project , I also made the dialog draggable. Everything is working fine. Now I have a new requirement where I should keep parent component active when I open the dialog . Anyone have any idea on how to achieve this ?
you can add a class to disable the particular part based on the dialog.
In your component, you can add a variable to identify the dialog state.
openDialog(): void {
this.dialogActive = true;
const dialogRef = this.dialog.open(DialogOverviewExampleDialog, {
width: '250px',
data: {name: this.name, animal: this.animal},
hasBackdrop: false
});
dialogRef.afterClosed().subscribe(result => {
this.dialogActive = false;
console.log('The dialog was closed');
this.animal = result;
});
}
}
and you can add a class to HTML based on the dialog state.
<div [class.modal-page-disable]="dialogActive"> disable part </div>
<div> enable part </div>
Then finally add the style to disable the part.
.modal-page-disable {
pointer-events: none;
background: transparent;
opacity: 0.5;
}
you can refer the sample code here.

How to assign angular directive to html element by using ElementRef and Renderer2?

I am developing the drag and drop application in Angular 6 and on drop operation, I am creating the new HTML element (elements like 'DIV', 'textarea' etc.), dynamically and assign styles, attributes, default x and y coordinates to it by using ElementRef and Renderer2 features of application and adding the newly created HTML element to parent element on which drop operation is being performed.
I also have an angular directive created which attaches draggable behavior to the newly created HTML element so user can move it anywhere on the parent element. The partial code for directive is given below:
#Directive({
selector: '[appMovable]'
})
export class MovableDirective {
#HostBinding('style.transform') get transform(): SafeStyle {
return this.sanitizer.bypassSecurityTrustStyle(
`translateX(${this.position.x}px) translateY(${this.position.y}px)`);
}
private position = {x: 100, y: 0};
constructor(private sanitizer: DomSanitizer) {
}
#HostListener('dragStart') onDragStart() {
console.log('drag start');
// Code to calculate the start position of the control being dragged....
}
#HostListener('dragMove') onDragMove() {
console.log('drag move');
// Code to calculate the current position of the control while it is being dragged....
}
#HostListener('dragEnd') onDragEnd() {
console.log('drag end');
// Code to calculate the end position of the control being dragged and the the position of the control properly.....
}
}
While I am able to assign the styles, attributes and default x and y coordinates to the newly created element but I am not able to bind the 'appMovable' directive to newly created HTML element. The code to create the HTML element and assigning different attributes to it is as below:
#Directive({
selector: '[appDroppable]'
})
export class DroppableDirective {
constructor(private elementRef: ElementRef, private renderer: Renderer2) {
}
#HostListener('dragover', ['$event'])
public onDragOver(evt) {
evt.preventDefault();
evt.stopPropagation();
}
#HostListener('dragleave', ['$event'])
public onDragLeave(evt) {
evt.preventDefault();
evt.stopPropagation();
}
#HostListener('drop', ['$event'])
public onDrop(evt) {
evt.preventDefault();
evt.stopPropagation();
// Since text element is being dragged so create new textarea html control
const textareaElement = this.renderer.createElement('textarea');
this.renderer.setAttribute(textareaElement, 'placeholder', 'click to add content...');
this.renderer.setAttribute(textareaElement, 'class', 'proInput editing');
this.renderer.setAttribute(textareaElement, 'draggable', 'true');
//Assign the appMovable directive to element
this.renderer.setAttribute(textareaElement, 'appMovable', '');
// this.renderer.appendChild(newDivElement, textareaElement);
this.renderer.appendChild(this.elementRef.nativeElement, textareaElement);
}
}
When I inspect the newly created HTML element in the browser debugger tool, I can see the appMovable directive getting assigned to the HTML element but element does not behave as per the directive assigned to it.
Is there anything else needs to be done or there is any alternate option to get directive work properly with dynamically created HTML elements?

AngularJs - My ui-sref anchor tag can't be cancelled by event.preventDefault()

I have this tag:
<a ui-sref="MyModule">My Module</a>
When I click on the link, this will be executed:
$scope.$on("$locationChangeStart", function (event) {
if (!confirm('You have unsaved changes, continue?')) {
event.preventDefault();
}
});
But still my view will switch to MyModule interface.
try using this:-
$scope.$on("$stateChangeStart", function (event) {
if (!confirm('You have unsaved changes, continue?')) {
event.preventDefault();
}
});
You are using UI-router. which is state based.

How to get on scroll events?

I need to get scroll events from a div with overflow: scroll in my Angular 2 app.
It seems onscroll event do not works on Angular 2.
How could I achieve that?
// #HostListener('scroll', ['$event']) // for scroll events of the current element
#HostListener('window:scroll', ['$event']) // for window scroll events
onScroll(event) {
...
}
or
<div (scroll)="onScroll($event)"></div>
You could use a #HostListener decorator. Works with Angular 4 and up.
import { HostListener } from '#angular/core';
#HostListener("window:scroll", []) onWindowScroll() {
// do some stuff here when the window is scrolled
const verticalOffset = window.pageYOffset
|| document.documentElement.scrollTop
|| document.body.scrollTop || 0;
}
for angular 4, the working solution was to do inside the component
#HostListener('window:scroll', ['$event']) onScrollEvent($event){
console.log($event);
console.log("scrolling");
}
Listen to window:scroll event for window/document level scrolling and element's scroll event for element level scrolling.
window:scroll
#HostListener('window:scroll', ['$event'])
onWindowScroll($event) {
}
or
<div (window:scroll)="onWindowScroll($event)">
scroll
#HostListener('scroll', ['$event'])
onElementScroll($event) {
}
or
<div (scroll)="onElementScroll($event)">
#HostListener('scroll', ['$event']) won't work if the host element itself is not scroll-able.
Examples
Using Event Binding
Using HostListener
Alternative to #HostListener and scroll output on the element I would suggest using fromEvent from RxJS since you can chain it with filter() and distinctUntilChanges() and can easily skip flood of potentially redundant events (and change detections).
Here is a simple example:
// {static: true} can be omitted if you don't need this element/listener in ngOnInit
#ViewChild('elementId', {static: true}) el: ElementRef;
// ...
fromEvent(this.el.nativeElement, 'scroll')
.pipe(
// Is elementId scrolled for more than 50 from top?
map((e: Event) => (e.srcElement as Element).scrollTop > 50),
// Dispatch change only if result from map above is different from previous result
distinctUntilChanged());
To capture scroll events and see which of the scroll event is being called, you have to use host listener who will observe the scroll behavior and then this thing will be detected in the function below the host listener.
currentPosition = window.pageYOffset;
#HostListener('window:scroll', ['$event.target']) // for window scroll events
scroll(e) {
let scroll = e.scrollingElement.scrollTop;
console.log("this is the scroll position", scroll)
if (scroll > this.currentPosition) {
console.log("scrollDown");
} else {
console.log("scrollUp");
}
this.currentPosition = scroll;
}
Check the multiple examples as mention on this URL.
I will recommend the method 3,
https://itnext.io/4-ways-to-listen-to-page-scrolling-for-dynamic-ui-in-angular-ft-rxjs-5a83f91ee487
#Component({
selector : 'ngx-root',
templateUrl : './app.component.html',
styleUrls : [ './app.component.scss' ],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent implements OnDestroy {
destroy = new Subject();
destroy$ = this.destroy.asObservable();
constructor() {
fromEvent(window, 'scroll').pipe(takeUntil(this.destroy$))
.subscribe((e: Event) => console.log(this.getYPosition(e)));
}
getYPosition(): number {
return (e.target as Element).scrollTop;
}
ngOnDestroy(): void {
this.destroy.next();
}
}
However Method 4 is not bad.