show and hide between 2 different component Angular - javascript

I have Parent component with 2 different child, inquiryForm and inquiryResponse, I got situation when I need to hide and show this 2 component based on condition:
If user had click submit on inquiryForm, it will hide inquiryForm component and show inquiryResponse component
On inquiryResponse component, there are button display inquiry form, where user clicked it and will hide inquiryResponse component and show inquiryForm.I cant solved this.
I know it can be solved using router but I want different solution like using service or subject
this is demo I created using stackblitz, this is what I had tried;
inquiry-response.ts
getReceivedSummons() {
this.inquiryStore.summons$.subscribe(result => {
this.receivedSummon = result;
this.addCheckboxes();
this.isShowResponse = true;
});
}
showInquiryForm() {
// do something
}
inquiry-response.html
<div *ngIf="isShowResponse">
<p>Inquiry Response</p>
<form [formGroup]="form" (ngSubmit)="submitSelectedCheckboxes()">
<ng-container formArrayName="receivedSummons" *ngFor="let summon of formReceivedSummons.controls; let i = index">
<ng-container [formGroup]="summon">
<ng-container formArrayName="items" *ngFor="let item of formReceivedSummonsItems(i).controls; let j = index">
<ng-container [formGroup]="item">
<input type="checkbox" formControlName="isChecked"> {{item.value.name}}
</ng-container>
</ng-container>
</ng-container>
<div *ngIf="!summon.valid">At least one order must be selected</div>
</ng-container>
<br>
<span class="button">
<button [disabled]="!form.valid">submit</button>
</span>
<button (click)="showInquiryForm()"> ( change ID number ) display inquiry form</button>
</form>
</div>

As AJT_82 say, you app.component can be like
<app-inquiry-form *ngIf="step==1" (submit)="step=2"></app-inquiry-form>
<br>
<app-inquiry-response *ngIf="step==2" (click)="step=1"></app-inquiry-response>
//you has a variable
step:number=1;
And in each component
#Output() submit=new EventEmitter<any>()
..in somewhere...
this.submit.emit()
#Output() click=new EventEmitter<any>()
..in somewhere...
this.click.emit()

Related

Angular MatMenu not working in double ngFor loop

Using Angular 13, I have been trying to add a menu using Angular MatMenu (https://material.angular.io/components/menu/overview) which is conditionally shown. Basically a bar shows button (operations) and some may have suboperations. In this case I want to display the suboperations when clicking on the button.
Here is the basic code I have, which is the complete html since there is another menu in the beginning. Note that removing it does not change the behavior.
<div class="rounded-box" *ngIf="!!selectedCategory">
<div class="selector" *ngIf="rateOrDislocationEnabled; else simpleAggregation">
<button color="primary" mat-button mat-icon-button [matMenuTriggerFor]="categoryMenu" class="dropdownButton">
<div class="dropdownText">{{ selectedCategory | agReplace: "_":" " }}</div>
<mat-icon class="dropdownIcon">arrow_drop_down</mat-icon>
</button>
<mat-menu #categoryMenu="matMenu" [overlapTrigger]="true" data-testid="categories-menu">
<button mat-menu-item *ngFor="let category of availableCategories" (click)="setSelectedCategory(category)">
<span [ngClass]="{ selectedLabel: isSelected(category) }">{{ category | agReplace: "_":" " }}</span>
<div *ngIf="category === BlockCategory.RATE_MAKING" class="alpha">ALPHA</div>
</button>
</mat-menu>
</div>
<ng-container *ngFor="let operationCategory of getOperations(); let lastItem = last">
<ng-container *ngFor="let operation of operationCategory">
<button *ngIf="operation.subOperations.length === 0"
mat-icon-button
class="iconWrapper"
id="operation-icon-{{ operation.value }}"
(click)="addOperation(operation.value)"
[disabled]="operation.disabled$ | async">
<mat-icon [ngClass]="operation.icon" class="icon" [agToolTip]="operation.tooltip$ | async"></mat-icon>
</button>
<ng-container *ngIf="operation.subOperations.length !== 0">
<button
mat-button
mat-icon-button
class="iconWrapper"
id="operation-menu-icon-{{ operation.value }}"
[matMenuTriggerFor]="subMenu">
<mat-icon [ngClass]="operation.icon" class="icon" [agToolTip]="operation.tooltip$ | async"></mat-icon>
</button>
<mat-menu #subMenu="matMenu">
<button mat-menu-item>Settings</button>
<button mat-menu-item>Log off</button>
</mat-menu>
</ng-container>
</ng-container>
<div class="divider" *ngIf="!lastItem"></div>
</ng-container>
</div>
I have created a stackblitz reproducing the issue: https://angular-ivy-cvv2xk.stackblitz.io
The issue is that when I click on the button, nothing happens. When I move the button out of the ngFor loops though, it works properly. I have tried things such as removing the ngIf condition (so all buttons are doubled) and none show the menu when clicking on it.
So the "submenu" is never displayed.
I wonder if I need to make the mat-menu specific or give it some id to ensure there are no conflicts? Since I'm a bit new to Angular I maybe be missing something.
Thanks in advance
Your button which triggers submenu got multiple button tags.
<button
mat-button
mat-icon-button
Can you remove one and try again?
Edit:
You use <ng-container *ngFor="let operationCategory of getOperations();
to populate your array.
If you press your button, angular will trigger change detection and this will trigger again your getOperations().
This will lead to this behaviour and dosent open your submenu.
So you should try to replace getOperations() with async pipe (if this is the case) or use properties.

Problem getting details for any particular cell on mouse hovering in ngx datatable in angular

I am using ngx datatable, importing my data from a json.
I have added some more details to be shown in Column 'domain'.
So while hovering to a particular cell of Column 'domain', i want to get more details about that cell only, but I am getting more details of all cells of that particular column.
//HTML that I am using
<ngx-datatable-column name="App Domain" [flexGrow]="2" >
<ng-template let-row="row" ngx-datatable-cell-template>
<div (mouseover)="showText=(true)" (mouseout)="showText=(false)" >{{row?.domain}}</div>
<div *ngIf="!showText"></div>
<div *ngIf="showText">
{{row?.vp}}<br>
{{row?.cpu}}<br>
{{row?.vm}}<br>
{{row?.maxspeed}}</div>
</ng-template>
</ngx-datatable-column>
//HTML datatable properties in my code
<ngx-datatable class="material full screen" class="bootstrap" [rows]="rows" [columnMode]="'flex'" [headerHeight]="50" [footerHeight]="50" rowHeight="auto">
//component.ts
export class DashboardComponent implements OnInit {
title = 'test-dashboard';
rows=[ ]
apiResponseData: any = [];
apiData = []
pingApiInterval = 300000;
showText: boolean;
constructor(private dashboardService: DashboardService) { this.showText = false; }
Tried various approaches, but I failed.
The problem is that you are using the same variable showText for all rows.
For getting the details of a particular cell you can use a variable (showedIndex) for storing the index of the row hovered and then check it for showing only his information.
<ngx-datatable-column name="App Domain" [flexGrow]="2" >
<ng-template let-row="row" let-rowIndex="rowIndex" ngx-datatable-cell-template>
<div (mouseover)="showedIndex = rowIndex; showText=true" (mouseout)="showText=false" >{{row?.domain}}</div>
<div *ngIf="!showText"></div>
<div *ngIf="showText && rowIndex === showedIndex">
{{row?.vp}}<br>
{{row?.cpu}}<br>
{{row?.vm}}<br>
{{row?.maxspeed}}</div>
</ng-template>
</ngx-datatable-column>

Dynamically added <input> not being rendered

I have a string which holds a form that I want to dynamically render.
When the user clicks "Add Step", my template string is added to a list and rendered with an ngFor. The problem is that the input doesn't render, only the <h3> tag.
Before button click:
After - no input is rendered on screen or in the html:
ts:
scenarioTemplate = `
<div id="content">
<h3>Name</h3>
<input name="{{i}}" [ngModel]="i">
</div>`;
steps = [];
addScenarioStep() {
this.steps.push(this.scenarioTemplate);
}
html:
<form #myForm="ngForm">
<fieldset ngModelGroup="inputs" #inputs="ngModelGroup">
<ng-container *ngFor="let step of steps; let i = index">
<div [innerHTML]=step attr.stepId="{{i}}"></div>
</ng-container>
</fieldset>
</form>
<button id="addStepBtn" type="button" class="btn btn-light" (click)="addScenarioStep()">Add Scenario Step +</button>
Put that whole thing
<div id="content">
<h3>Name</h3>
<input name="{{i}}" [ngModel]="i">
</div>
in the template, not the TS.
Don't mutate the array. Instead of
this.steps.push(newElem);
do
this.steps = [...this.steps, newElem];

How to render component with *ngIf else

I am new to angular and I am writing dummy app to teach myself angular.
My idea was to have 2 inputs where player1 and player2 write down their names. When they press the button game starts and shows their names and health.
I am doing that with *ngIf else, but when I click the button to change boolean nothing is shown.
What is the problem and is there a better way to do that?
app.component.html
<p>This will not change!</p>
<ng-template *ngIf="startGame;
else noStart">
<p> Render other components for health and names. Did game start: {{startGame}}</p>
</ng-template>
<ng-template #noStart>
<h1> Input player names to start the game!</h1>
<input [(ngModel)]="player1">
<br>
<input [(ngModel)]="player2">
<br>
<button (click)="onStartGame()">Start</button>
</ng-template>
app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
startGame: boolean = false;
player1: string = '';
player2: string = '';
username = '';
setPlayer1(event) {
this.player1 = event.target.value;
}
setPlayer2(event) {
this.player2 = event.target.value;
}
onStartGame() {
if(this.player1 !== '' && this.player2 !== '')
this.startGame = true;
}
}
I want to render other component or HTML if boolean changes in if statment.
The ng-template just create a template and which won't show by default, use ng-container for that purpose which helps to group and
add multiple elements to DOM.
<p>This will not change!</p>
<ng-container *ngIf="startGame;
else noStart">
<p> Render other components for health and names. Did game start: {{startGame}}</p>
</ng-container>
<ng-template #noStart>
<h1> Input player names to start the game!</h1>
<input [(ngModel)]="player1">
<br>
<input [(ngModel)]="player2">
<br>
<button (click)="onStartGame()">Start</button>
</ng-template>
You can event use *ngIf directive with the p tag since there is only one element(p tag) and use ng-container whenever you want to group multiple elements.
<p>This will not change!</p>
<p *ngIf="startGame;
else noStart"> Render other components for health and names. Did game start: {{startGame}}</p>
<ng-template #noStart>
<h1> Input player names to start the game!</h1>
<input [(ngModel)]="player1">
<br>
<input [(ngModel)]="player2">
<br>
<button (click)="onStartGame()">Start</button>
</ng-template>
Change *ngIf and write [ngIf] but is not recommendable

Angular 5 is not rendering the component until click or hover anywhere

im having this issue which is breaking my head right now and I cant figured out what is the problem.
I have a form called device-form, which is called from the dashboard using routing. The device form has inside 4 tabs (angular material), and the second one must show a Highchart component, when you select that tab, the container appears but not the chart.... if you wait, the chart will never show up, but if you click in any place the chart appears, also if you hover some item with mouse, or if you resize the screen!!
App-chart-box.component.html:
<mat-card fxFlex="100%" fxLayout="row">
<mat-card-title></mat-card-title>
<mat-card-content>
<mat-tab-group class="form-wizard tab-group">
<mat-tab *ngFor="let chart of charts; let i = index">
<ng-template mat-tab-label>
{{ chart.sensorTypeName }}
</ng-template>
<div class="tab-content">
<vr-chart class="card-img-top" [title]="chart.sensorTypeName" [yTitle]="chart.sensorTypeUnit" type="spline" [series]="chart.series"
[period]="period" [minThreshold]="minThreshold" [maxThreshold]="maxThreshold"></vr-chart>
</div>
</mat-tab>
</mat-tab-group>
</mat-card-content>
<mat-card-actions>
<small class="footer">Last updated: {{ dateUpdated }}</small>
</mat-card-actions>
device-form.component.html:
<mat-tab>
<ng-template mat-tab-label>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<span>Statistics</span>
</div>
</ng-template>
<div fxFlex="100%" class="shipping-address" fxLayout="column">
<mat-form-field class="select-period">
<mat-select placeholder="{{ 'DEVICE_FORM.PERIOD' | translate }}" [(ngModel)]="filterPeriodSelected" (change)="loadDeviceChart()">
<mat-option *ngFor="let period of chartPeriods" [value]="period.value">
{{ period.label | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<!-- <div *ngIf="deviceCharts.length == 0" class="alert bg-primary alert-dismissible fade show" role="alert">
<strong class="ng-tns-c6-44"> {{'MESSAGE.NO_DATA_TO_SHOW' | translate}}</strong>
</div> -->
<vr-chart-box *ngIf="deviceCharts" class="fix-width" [charts]="deviceCharts" [period]="filterPeriodSelected"></vr-chart-box>
</div>
</mat-tab>
As you see the app-chart-box component is rendered, actually we can always see the footer loaded, always, but the body of the chart dont appear until click or hover o whatever.
Update:
Actually Im having the very same issue with a table which is filled with data coming from an API when you change a dropdown up there in the main dashboard page, the table component is always listening to .onCompanyChange.subscribe, read all the data, but the table is not showing until you make click or hover or whatever event... this is the code :
Table component:
export class CompanyHistoryComponent implements OnInit {
#ViewChild('tableInput') tableInput: ElementRef;
#Input() companyId = 0;
private rows: Observable<Array<any>>;
// public rows: any[] = [];
resultsLength: number;
dataSource: ListDataSource<any> | null;
database: ListDatabase<any>;
tableHover = true;
tableStriped = true;
tableCondensed = true;
tableBordered = true;
constructor(
public sensorService: SensorService,
public dashboardService: DashboardService,
private cd: ChangeDetectorRef,
) {
// Selected company changed
this.dashboardService.onCompanyChange.subscribe(
(id: number) => {
this.companyId = id;
this.loadSensorHistory();
cd.detectChanges();
});
}
public loadSensorHistory() {
const sDate: Number = moment().subtract(30, 'day').unix()
const eDate: Number = moment().unix();
this.sensorService.getSensorDataHistory(this.companyId, sDate, eDate, null, null, 1, 10).subscribe(response => {
if (response.statusCode !== 200 || !response.data) {
// this.toastrService.error('MESSAGE.NO_DATA', 'SENSOR_FORM_LIST.TITLE', { positionClass: 'toast-top-right', closeButton: true });
} else {
this.rows = response.data.list;
}
});
}
ngOnInit() {
}
As you see this time I added detectChanges() without any results :(
let me know if you have an idea.
This is the HTML of the Table :
<table class="table" [class.table-hover]="tableHover" [class.table-striped]="tableStriped" [class.table-condensed]="tableCondensed"
[class.table-bordered]="tableBordered">
<thead>
<tr>
<th>Date</th>
<th>Device</th>
<th>Sensor</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of rows" [class.row-failed]="row.failed > 0">
<td>{{ row.data_createdDate | date:'MM/dd/yyyy HH:mm:ss a Z' }}</td>
<td>
{{ row.deviceMAC }}
</td>
<td>
{{ row.sensorNumber }} - {{ row.sensorName }}
</td>
<td>{{ row.value }}</td>
</tr>
</tbody>
</table>
You should call ChangeDetectorRef detectChanges()
It might be an incorrect pipe operator.
I had a similar issue with Angular 11 and mat-table. The rows wouldn't show up until I hovered over them. My issue was that I was using an invalid pipe operator on one of the columns. I was using a decimal pipe on a string column. Once I corrected that it works perfectly.

Categories

Resources