Subscribe to Angular Material Mat-Drawer events .. Ex: openedChange - javascript

I'm using mat-drawer and I want to be notified in the associated Component, when the mat-drawer is opened and close to add some logic at that moment;
The html has the follosing structure :
<mat-drawer-container class="example-container" autosize>
<mat-drawer #drawer class="custom-sidenav" mode="side">
<div>
<button routerLink="/" routerLinkActive="active"
style="margin-top: 50px" mat-button class="small" (click)="showFiller = !showFiller" >
<mat-icon style="color: red">home</mat-icon>
<b style="margin-left: 20px">Home</b>
</button>
</div>
<div>
<button routerLink="/transactions" routerLinkActive="active" style="margin-top: 20px" mat-button class="small" (click)="showFiller = !showFiller" >
<mat-icon style="color:gray">trending_flat</mat-icon>
<b matBadge="{{totalTransactions}}" matBadgeColor="red" matBadgeOverlap="false" style="margin-left: 20px">Transactions</b>
</button>
</div>
<div *ngIf="isAdmin">
<button routerLink="/fetch-data" routerLinkActive="active" style="margin-top: 20px" mat-button class="small" (click)="showFiller = !showFiller" >
<mat-icon matBadge="{{totalCertificates}}" matBadgePosition="before" matBadgeColor="accent" style="color:gray">description</mat-icon>
<b style="margin-left: 20px">Certificates</b>
</button>
</div>
<div>
<button (click)="navigateToMyCertificates()" routerLinkActive="active" style="margin-top: 20px" mat-button class="small" (click)="showFiller = !showFiller" >
<mat-icon matBadge="{{myCertificates}}" matBadgePosition="before" matBadgeColor="accent" style="color:gray">description</mat-icon>
<b style="margin-left: 20px">My Certificates</b>
</button>
</div>
<div>
<button routerLink="/certificate-validator" routerLinkActive="active" style="margin-top: 20px" mat-button class="small" (click)="showFiller = !showFiller" >
<mat-icon style="color:black">check</mat-icon>
<b style="margin-left: 20px">Validate Certificate</b>
</button>
</div>
</mat-drawer>
and this is the associated Component class :
export class HomeLayoutComponent {
..etc
}
What is the required code that needs to be added in the mat-drawer and in the component to realize a correct binding that will fire the "openedChange" event in the Component class
Thanks !

There are 2 ways of doing it. You can either do
<mat-drawer #drawer (openedChange)="onOpenedChange($event)"></mat-drawer>
In your component you would then have a method
onOpenedChange(e: boolean)
Or you can do it using a view child in the component
export class MyComponent implements OnInit {
#ViewChild('drawer') drawer: MatDrawer;
ngOnInit() {
this.drawer.openedChange.subscribe((o: boolean) => { console.log(`IsOpen: ${o}`) });
}
}

you can go to the official website of angular material. They have a very nice doc of that.
Above answer is perfect.
Just adding some more info.
There are many other events like: openedStart, closedStart, onPositionChanged ... etc

Related

Angular ngbDropdown: keyboard navigation not working

I have modal made of a search bar and a list of elements, created with a ngbDropdown splitted into 2 components, parent and child. It works correctly, but I can't figure out a way to enable navigation with keyboard (use UP & DOWN keys to move between list's elements).
Following the official documentation, I tried to use ngbDropdownItem, but it's not working.
These are my 2 component's templates:
PARENT:
<div ngbDropdown class="dropdown-no-arrow" (openChange)="openChange($event)" container="body">
<!-- trigger -->
<ng-container>
<button class="btn" ngbDropdownToggle *ngIf="authorizationService.loggedInUser">
<i class="fal fa-farm me-2"></i>
<span>{{ authorizationService.loggedInUser.name }}</span>
<i class="fal fa-chevron-down ms-2"></i>
</button>
</ng-container>
<!-- menu -->
<div ngbDropdownMenu aria-labelledby="currentMenuItem" id="currentDropdown_{{ id }}">
<button ngbDropdownItem (click)="openNewModal()">
<i class="fal fa-plus me-1"></i> <span i18n>New</span>
</button>
<dm-child-list [isListDisplayed]="isDropdownOpened"></dm-child-list>
</div>
</div>
CHILD:
<div class="dropdown-header d-flex margin-x align-items-center">
<h6 class=" mb-0 flex-grow-1" i18n>MY LIST</h6>
</div>
<div class="px-4 py-2">
<div class="form-group mb-0">
<input class="form-control form-control-sm" libAutofocus [(ngModel)]="elSearch" (ngModelChange)="elSearch$.next($event)" i18n-placeholder placeholder="Search elements">
</div>
</div>
<button *ngFor="let el of list; let i = index;" ngbDropdownItem [ngClass]="{'top-border': i === 0}">
<i class="me-2 fas fa-check-circle text-success"
*ngIf="selectedEl?.id === el.id" title="Current element"></i>
<i class="me-2 fal fa-circle" *ngIf="selectedEl?.id !== el.id"></i>
<span>{{ el.name }}</span>
</button>
Can anyone help with making keyboard selection work?
Thanks!
By adding
#myDrop="ngbDropdown" (keyup)="myDrop.onKeyDown($event)"
on div where ngbDropdown directive is used, Arrow key navigation works.
In your case,
<div ngbDropdown
#myDrop="ngbDropdown"
(keyup)="myDrop.onKeyDown($event)"
class="dropdown-no-arrow
(openChange)="openChange($event)"
container="body">

how to avoid changing of ng bootstrap dropdown when enter key is pressed on any on input field in angular13

i am using angular powered bootstrap dropdown and here whenever i do enter key press in input, it always changes the dropdown value to first option.
DEMO LINK
HTML:
<div class="row mb-3 mt-3">
<div class="col">
<div ngbDropdown class="d-inline-block">
<button
type="button"
class="btn btn-outline-primary"
id="dropdownBasic1"
ngbDropdownToggle
>
{{ clickMessage }}
</button>
<div ngbDropdownMenu aria-labelledby="dropdownBasic1">
<button
ngbDropdownItem
class="nav-link"
href="#"
(click)="getText($event.target.innerText)"
>
Option 1
</button>
<button
ngbDropdownItem
class="nav-link"
href="#"
(click)="getText($event.target.innerText)"
>
Option 2
</button>
<button
ngbDropdownItem
class="nav-link"
href="#"
(click)="getText($event.target.innerText)"
>
Option 3
</button>
</div>
</div>
</div>
</div>
TS:
clickMessage = 'Choose an option';
getText(text) {
this.clickMessage = text;
}
The behaviour you are seeing is due to you have some buttons without any type attribute and by default the buttons in the form trigger the submit event.Add the type to the buttons in the dropdown and it should work.
<div ngbDropdownMenu aria-labelledby="dropdownBasic1">
<button
type="button"
ngbDropdownItem
class="nav-link"
href="#"
(click)="getText($event, $event.target.innerText)"
>
Option 1
</button>
<button
type="button"
ngbDropdownItem
class="nav-link"
href="#"
(click)="getText($event, $event.target.innerText)"
>
Option 2
</button>
<button
ngbDropdownItem
class="nav-link"
href="#"
(click)="getText($event, $event.target.innerText)"
>
Option 3
</button>
</div>
Add the following code to your ts file.
#HostListener('keydown', ['$event']) public onKeyDown(evt) {
if (evt.key === 'Enter') {
evt.preventDefault();
this.onSubmit();
}
}
I write it for you in the following stackblitz.
https://stackblitz.com/edit/angular12-bootstrap-skiant?file=src%2Fapp%2Fapp.component.ts,src%2Fapp%2Fapp.component.html,src%2Fapp%2Fapp.module.ts

TypeError: Cannot read property '$emit' of null ( "THIS" IS NULL)

I'm converting my project from JS to TS and I don't know why I cannot call "this" here.
<template>
<transition name="modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-body">
<div class="text-right">
<label>
<span>
<v-icon name="times" scale="1.5" />
<button
#click="closeModal"
type="button"
class="btn btn-sm btn-outline-info btn-block"
style="display: none"
>
Cancel
</button>
</span>
</label>
</div>
<h4 class="text-center title-switch">
<span style="font-weigth: bold">{{ title }}</span
>リストに追加しますか?
</h4>
<div class="d-flex justify-content-center align-items-center mb-2">
<button #click="closeModal" class="btn btn-no mr-5">No</button>
<button #click="getDate" class="btn btn-yes">Yes</button>
</div>
</div>
</div>
</div>
</div>
</transition>
</template>
<script lang="ts">
import { Vue, Prop } from 'vue-property-decorator';
import { chatModule } from '#/store/modules/manage-chat';
export default class ModalConfirm extends Vue {
#Prop(String) readonly title!: string;
#Prop(Boolean) readonly check!: boolean;
closeModal(): void {
if (confirm('Close the window without saving?')) {
chatModule.actionChangeNgListState({
status: false,
});
this.$emit('close');
}
}
}
</script>
this is log
app.js:sourcemap:161212 TypeError: Cannot read property '$emit' of null
In other file, I can still use "this" is method, but in this method I can not
[SOLVED] : I have already solved my problem.
It caused because I forgot add this decorator #Component({}).
So pls add this when you caught this problem.

How do I Import js file to React js file

JavaScript File.
const signUpButton = document.getElementById('signUp');
const signInButton = document.getElementById('signIn');
const container = document.getElementById('container');
signUpButton.addEventListener('click', () => {
container.classList.add("right-panel-active");
});
signInButton.addEventListener('click', () => {
container.classList.remove("right-panel-active");
});
I have this javascript Code, I want to use this in my React file.
This is my React js file Code.
import React, { Component } from 'react'
// import './js/main'
class Login extends Component {
render() {
return (
<div>
<div class="container" id="container">
<div class="form-container sign-up-container">
<form action="#">
<h1>Create Account</h1>
<div class="social-container">
<i class="fa fa-facebook-f" style={{color: 'blue'}} aria-hidden="true"></i>
<i class="fa fa-google-plus" style={{color: 'red'}} aria-hidden="true"></i>
<i class="fa fa-linkedin" style={{color: 'blue'}} aria-hidden="true"></i>
</div>
<span>or use your email for registration</span>
<input type="text" placeholder="Name" />
<input type="email" placeholder="Email" />
<input type="password" placeholder="Password" />
<button>Sign Up</button>
</form>
</div>
<div class="form-container sign-in-container">
<form action="#">
<h1>Sign in</h1>
<div class="social-container">
<i class="fa fa-facebook-f" style={{color: 'blue'}} aria-hidden="true"></i>
<i class="fa fa-google-plus" style={{color: 'red'}} aria-hidden="true"></i>
<i class="fa fa-linkedin" style={{color: 'blue'}} aria-hidden="true"></i>
</div>
<span>or use your account</span>
<input type="email" placeholder="Email" />
<input type="password" placeholder="Password" />
Forgot your password?
<button>Sign In</button>
</form>
</div>
<div class="overlay-container">
<div class="overlay">
<div class="overlay-panel overlay-left">
<h1>Welcome Back!</h1>
<p>To keep connected with us please login with your personal info</p>
<button class="ghost" id="signIn">Sign In</button>
</div>
<div class="overlay-panel overlay-right">
<h1>Hello, Friend!</h1>
<p>Enter your personal details and start journey with us</p>
<button class="ghost" id="signUp">Sign Up</button>
</div>
</div>
</div>
</div>
</div>
)
}
}
export default Login
In this code there onclick events for scrolling the login form and get the signup page.
How do I use Javascript to perform click events. I am new to React. Help me to get out of this.
You should be doing the following
Create two separate components for signUpButton.js and signInButton.js, each. These components should include their respective event handlers as well
Import these two components into your main component (your main React.js file) and use them.
import { SignUpButton } from './signUpButton.js'
import { SignInButton } from './signUpButton.js'
Right now, in your JavaScript file, you are trying to directly access DOM elements using document.getElementById. This is not recommended in React
Its important that you go through the core react concepts here and understand these thoroughly. This will definitely help you in the long run
https://reactjs.org/docs/hello-world.html
Event Handling in React
https://reactjs.org/docs/glossary.html#events
class Login extends Component {
constructor(props) {
super(props);
this.state = {addClass: false}
}
toggle() {
this.setState({addClass: !this.state.addClass});
}
render() {
let Class = ['container'];
if(this.state.addClass) {
Class.push('right-panel-active');
}
return (
<div>
<div className={Class.join(' ')} id="container">
Putting this is did a great Job to me. Working as Expected.
<button className="ghost" id="signIn" onClick={this.toggle.bind(this)}>{this.state.addClass}Log In</button>
And Calling this on Button click. Solved this after doing tones of Research. Feeling very Happy as new Beginner React js Developer.

How can I keep the selection active state of a button?

In this quiz selection component I put two different div bootstrap list-group with buttons.
I'd like to keep the active class when I click on some button but only one of them inside each div can be active.
So for example if I click on "History" and then "Medium", I'd like them to keep active class.
I've tried to add some bootstrap 4 options like "Active state" and tried to toggle active class onClick.
But in this way active class still stay in each button I click.
Thank you very much for help
class Selection extends React.Component {
render() {
return (
<div className="border rounded w-75 mx-auto">
<div className="row pt-4">
<div className="col-6">
<div
onClick={this.props.chooseCategory}
className="list-group w-75 ml-auto"
>
<p>Choose a category</p>
<button
type="button"
className="list-group-item list-group-item-action" active
>
Mix
</button>
<button
type="button"
className="list-group-item list-group-item-action"
>
Sports
</button>
<button
type="button"
className="list-group-item list-group-item-action"
>
History
</button>
<button
type="button"
className="list-group-item list-group-item-action"
>
Movies
</button>
<button
type="button"
className="list-group-item list-group-item-action"
>
Geography
</button>
</div>
</div>
<div className="col-6">
<div
className="list-group w-50 mr-auto"
onClick={this.props.chooseDifficulty}
>
<p>Choose the difficulty</p>
<button
type="button"
className="list-group-item list-group-item-action active"
>
Easy
</button>
<button
type="button"
className="list-group-item list-group-item-action"
>
Medium
</button>
<button
type="button"
className="list-group-item list-group-item-action"
>
Hard
</button>
</div>
</div>
</div>
<button
onClick={this.props.handleStart}
className="btn btn-outline-primary my-4"
>
START
</button>
</div>
Add state to the component, to represent the actively selected category and difficulty.
i.e. (in constructor)
this.state = { category: 'Mix', difficulty: 'Easy' }
Later in the render function you can check, using an if or inline ternary statement. I would also create an array representing the options and use array.map() to shorten your code.
const categoryOptions = [ 'Mix', 'Sports', 'History']
(in render function, instead of manually adding all those buttons...)
{ categoryOptions.map(category => (
<button
type="button"
className={`list-group-item list-group-item-action $(this.state.category === category ? 'active' : '')`}
onClick=(() => this.setState({category: category}))
>
{category}
</button>
)) }
The onClick will alter the state to represent the active element, the active class will conditionally be shown, only when that category has been selected.
I don't want to take this answer too far astray, but a further enhancement would be using the React useState hook with functional components, from the latest version of React.
use state to show the active div elements
onClick of the div make the state active as true
<div>
{this.state.active ? <div><button1><div> : <div><button2></div>}
</div>

Categories

Resources