How to Hide and Show Popup dialog based on Condition In Angular? - html

I have a Suspend Toggle(ON/OFF) in Update form which is used for suspending and un-suspending the Row value of a Table as shown below in image.
On click of Suspend Toggle, It should call Service method and suspend/unsuspend the row without opening the Suspend dialog as shown below.
The Suspend dialog only should open, if on click of Suspend toggle(ON/OFF), validations return some warning message.
Below is code for Suspend dialog HTML.
<div class="container mt-2" style="width: 500px; height: 90px">
<div class="spinner" *ngIf="loadspinner" align="center"></div>
<div *ngIf="!loadspinner">
<mat-dialog-content>
<p style="color:rgb(255, 60, 0)">{{errorMsg}}</p>
<p align="center">{{warningMsg}}</p>
</mat-dialog-content>
<mat-dialog-actions align="center">
<button *ngIf="errorMsg ; else elseBlock" mat-raised-button mat-dialog-close tabindex="-1" (click)="oKBtn()" style="border-color:#3f51b5;">OK</button>
<ng-template #elseBlock>
<button mat-raised-button color="primary" [mat-dialog-close] = "true">SUSPEND</button>
<button mat-raised-button mat-dialog-close tabindex="-1" (click)="cancel()" style="border-color:#3f51b5;">Cancel</button>
</ng-template>
</mat-dialog-actions>
</div>
Update Dialog is Parent .ts for child suspend dialog .ts
Below is code for child suspend.ts
constructor(public dialogRef: MatDialogRef<SuspendModalComponent>,
#Inject(MAT_DIALOG_DATA) public data:DialogData, private updateService: UpdateService) {
this.mainData = this.data; }
ngOnInit() {
if (this.mainData.buttonChecked == false) {
this.updateService.validate(this.mainData.updateData).subscribe(value => {
this.loadspinner = false;
if (value != null) {
this.warningMsg = value.statusMessage;
} else {
this.warningMsg = "";
}
});
} else {
this.updateService.validateRecord(this.mainData.updateData).subscribe(record => {
this.loadspinner = false;
if (record != null) {
this.errorMsg = "Record is present";
}
});
}
}
cancel() : void {
this.dialogRef.close();}
Suspend/unsuspend service methods i'm calling from suspend() function of parent update.ts as shown in code.
suspend(){
const list: any[] = Array.of(this.mainData.updateData);
if(this.toggleRef.checked) {
if(this.toggleRef.record == null) {
this.updateService.unsuspendCall(list).subscribe(data => {
this.toggleRef.checked = true;
this.buttonChecked = false;
});
}
} else {
if(this.toggleRef.value == null) {
this.updateService.suspendCall(list).subscribe(data => {
this.toggleRef.checked = false;
this.buttonChecked = true;
});
}
}
Can anyone help on this how to hide suspend dialog if there is no validations message on click of Suspend Toggle button and show the dialog if validation message is there?

Related

Is there any way to render focus on ng-template modal using keyboard arrow key?

I used one directive and service for gaining focus and that is working on all pages when pressing the arrow keys but on ng-template modal the focus is not gathering and am getting the find index value -1.Please refer this link Link for complete code to see the full code.The solution provided in that link is working on everywhere except the ng-template modal.Please refer with some ideas to solve this issues.
<ng-template #content let-modal>
<div class="modal-header">
<h3 class="modal-title">Accept Offer</h3>
</div>
<div class="modal-body">
<p>Do you really want to accept the offer?</p>
</div>
<div class="modal-footer>
<button type="submit" class="btn btn-primary tab" (click)="onAcceptOffer()" arrow-div>Submit</button>
<button type="button" class="btn btn-secondary tab" (click)="modal.dismiss('Crossclick');
isClicked=false" arrow-div>Cancel</button></div>
</ng-template>
Update 2022-08-11 Control input Select (I change the function onArrowDown)
We can improve the code of the link using a directive instead of use fromEvent in main component.
I want that keydown can be listend from document or from another div. Futhermore, we need control if the element is an Input or a select to change a bit how the arrow work
So we can make a directive like
export enum Key {
Tab = 9,
Enter = 13,
Escape = 27,
Space = 32,
PageUp = 33,
PageDown = 34,
End = 35,
Home = 36,
ArrowLeft = 37,
ArrowUp = 38,
ArrowRight = 39,
ArrowDown = 40,
}
#Directive({
selector: '[div-group-arrow]',
})
export class DivGroupArrowDirective implements OnInit, OnDestroy {
#ContentChildren(ControlArrowDirective, { descendants: true })
items: QueryList<ControlArrowDirective>;
active: boolean = true;
subscription: Subscription;
#Input() step = 1;
#Input() focus = true;
#Input() main = false;
constructor(private elementRef: ElementRef) {}
ngOnInit() {
this.subscription = fromEvent(
this.main ? document : this.elementRef.nativeElement,
'keydown'
)
.pipe(
filter(
(event: any) =>
this.active &&
event.which >= Key.ArrowLeft &&
event.which <= Key.ArrowDown
)
)
.subscribe((event) => {
this.onArrowDown(event);
});
}
ngOnDestroy() {
this.subscription && this.subscription.unsubscribe();
}
onArrowDown(event: any) {
const focused = this.items.find(
(x) => x.elementRef.nativeElement == document.activeElement
);
if (!focused) {
this.items.first.elementRef.nativeElement.focus();
return;
}
let index = this.items.reduce((a, b, i) => (b == focused ? i : a), 0);
const htmlElement = focused.elementRef.nativeElement;
const isInput = htmlElement.tagName == 'INPUT';
const isSelect=htmlElement.tagName == 'SELECT';
const oldIndex = index;
switch (event.which) {
case Key.ArrowLeft:
if ((isInput && !htmlElement.selectionStart) || isSelect)event.preventDefault();
index += !isInput || !htmlElement.selectionStart ? -1 : 0;
break;
case Key.ArrowRight:
if ((isInput && htmlElement.selectionEnd == htmlElement.value.length) || isSelect)
event.preventDefault();
index +=
!isInput || htmlElement.selectionEnd == htmlElement.value.length
? 1
: 0;
break;
case Key.ArrowUp:
if (!isSelect) {
index -= this.step;
event.preventDefault();
}
break;
case Key.ArrowDown:
if (!isSelect) {
index += this.step;
event.preventDefault();
}
break;
}
if (index >= 0 && index < this.items.length && index != oldIndex) {
const next = this.items.find((_, i) => i == index).elementRef
.nativeElement;
if (next.tagName == 'INPUT') {
next.selectionStart = 0;
next.selectionEnd = this.focus ? next.value.length : 0;
}
next.focus();
}
}
}
See that we have a property "active" to help us "stop" the listener
The control-arrow is simple
#Directive({
selector: '[control-arrow]'
})
export class ControlArrowDirective {
constructor(public elementRef:ElementRef) { }
}
We can then use, e.g. (I use ngb-bootstrap modal but we can use the same using material or whatever
<!--see that in main.html, we use [main]="true"-->
<div class="container mt-3" div-group-arrow [main]="true" [step]="2">
<input control-arrow class="me-2 my-2" />
<input control-arrow class="me-2 my-2"/><br />
<input control-arrow class="me-2"/>
<input control-arrow class="me-2 mb-3"/>
<button class="btn btn-lg btn-outline-primary" (click)="open(content, null)">
Launch demo modal
</button>
</div>
<ng-template #content let-modal>
<!---we enclose all in a div with the directive "div-group-arrow"-->
<div div-group-arrow>
<div class="modal-header">
...
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button
control-arrow
type="button"
class="btn btn-outline-dark"
(click)="modal.close('Save click')"
>
Save
</button>
<button
control-arrow
type="button"
class="btn btn-outline-dark"
(click)="modal.dismiss('Cancel click')"
>
Cancel
</button>
</div>
</div>
</ng-template>
The stackblitz
Update
Really I don't like the property "active". We can avoid simply change the filter
.pipe(
filter(
(event: any) =>
event.which >= Key.ArrowLeft &&
event.which <= Key.ArrowDown &&
((document.activeElement.tagName=='BODY' && this.main)
||this.elementRef.nativeElement.contains(document.activeElement))
)
)

How to change the color of text on click of radio - Angular

I am designing a quiz component, I have an issue when revealing the solution using a submit button. I have a variable checked which is initially false.
Once the condition of right answer is met, checked is turned to true and the color is changed.
The problem is when I click reveal solution, all the answers go green. And when I click reveal solution again it stays green.
So
what I want :
When the user presses the correct answer and presses reveal solution, the answer should be green or else the selected answer should be red.
import { Component, OnInit, Input } from '#angular/core';
import { Quiz } from './ez-quiz.types';
import { Subject, takeUntil } from 'rxjs';
import { QuizService } from './ez-quiz.service';
class answerDataStructure {
check: boolean;
value: string;
expanded: boolean;
constructor(answers) {
this.value = answers;
}
}
#Component({
selector: 'app-ez-quiz',
templateUrl: './ez-quiz.component.html',
styleUrls: ['./ez-quiz.component.scss'],
})
export class EzQuizComponent implements OnInit {
expand_button: boolean = false;
private _unsubscribeAll: Subject<any> = new Subject<any>();
quiz: Quiz;
options: answerDataStructure[] = [];
checked: boolean = false;
selectedAnswer: any[] = [];
constructor(private quizService: QuizService) {}
ngOnInit(): void {
this.quizService.Quiz$.pipe(takeUntil(this._unsubscribeAll)).subscribe(
(quiz: Quiz) => {
this.quiz = quiz;
for (var answers of this.quiz[0].options) {
let ansData = new answerDataStructure(answers);
console.log(ansData);
this.options.push(ansData);
}
}
);
}
expand_and_check(correctAnswer: any) {
//Expanded Condition
if (this.expand_button == false) {
this.expand_button = true;
this.selectedAnswer.reverse();
if (correctAnswer == this.selectedAnswer[0]) {
console.log('Correct Answer'), (this.checked = true);
} else if (this.selectedAnswer.length == 0) {
console.log('Please select one answer');
} else {
console.log('Wrong Answer'), (this.checked = false);
}
} else {
this.expand_button = false;
}
}
changed(event: any, value: any) {
this.selectedAnswer.push(value);
console.log(event);
}
}
<div class="card">
<!-- 1st Question -->
<div class="questionStyle">
{{ quiz[0].questionId }}{{ quiz[0].question }}
</div>
<section class="question-section">
<ol>
<mat-radio-group>
<li *ngFor="let answers of options; let j = index">
<mat-radio-button
class="option-style-margin"
[value]="answers.value"
(change)="changed($event, j)"
>
<span [style.color]="checked ? 'green' : 'black'">
{{ answers.value }}
</span>
</mat-radio-button>
</li>
</mat-radio-group>
</ol>
</section>
<section class="pageMargin">
<!--Buttons Margin and Button Placing-->
<div class="buttonsMargin">
<button
mat-raised-button
color="primary"
(click)="expand_and_check(quiz[0].correctAnswer)"
>
<span class="buttonStyle">Reveal Solution</span></button
>
<button mat-raised-button color="warn">
<span class="buttonStyle"> Labs</span>
<mat-icon svgIcon="heroicons_outline:beaker"></mat-icon>
</button>
</div>
<mat-card *ngIf="expand_button" class="mat-card">
<mat-card-title>Explanation</mat-card-title>
<mat-card-content>
<p class="matContent">
Both private and public cloud solutions are useful in various
scenarios. Private clouds have restricted access to services whereas
the public cloud is accessible to any user. A private cloud is most
often connected to the Internet and works the same way as a public
cloud when it comes to security and Azure management. Private clouds
can have access to all Azure features too.
</p>
</mat-card-content>
</mat-card>
</section>
<!--End of Question 1-->
</div>
<!--End of the Page-->
Try having a separate function to get the color, and a separate variable to indicate correctness:
<span [style.color]="getColor(j)">{{ answers.value }}</span>
correct = false;
selectedIndex = -1;
getColor(index: number) {
if (!this.checked || index != this.selectedIndex) return 'black';
if (this.correct) return 'green';
return 'red';
}
changed(event:any,value:any){
this.selectedIndex = value;
this.selectedAnswer.push(value);
console.log(event)
}
Then your submit function becomes:
expand_and_check(correctAnswer: any) {
//Expanded Condition
if (this.expand_button == false) {
this.expand_button = true;
this.selectedAnswer.reverse();
if (correctAnswer == this.selectedAnswer[0]) {
console.log('Correct Answer');
this.checked = true;
this.correct = true;
} else if (this.selectedAnswer.length == 0) {
console.log('Please select one answer');
} else {
console.log('Wrong Answer');
this.checked = true;
this.correct = false;
}
} else {
this.expand_button = false;
this.checked = false;
}
}

how to update changes on view in Angular

I have a charts that have a few options for user and I already implemented everything but not sure why I don't see any immediate changes when I click Delete Chart, Publish Chart or Unpublished Chart button. I can only see the result only after I refresh the browser.
I'm new to Angular so I'm wonder how to remove the selected chart immediately or make it disappear when delete button is click and also the same for publish and unpublish chart without having to refresh the browser. any help or suggestion will be really appreciated
#Input() chart: Chart;
data: ChartData;
chartData: ChartData;
hasError: boolean = false;
maxisChartConfig: ChartConfig;
hasChart: boolean = false;
#Input() editMode: boolean;
isTextChart: boolean = false;
constructor(private chartService: ChartService, private router: Router, private dialog: MatDialog) { }
isGrid: boolean = false;
#Input() wsType?: WorkspaceType;
isPublicWs: boolean = false;
ngOnInit(): void {
if(this.wsType) {
if(this.wsType == WorkspaceType.public) {
this.isPublicWs = true;
}
}
this.generateChartConfig();
if(this.chart.chartType == ChartType.text){
this.isTextChart = true;
}
else if(this.chart.chartType == ChartType.grid){
this.isGrid = true;
}
if (this.chart.data) {
if(!this.isTextChart){
this.hasChart = true;
}
this.chartData = this.chart.data;
}
}
deleteChart() {
this.chartService.deleteChart(this.chart.guid).subscribe((deleted) => {
console.log(deleted);
});
}
publishChart() {
this.chartService.setChartPublished(this.chart.guid, !this.chart.isPublished).subscribe((published) => {
console.log(published);
});
}
<button mat-menu-item (click) = "deleteChart()" *ngIf = "chart.hasAccess && chart.canEdit && !chart.isPublished">Delete Chart</button>
<button mat-menu-item (click) = "publishChart()" *ngIf = "chart.canEdit && chart.hasAccess && !chart.isPublished && isPublicWs">Publish Chart</button>
<button mat-menu-item (click) = "publishChart()" *ngIf = "chart.canEdit && chart.hasAccess && chart.isPublished && isPublicWs">Unpublish Chart</button>
The will not run but I uploaded the full code for this component here https://stackblitz.com/edit/angular-ivy-bepxss . Thanks
After each function you can call oninit to reconstruct the charts after changes like this -
deleteChart() {
this.chartService.deleteChart(this.chart.guid).subscribe((deleted) => {
console.log(deleted);
this.ngOnInit(); // Add this line
});
}
///This is how i have refreshed variables in my case -
saveWTPModel(){
if(some condition){
//Perform Save logic
var headers = new HttpHeaders();
headers.append('Content-Type', 'application/json');
const httpOptions = { headers: headers };
this.httpClient.post(environment.api_url + "/User/SavePriority",
this.finalWTPArray, httpOptions)
.subscribe(
response => {
if(response){
this.alertService.success('Priorities Saved.');
//Once i have saved everything I am again calling the api to get the updated data from backend. This function again is called to get the updated Priorities.
this.getWorkTypesPriority(this.loggedinUserId);
}
else{
this.alertService.warning('Problem Occurred.');
}
});
}

Angular *ngIf updating after clicking on page or alt+tab (refocusing)

I have a strange bug on an angular project,these are the fragments of the code
#Injectable()
export class FirebaseMessagingService {
public tokenReceivedEmitter: any = new EventEmitter();
public messageReceivedEmitter: any = new EventEmitter();
constructor(
private angularFireMessaging: AngularFireMessaging) {
this.angularFireMessaging.messaging.subscribe(
(messaging) => {
messaging.onMessage = messaging.onMessage.bind(messaging);
messaging.onTokenRefresh = messaging.onTokenRefresh.bind(messaging);
}
);
}
/**
* request permission for notification from firebase cloud messaging
*
* #param userId userId
*/
requestPermission(userId) {
this.angularFireMessaging.requestToken.subscribe(
(token) => {
this.tokenReceivedEmitter.emit({status: true, result: token});
},
(err) => {
this.tokenReceivedEmitter.emit({status: false, result: err});
}
);
}
/**
* hook method when new notification received in foreground
*/
receiveMessage() {
this.angularFireMessaging.messages.subscribe(
(payload) => {
this.messageReceivedEmitter.emit(payload);
});
}
So this was the firebase messaging service which emit token receiving events and when a push notification is received.
Now in the component
ngOnInit(){
// Subscribing to firebase token receive
this.firebaseTokenSubscription = this.messagingService.tokenReceivedEmitter.subscribe(
(message) => {
if (message.status) {
const token = message.result;
this.sendNotificationToken(token);
} else {
this.snackBar.open(message.result, this.translate.instant('CLOSE')
{duration:3000});
}
}
);
}
And also I have enable/disable button in the component, here are the html parts of that code
<div *ngIf="user && !user.webPushEnabled"
class="user-verification fx-all-100 layout-all-row-wrap">
<div class="fx-gtSm-48 fx-ltMd-100 layout-all-col-nowrap">
<p>{{"EXCHANGE.PROFILE.ENABLE_DISABLE_NOTIFICATION" | translate}}</p>
</div>
<div class="fx-gtSm-48 fx-ltMd-100 offset-gtSm-4 align-all-fxEnd-fxStr">
<button mat-raised-button class="button-auth button-main-shadow"
(click)="updateNotificationStatus(true)">
{{"EXCHANGE.PROFILE.ENABLE_NOTIFICATIONS_BUTTON" | translate}}
</button>
</div>
</div>
<div *ngIf="user && user.webPushEnabled"
class="user-verification fx-all-100 layout-all-row-wrap">
<div class="fx-gtSm-48 fx-ltMd-100 layout-all-col-nowrap">
<p>{{"EXCHANGE.PROFILE.ENABLE_DISABLE_NOTIFICATION" | translate}}</p>
</div>
<div class="fx-gtSm-48 fx-ltMd-100 offset-gtSm-4 align-all-fxEnd-fxStr">
<button mat-raised-button class="del-api-key-btn button-main-shadow"
(click)="updateNotificationStatus(false)">
{{"EXCHANGE.PROFILE.DISABLE_NOTIFICATIONS_BUTTON" | translate}}
</button>
</div>
</div>
And obviously I have
updateNotificationStatus(on: boolean) {
if (on) {
this.messagingService.requestPermission(this.user.userId);
} else {
this.userService.updateNotificationStatus(null, false).subscribe(
(result) => {
this.user.webPushEnabled = false;
},
(error) => {
this.snackBar.open(error, this.translate.instant('CLOSE'), {duration: 3000});
}
);
}
}
sendNotificationToken(token) {
this.userService.updateNotificationStatus(token, true).subscribe(
(result) => {
debugger;
this.user.webPushEnabled = true;
},
(error) => {
this.snackBar.open(error, this.translate.instant('CLOSE'), {duration: 3000});
}
);
}
The problem is that when I enable push notifications it only updates html when page is reloaded or refocused(alt+tab or clicking on page with mouse). It also works fine when webpage is loaded at first time.
Pleas help any suggestions or ideas may help.
The problem was that firebase was requesting user token outside Angular's view thread, so I had to update the model in angular's view thread.
this.ngZone.run(() =>{
this.user.webPushEnabled = true;
})
It helped me out.

Angular directive *ngIf not working as intended

I have this block of html in my template to show or hide the div.
<div *ngIf="csvVisible">
<p>Paragraph works</p>
</div>
This is my component.
export class SettingsComponent implements OnInit {
csvVisible: boolean = false;
private dataSource: string[];
#ViewChild(MatTable, { static: true }) table: MatTable<any>;
constructor(private dialog: MatDialog, private templateParserService: TemplateParserService) { }
ngOnInit() {
this.templateParserService.subscribe({
next(result: string[]) {
if (result !== null) {
this.dataSource = result;
if (this.dataSource && this.dataSource.length) {
this.csvVisible = true;
} else {
this.csvVisible = false;
}
}
},
error(error: Error) {
console.log(error.message);
}
});
}
Eventhough the DIV is hidden at start, it doesnt automatically show / hide on the csvVisible value change. Value of csvVisible is properly set when the observer emits data. [hidden]="csvVisible" isn't working either.
Edit :
Subscriber registration on the service is done by the following code.
private subject = new Subject<string[]>();
public subscribe(observer: any): Subscription {
return this.subject.subscribe(observer);
}
Since you are using Object inside subscribe, this points to current subscribe object, Instead of using subscribe({next:()}) try using this way
component.ts
this.templateParserService.subscribe((result: string[])=>{
if (result !== null) {
this.dataSource = result;
if (this.dataSource && this.dataSource.length) {
this.csvVisible = true;
} else {
this.csvVisible = false;
}
}
},(error: Error)=>{
console.log(error.message);
});