How to implement a Angular 2+ step progress bar - html

I want to implement a 7 step progress bar in Angular2+ TypeScript+SCSS+HTML like shown in above image. I don't know how to proceed.
I have 7 steps(created, assigned, inprogress and so on) and three different paths (all 7 steps, blocked after 3 steps, rejected at initial step)
My thoughts:
Draw a line, add icons and then change icons once step is completed. should I use routing here?
add image/icons then add lines in between?
add default line, then add icons/images over it and colour the completed steps?
I am doing for a website so the words below the icons/images should resize accordingly and should work for phone size although not required at this point of time. Angular stepper has buttons and a bit complex for me. I am implementing in already existing website with internal calls for status variable. It will be placed in top right corner of the website.
Also it is ok to grey out 2 previous steps of current steps and showing next step in grey.
It's been quite confusing how to go about it, I am a very new to Angular2+.

I did something somewhat similar awhile back, but ended up scrapping it so it is not super clean. I also was just writing the name of the statuses and coloring them differently instead of having icons with labels underneath. Mine would switch to a vertical view on small screen sizes. Not sure if it will help much, but here's the html:
<div
*ngIf="appeal && statuses && statuses.length > 0 && childVisible"
fxLayout="row"
fxLayoutAlign="start center"
fxLayout.lt-md="column"
class="py-24"
>
<ng-container *ngFor="let status of statuses; let last = last; let index = index">
<span [ngClass]="{ 'green-fg': index <= selection, 'orange-fg text-bold': index === selection }">{{
status.statusDescription
}}</span>
<mat-divider
fxHide.lt-md="true"
fxHide="false"
inset="true"
fxFlex="1 0 15px"
*ngIf="!last"
class="my-0 mx-8"
></mat-divider>
<mat-divider
fxHide.lt-md="false"
fxHide="true"
vertical="true"
inset="true"
fxFlex="1 0 10px"
*ngIf="!last"
class="mx-0 my-4"
></mat-divider>
</ng-container>
</div>

hi i find a solution: this component call "stepper" in angular material have this solucion
example:
HTML
<button mat-raised-button (click)="isLinear = !isLinear" id="toggle-linear">
{{!isLinear ? 'Enable linear mode' : 'Disable linear mode'}}
</button>
<mat-stepper [linear]="isLinear" #stepper>
<mat-step [stepControl]="firstFormGroup">
<form [formGroup]="firstFormGroup">
<ng-template matStepLabel>Fill out your name</ng-template>
<mat-form-field appearance="fill">
<mat-label>Name</mat-label>
<input matInput placeholder="Last name, First name" formControlName="firstCtrl" required>
</mat-form-field>
<div>
<button mat-button matStepperNext>Next</button>
</div>
</form>
</mat-step>
<mat-step [stepControl]="secondFormGroup" label="Fill out your address">
<form [formGroup]="secondFormGroup">
<mat-form-field appearance="fill">
<mat-label>Address</mat-label>
<input matInput formControlName="secondCtrl" placeholder="Ex. 1 Main St, New York, NY" required>
</mat-form-field>
<div>
<button mat-button matStepperPrevious>Back</button>
<button mat-button matStepperNext>Next</button>
</div>
</form>
</mat-step>
<mat-step>
<ng-template matStepLabel>Done</ng-template>
<p>You are now done.</p>
<div>
<button mat-button matStepperPrevious>Back</button>
<button mat-button (click)="stepper.reset()">Reset</button>
</div>
</mat-step>
</mat-stepper>
ts
import { Component } from '#angular/core';
import { FormBuilder, Validators } from '#angular/forms';
/**
* #title Stepper overview
*/
#Component({
selector: 'stepper-overview-example',
templateUrl: 'stepper-overview-example.html',
styleUrls: ['stepper-overview-example.css'],
})
export class StepperOverviewExample {
firstFormGroup = this._formBuilder.group({
firstCtrl: ['', Validators.required],
});
secondFormGroup = this._formBuilder.group({
secondCtrl: ['', Validators.required],
});
isLinear = false;
constructor(private _formBuilder: FormBuilder) { }
}
in here link find you the documentation here https://material.angular.io/components/stepper/overview

Related

HTML & Angular Material disable save button from outside div when form fields are empty

I have the following Angular Material form with the Close and Save buttons in an outside div for design reasons:
<h1 mat-dialog-title>Product Page</h1>
<div mat-dialog-content>
<form [formGroup]="productForm">
<mat-form-field appearance="outline">
<mat-label>Name</mat-label>
<input formControlName="name" required matInput placeholder="Name" style="text-transform:uppercase">
</mat-form-field>
<mat-form-field appearance="outline">
<mat-label>Weight</mat-label>
<input type="number" required formControlName="weight" matInput placeholder="weight">
</mat-form-field>
</form>
</div>
<div mat-dialog-actions [align]="'end'">
<button mat-raised-button color="warn" mat-dialog-close>Close</button>
<button mat-raised-button color="primary" (click)="saveProduct()">Save</button>
</div>
I want to disable the Save button when the form fields are empty but the required parameter isn't working since the buttons are in an outside div. Is there a way to correlate the buttons with the form such that the Save button is disabled until the required fields are filled in?
You can bind it manually :
<button (click)="submit()" [disabled]="!form.valid">Submit</button>
Or you can cheat your way in the modal by providing the form as the main container (yes, it works)
<form [formGroup]="form">
<h1 mat-dialog-title>...</h1>
<div mat-dialog-content>...</div>
<div mat-dialog-actions align="end">
<button type="submit" [disabled]="!form.valid">Submit</button>
</div>
</form>
You could add a validation to your formGroup and use the formGroup to set the button disabled:
on your component:
constructor(fb:FormBuilder
(...)
) {
this.productForm = fb.group({
name: [null, Validators.required]
(...)
})
}
then on your template, adjust the button:
<button mat-raised-button color="primary" [disabled]="productForm.invalid" (click)="saveProduct()">Save</button>
You might as well remove the 'required' from you input (as angular will warn you about this in the console):
<input formControlName="name" matInput placeholder="Name" style="text-transform:uppercase">

Angular-material, how to bind an object array

I'm dealing with this code which was written by another developer, and I'm not used to angular.
I'm trying to bind the data.order.order_items to an object in the component, to do an additional logic in the component side when the user clicks the button.
<!-- some code -->
<form class="form">
<h4 class="sku-list-title">SKU List</h4>
<mat-slide-toggle
[checked]="isChecked"
(change)="isChecked = $event.source.checked"
class="toggle"
>Edit SKUs</mat-slide-toggle
>
<div
class="item-container"
*ngFor="let element of data.order.order_items"
[(ngModel)]="orderItems"
>
<mat-form-field>
<mat-label>SKU</mat-label>
<input
[value]="element.item.seller_sku"
matInput
tabindex="-1"
[disabled]="true"
/>
</mat-form-field>
<mat-form-field>
<mat-label>New SKU</mat-label>
<input
[placeholder]="element.item.new_seller_sku"
matInput
tabindex="-1"
[disabled]="!isChecked"
/>
</mat-form-field>
<mat-form-field>
<mat-label>Quantity</mat-label>
<input
matInput
maxlength="5"
[value]="element.quantity"
tabindex="-1"
[disabled]="!isChecked"
/>
</mat-form-field>
</div>
</form>
</div>
<!-- some code -->
<div mat-dialog-actions class="actions full-width">
<button mat-flat-button color="warn" (click)="onNoClick()">Cancel</button>
<button
mat-flat-button
color="primary"
(click)="onClick()"
[mat-dialog-close]="closeAnswer"
>
Accept
</button>
</div>
Component side
#Component({
selector: "app-message-dialog",
templateUrl: "./message-dialog.component.html",
styleUrls: ["./message-dialog.component.scss"],
})
export class MessageDialogComponent implements OnInit {
orderItems: any; //This object would bind the order_items
//some code
onClick() {
//some code
this.orderItems //doesn't get the binded data.
How can I bind the data from the data.order.order_items that is updated in that input, to the object this.orderItems?
I tried with the ngModel, but I guess i'm missing something or doing it in the wrong element.
Thanks in advance!
you are binded the data but forgot to display data you can use following syntax {{element }}
you should use the ngModel inside input tag to get the value from corresponding input tag or another option is to use formControl to get the value
NG Model
<input
matInput
maxlength="5"
[value]="element.quantity"
tabindex="-1"
[disabled]="!isChecked"
[(ngModel)]="orderItems"
/>
Form Control
visit this site -> https://angular.io/api/forms/FormControl

Angular: Submit method executed by clicking another button

I'm using Angular with Angular Material components.
So, I added a login component (form) where the user can type in his email and password. The input field for the password has an eye on the end to enable the user to display the password in plain text if wanted.
Unfortunately, by clicking twice the eye button, the submit method executes which is binded to the submit button.
The simple question is: why?
Template
<form [formGroup]='loginForm' (ngSubmit)="onSubmit()">
<div>
<mat-form-field>
<mat-label for="email">E-Mail</mat-label>
<input matInput type="text" formControlField="email" />
<mat-error>
Test
</mat-error>
</mat-form-field>
</div>
<div>
<mat-form-field>
<mat-label for="password">Password</mat-label>
<input matInput [type]="hide ? 'password' : 'text'" formControlField="password" />
<button mat-icon-button matSuffix class="mat-icon-button mat-button-base" (click)="hide = !hide" [attr.aria-label]="'Hide password'" [attr.aria-pressed]="hide">
<mat-icon>{{ hide ? 'visibility_off' : 'visibility' }}</mat-icon>
</button>
</mat-form-field>
</div>
<button mat-raised-button color="primary" type="submit">Login</button>
Component
export class LoginComponent implements OnInit {
loginForm: FormGroup;
hide = true;
constructor(
private formBuilder: FormBuilder
) {
this.loginForm = this.formBuilder.group({
email: ['', [Validators.required, Validators.email]],
password: ['', [Validators.required]]
})
}
onSubmit() {
window.alert("Login button clicked");
}
Try adding type="button" to your "eye" button.
This will tell the browser not to treat it as a submit button when inside a form.
The reason is that missing type argument from button is treated as default state and by default button element has submit.
The missing value default and invalid value default are the Submit Button state.
Source: https://html.spec.whatwg.org/multipage/form-elements.html#attr-button-type

How to make my ngForm dirty after modifying an Angular Material table inside the form

I have an Angular form like below and it has a save button that is disabled until a input field is changed (made dirty) and it works fine with input elements.
Then I placed a Angular Material UI table inside the form and I want the form to be dirty if I make a change to the table ex. select a row, edit a row value, add a row, delete a row, etc.
Is there a way to make the form dirty, to enable the save button, either manually setting it in the ts file or some other way so that my save button will be enabled?
I tried putting a form-control class in the table class, but I don't think it worked and it messed up all my css, because I'm using an Angular Material table with lots of pre defined CSS.
Here is my code that show my basic form with a mat table in it
// just to show here how my ngForm is in the ts file
#ViewChild('editForm', {static: false}) editForm: NgForm;
<form #editForm="ngForm" id="editForm" (ngSubmit)="updateData()">
<button class="btn btn-primary btn-sm" type="submit" [disabled]="!editForm.dirty">Save</button>
<input type="text" class="form-control" placeholder="ex. Chuck" [(ngModel)]="matterData.firstName" name="firstName">
<div class="form-row">
<div class="form-group col-md-12">
<table mat-table [dataSource]="generalSmokingSource" class="smoking-table" name=smokingTable>
<ng-container matColumnDef="product">
<th mat-header-cell *matHeaderCellDef> Product </th>
<td mat-cell *matCellDef="let element"> {{element.product}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="generalSmokingColumns"></tr>
<tr mat-row *matRowDef="let row; columns: generalSmokingColumns;"></tr>
</table>
</div>
</div>
</form>
I think one solution, maybe not the best, is to add a second check in the disabled attribute Like
[disabled]="!editForm.dirty || tableModified"
and then when I modify something in a table (ex. add a row, select a row checkbox, etc) I can set this bool to true. And then after I save, set it to false!
Any thoughts? Is there a better way?
I think you can use (ngModelChange) event in input tag eg.
import {Component} from '#angular/core'
import {FormsModule} from '#angular/forms'
#Component({
selector: 'template-driven-form',
template: `
<section>
<h1>(ngModelChange) Example:</h1>
<form #f="ngForm" (ngSubmit)="onSubmitTemplateBased()">
<p>
<label>Name:</label>
<input type="text"
[ngModel]="username"
(ngModelChange)="onChange($event)"
name="username"
required>
</p>
<p>
<button type="submit" [disabled]="!f.valid">Submit</button>
</p>
</form>
</section>
`
})
export class TemplateDrivenForm {
username: string = 'nome';
onSubmitTemplateBased() {
console.log(this.username);
}
onChange(event) {
console.log(event);
}
}
May this help. Thank You

Angular material button does not change color

Hey people I'm facing an issue where Angular material button's color does bot apply in some cases, just like this one:
html:
<mat-card>
<mat-spinner *ngIf="isLoading"></mat-spinner>
<form [formGroup]="form" (submit)="onLogin()" *ngIf="!isLoading">
<mat-form-field>
<input matInput type="email" formControlName="email" placeholder="Email">
<mat-error *ngIf="form.get('email').invalid">Please enter a valid email.</mat-error>
</mat-form-field>
<mat-form-field>
<input matInput type="password" formControlName="password" placeholder="Password">
<mat-error *ngIf="form.get('password').invalid">Please enter a valid password.</mat-error>
</mat-form-field>
<mat-action-row>
<!-- NOT COLORED-->
<button mat-raised-button type="submit" color="warn">Login</button>
</mat-action-row>
</form>
<!-- COLORED-->
<button mat-raised-button type="submit" color="warn">Login</button>
</mat-card>
result:
As you can see, both buttons has same code, but for one the color is applied and for the other one it doesnt, and I want to use that color inside my form... any solutions?
I had a similar problem with the mat-select and mat-options components. I know this post is dated, but this is still a common problem. Sometimes when you add a style to a material component it just doesn't work.
For me, I managed to get it to work by moving my material related styles to the global stylesheet. This seems to work consistently.
problem solved by adding :
this.form = this.fb.group({
email: ['', [Validators.required]],
password: ['', [Validators.required]]
});
in the compponent.ts file