Angular Material Stepper with Autocomplete more options to step - javascript

I have a question, is it possible that if I select an item in autocomplete via ngModel in step1, a different window will open every time I select it - different content in step 2. (for example, I load a different component, but let it be displayed on step2 item).
I need to display different content for different selections in autocomplete on step 2.
component.html
<mat-step [stepControl]="stepOne" label="step 1" [editable]="true" [completed]="true">
<form [formGroup]="stepOne">
<mat-form-field>
<input [(ngModel)]="SelectedFunctions"
type="search"
aria-label="Number"
placeholder="Vložiť funkciu"
matInput
[formControl]="MyControl"
[matAutocomplete]="auto">
<mat-icon matPrefix>search</mat-icon>
</mat-form-field>
<mat-autocomplete panelWidth="auto" #auto="matAutocomplete" [displayWith]="displayWith">
<mat-option *ngFor="let function of arrFilteredFunctions | async" [value]="function">
{{function.Name}}
</mat-option>
</mat-autocomplete>
<div>
<button mat-button matStepperNext (click)="OnFunctionSelected(SelectedFunctions)">Ok</button></div>
</mat-step>
component.ts
OnFunctionSelected(SelectedFunctions: any) {
console.log(SelectedFunctions.Name);
if( this.SelectedFunctions.Name === 'AVG'){
console.log('mojeee')
let dialogRef = this.dialog.open(WizardDialogAlgorithmDialog, {
width: '500px', height: '500px'
})}
if (this.SelectedFunctions.Name === 'ALT'){
console.log('ide')
let dialogRef = this.dialog.open(WizardDialogAlternativDialog, {
width: '500px', height: '500px'
})}
}

Related

How show error in Quasar Stepper when required field is empty

I work with Quasar framwork. I create a stepper and in each step I've several field. Some are required
like this:
<q-stepper dense v-model="step" ref="stepper" color="primary" animated header-nav>\
<q-step dense :name="1" title="Infos générales" icon="settings" :done="step > 1" :error="step < 3">
<q-card-section class="q-pt-none">
<div class="q-col-gutter-x-md">
<q-input class="full-width" dense v-model="infos.motif" label="Raison *" hint="Détaillez la raison. * Champs requis" :rules="Required"></q-input>
</div>
</q-card-section >
</q-step>
<q-step dense :name="2" title="Mise en copie" icon="assignment" :done="step > 2" >
<q-card-section class="q-pt-none" >
<div class="row items-start content-start" >
<div class="text-subtitle2">A la demande</div>
<selectusers v-bind:users="users" v-bind:model.sync="infos.copiedemande"></selectusers>
</div >\
</q-card-section >
</q-step>
<template v-slot:navigation>
<q-stepper-navigation >
<q-btn v-if="step > 1" flat color="primary" #click="$refs.stepper.previous()" label="Retour" />
<q-btn #click="$refs.stepper.next()" color="primary" :label="step === 2 ? \'Fini\' : \'Continuer\'" class="float-right"/>
</q-stepper-navigation >\
</template >\
</q-stepper>
Required is a computed : Required() { return [(v) => !!v || 'Saisissez quelque chose :-)'] },
I want when i change step my first step display error if I don't fill my infos.motif field
I don't find how link :error from step to rules from field
Thanks for your guidance
UPDATE1
I Add a form with ref in my 1st page.
<q-stepper dense v-model="step" ref="stepper" color="primary" animated header-nav>
<q-step dense :name="1" ref="step1" title="Infos générales" icon="settings" :done="step > 1" :error="checkform1()">
<q-form ref="myForm1">
Where checkform1 is a method
checkform1() { return this.$refs.stepper ? this.$refs.stepper.$refs.step1.$refs.myForm1.validate() : true; }
But I can't access to my form. When I has this.$refs.stepper, the $ref is empty...
UPDATE2 I create a sample on codepen here
I make a big step... The idea is to pass by a data and on before-transtion call my checkform function
<div id="q-app">
<q-stepper
v-model="step"
header-nav
ref="stepper"
color="primary"
animated
#before-transition="checkform1"
>
<q-step
:name="1"
title="Select campaign settings"
icon="settings"
:done="done1"
:error="stateform1"
> <q-form ref="myForm" class="q-gutter-md" >
<q-input
v-model="firstName"
:rules="[val => !!val || 'First name is required']"
/>
</q-form>
<q-stepper-navigation>
<q-btn #click="() => { done1 = true; step = 2 }" color="primary" label="Continue"></q-btn>
</q-stepper-navigation>
</q-step>
<q-step
:name="2"
title="Create an ad group"
caption="Optional"
icon="create_new_folder"
:done="done2"
>
An ad group contains one or more ads which target a shared set of keywords.
<q-stepper-navigation>
<q-btn #click="() => { done2 = true; step = 3 }" color="primary" label="Continue"></q-btn>
<q-btn flat #click="step = 1" color="primary" label="Back" class="q-ml-sm"></q-btn>
</q-stepper-navigation>
</q-step>
<q-step
:name="3"
title="Create an ad"
icon="add_comment"
:done="done3"
>
text3
<q-stepper-navigation>
<q-btn color="primary" #click="done3 = true" label="Finish"></q-btn>
<q-btn flat #click="step = 2" color="primary" label="Back" class="q-ml-sm"></q-btn>
</q-stepper-navigation>
</q-step>
</q-stepper>
</div>
</div>
and js
new Vue({
el: '#q-app',
data () {
return {
step: 1,
done1: false,
done2: false,
done3: false,
firstName: '',
stateform1:false
}
},
methods: {
reset () {
this.done1 = false
this.done2 = false
this.done3 = false
this.step = 1
this.stateform1=false
this.firstName= ''
},
checkform1() {
if (this.$refs.myForm) {
this.$refs.myForm.validate().then(success => {
if (success) {
this.stateform1= false;
}
else {
this.stateform1= true;
}
});
}
} //this.step<3;
}
})
like here
But stay another problem. When I'm on specific step, the other form don't exist... and if I pass step1 tp step 3... i can't check step2
like u can see enter link description here
Finally I found another way. I keep my :error="stateform1" but I check in addition in server side and if I've a missing field I return the name of my step and change the variable when I was a error in return

Disable button when checkbox is unchecked

when user does not check the checkbox, I want the submit button to be disabled.
<ion-row *ngFor="let item of classDescription; let i = index" >
{{ item.Location }}
{{ item.Instructor }}
<ion-checkbox style="text-align: center;"
(ionChange)="onChecked($event,item)"
[checked]="item.checked"
name="classCheck"
[(ngModel)]="item.register">
</ion-checkbox>
</ion-row>
<ion-button color="success"
expand="block"
(click)="btnSubmit()"
[disabled]="!classCheck">
Submit
</ion-button>
Since, there item variable from another tag, i cant use it to another tag. I tried to call by name. but its not working.
<ion-row *ngFor="let item of classDescription; let i = index" >
{{ item.Location }}
{{ item.Instructor }}
<ion-checkbox style="text-align: center;" (ionChange)="onChecked($event,item)" [checked]="item.checked" name="classCheck" [(ngModel)]="item.register" name="classCheck"></ion-checkbox>
</ion-row>
<ion-button color="success" expand="block" (click)="btnSubmit()" [disabled]="isNotAllCheckedYet()">Submit</ion-button>
and in your component
isNotAllCheckedYet():boolean{
if(!this.classDescription){
return false;
}
return this.classDescription.filter(a=>!a.register);
}
disable submit button if not all checked

<template> syntax of vue.js does not work

I want to use this dropdown menue for my webproject based on vue.js.
Everything with vue.js worked fine so far.
Unfortunately in the following example the template part does (i guess) not get rendered. There is no error message in the console and i don't know what i need to do to use <template> properly in my webproject.
<div>
<label class="typo__label">Simple select / dropdown</label>
<multiselect v-model="value" :options="options" :multiple="true" :close-on-select="false" :clear-on-select="false" :preserve-search="true" placeholder="Pick some" label="name" track-by="name" :preselect-first="true">
<template slot="selection" slot-scope="{ values, search, isOpen }"><span class="multiselect__single" v-if="values.length && !isOpen">{{ values.length }} options selected</span></template>
</multiselect>
<pre class="language-json"><code>{{ value }}</code></pre>
</div>
Any hint is highly appreciated!
In the link, he says that
<template slot="tag" slot-scope="props"><Your code></template>
so update your code to
<template slot="selection" slot-scope="{ values, search, isOpen }">
<div>
<label class="typo__label">Simple select / dropdown</label>
<multiselect v-model="value" :options="options" :multiple="true" :close-on-select="false" :clear-on-select="false" :preserve-search="true" placeholder="Pick some" label="name" track-by="name" :preselect-first="true">
<span class="multiselect__single" v-if="values.length && !isOpen">{{ values.length }} options selected</span>
</multiselect>
<pre class="language-json"><code>{{ value }}</code></pre>
</div>
</template>
because Vue read from <template> tag so don't use it inside codes
Since the template tag is within the mulitselect, I'd suggest you check the documentation for vue-multiselect and check out their slot scopes. This should help
https://vue-multiselect.js.org/#sub-getting-started

Angular Material - Collapse inactive steps of Stepper

I have a Stepper from #Angular/Material and it looks great. However, I see many example that have only the current step opened up. I would like this functionality. All inactive steps should be closed.
[EDIT]: Just added in the HTML and TS file.
Component HTML File
<img width="350px" align="middle" mat-card-image src="../assets/Icon_Rev8.png" alt="Logo">
<mat-card-content>
<mat-tab-group mat-stretch-tabs [selectedIndex]="0" dynamicHeight=true>
<mat-tab label="Login">
<form>
<mat-form-field class="sameWidth">
<input matInput style="width:100%;" placeholder="Username">
</mat-form-field>
<mat-form-field class="sameWidth">
<input matInput style="width:100%;" placeholder="Password">
</mat-form-field>
</form>
<button class="sameWidth" mat-raised-button color="primary">Login</button>
<button class="sameWidth" mat-button color="primary">Forgot Password?</button>
</mat-tab>
<mat-tab label="Register">
<mat-progress-spinner mode="indeterminate"></mat-progress-spinner>
<mat-vertical-stepper [linear]=true>
<mat-step [stepControl]="firstFormGroup">
<form [formGroup]="firstFormGroup">
<ng-template matStepLabel>Fill out your name</ng-template>
<mat-form-field>
<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 [active]="true" [stepControl]="secondFormGroup">
<form [formGroup]="secondFormGroup">
<ng-template matStepLabel>Fill out your address</ng-template>
<mat-form-field>
<input matInput placeholder="Address" formControlName="secondCtrl" 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>
You are now done.
<div>
<button mat-button matStepperPrevious>Back</button>
</div>
</mat-step>
</mat-vertical-stepper>
<!--<form>
<table cellspacing="0">
<tr>
<td>
<mat-form-field>
<input style="width: 40%;" matInput placeholder="First Name">
</mat-form-field>
</td>
<td>
<mat-form-field>
<input style="width: 40%;" matInput placeholder="Last name">
</mat-form-field>
</td>
</tr>
</table>
<mat-form-field style="width:100%;">
<input matInput placeholder="Password">
</mat-form-field>
</form>-->
<mat-checkbox style="z-index: 1000;" color="primary">I Agree to the Terms and Conditions</mat-checkbox>
<button class="sameWidth" mat-raised-button color="primary">Register</button>
</mat-tab>
</mat-tab-group>
</mat-card-content>
Component TS File
import { Component, OnInit, ViewEncapsulation, Inject } from "#angular/core";
import {
MatIconRegistry,
MatDialog,
MatDialogRef,
MAT_DIALOG_DATA
} from "#angular/material";
import { DomSanitizer } from "#angular/platform-browser";
import { HttpClientModule, HttpClient } from "#angular/common/http";
import { FormBuilder, FormGroup, Validators } from "#angular/forms";
#Component({
selector: "app-login",
templateUrl: "login.component.html",
styleUrls: ["login.component.css"]
})
export class LoginComponent {
animal: string;
name: string;
constructor(
private _formBuilder: FormBuilder,
iconRegistry: MatIconRegistry,
sanitizer: DomSanitizer,
public dialog: MatDialog
) {
iconRegistry.addSvgIcon(
"close",
sanitizer.bypassSecurityTrustResourceUrl(
"assets/icons/ic_close_48px.svg"
)
);
}
openDialog(): void {
let dialogRef = this.dialog.open(LoginDialogComponent, {
width: "400px",
data: { name: this.name, animal: this.animal }
});
dialogRef.afterClosed().subscribe(result => {
console.log("The dialog was closed");
this.animal = result;
});
}
}
#Component({
selector: "dialog-login",
templateUrl: "loginDialog.component.html",
styleUrls: ["loginDialog.component.css"]
})
export class LoginDialogComponent {
constructor(
private _formBuilder: FormBuilder,
public dialogRef: MatDialogRef<LoginDialogComponent>,
#Inject(MAT_DIALOG_DATA) public data: any
) {}
onNoClick(): void {
this.dialogRef.close();
}
ngOnInit() {
this.firstFormGroup = this._formBuilder.group({
firstCtrl: ["", Validators.required]
});
this.secondFormGroup = this._formBuilder.group({
secondCtrl: ["", Validators.required]
});
}
}
My Current Status:
My Goal:
There is no official fix yet. I have submitted a bug-report and it is being looked into. For now I have researched and found a workaround for this issue. I had to add (selectionChange)="cambiaStep($event)" as an attribute to my <mat-vertical-stepper> tag. Then I had to add a <ng-container> under all of my <mat-step> tags. In each corresponding <ng-container>, I had to set an attribute based on which position it had in the stepper order. In each <ng-container> I had to add *ngIf="stepIndex === 0" but the 0 was based on its order in the steps (0: first, 1: second, 2: third, etc.)
My stepper ended up having code as such:
<mat-vertical-stepper (selectionChange)="cambiaStep($event)">
<mat-step>
<ng-container *ngIf="stepIndex === 0">
</ng-container>
</mat-step>
<mat-step>
<ng-container *ngIf="stepIndex === 1">
</ng-container>
</mat-step>
<mat-step >
<ng-container *ngIf="stepIndex === 2">
</ng-container>
</mat-step>
</mat-vertical-stepper>
I also had to add the event function in my component's *.ts file.
export class LoginDialogComponent {
stepIndex: number = 0;
cambiaStep(e) {
this.stepIndex = e.selectedIndex;
}
constructor() {}
}
I just copy pasted your code in default angular-material stepper code and it's showing like your goal
https://stackblitz.com/edit/angular-tpeo6s?embed=1&file=app/stepper-overview-example.html
Edit
It seems angular material bug to me.
if stepper is put out of tabs, it is working but inside tab, though aria-expanded="false" for inactive steps , material is not adding style="height: 0px; visibility: hidden;" to hide inactive steps.
you can log issues related to angular material 2 HERE

angular2 Can't have multiple template bindings on one element

I have this angular2 template:
<template *ngIf="alerts.length > 0">
<alert *ngFor="let alert of alerts;let i = index" [type]="alert.type" dismissible="true" (close)="closeAlert(i)">
{{ alert?.msg }}
</alert>
</template>
I get these errors:
zone.js:461 Unhandled Promise rejection: Template parse errors:
Can't have multiple template bindings on one element. Use only one attribute named 'template' or prefixed with * (" </div>
<div *ngSwitchCase="false" class="container p-t-10">
<alert *ngIf="alerts.length > 0" [ERROR ->]*ngFor="let alert of alerts;let i = index" [type]="alert.type" dismissible="true" (close)="closeAlert"): b#5:37
what's the problem I put *ngIf and *ngFor in defferent html elements. It should work. no?
and:
Can't bind to 'type' since it isn't a known property of 'alert'. (""container p-t-10">
<alert *ngIf="alerts.length > 0" *ngFor="let alert of alerts;let i = index" [ERROR ->][type]="alert.type" dismissible="true" (close)="closeAlert(i)">
{{ alert?.msg }}
</alert>
"): b#5:80
I added the
*ngIf="alerts.length > 0 to avoid cases of alert = []. How can i fix it otherwise?
The * in *ngFor makes Angular to add a <template> tag. On a <template> tag this doesn't make sense and therefore here structural directives have a different syntax.
<template ngFor [ngForOf]="alerts" let-alert let-i="index">
Because different syntax for almost the same on different places caused quite some confusion, the Angular team recently introduced
<ng-container>
that behaves similar to the <template> tag (is not added to the DOM) but allows the more common syntax
<ng-container *ngIf="alerts.length > 0">
<alert *ngFor="let alert of alerts;let i = index" [type]="alert.type" dismissible="true" (close)="closeAlert(i)">
{{ alert?.msg }}
</alert>
</ng-container>
You should use <ng-container> for this case. As a example:
<ng-container *ngIf="totalItems > 0">
<tr *ngFor="let item of outputs| paginate: { id:'ab', itemsPerPage: pageSize, currentPage: currentPage, totalItems: totalItems }; let $index = index">
<td>{{item.x}}</td>
<td>{{item.y | date: 'MMMM d, y, h:mm:ss a' }}</td>
<td>{{item.z}}</td>
<td>{{item.r}}</td>
</tr>
</ng-container>
<ng-container *ngIf="totalItems > 10">
<tr *ngFor="let item of outputs| paginate: { id:'aabbbbbbbbb', itemsPerPage: pageSize, currentPage: currentPage, totalItems: totalItems }; let $index = index">
<td>{{item.x}}</td>
<td>{{item.y | date: 'MMMM d, y, h:mm:ss a' }}</td>
<td>{{item.z}}</td>
<td>{{item.r}}</td>
</tr>
</ng-container>

Categories

Resources