Topic: MDB Select is not working in Angular 2
Bartłomiej Malanowski
staff pro premium answered 4 years ago
declare let $ : any;
@Directive({
selector: '[md-select]'
})
export class MDSelectDirective implements AfterViewInit {
constructor(private logger:Logger,
private el: ElementRef) {}
ngAfterViewInit(): void {
// this.logger.debug("After view init", this.el);
$(this.el.nativeElement).material_select();
}
}
Then, simply add the directive to your select element:
<select md-select ...> ... </select>
Benny Bottema
pro answered 4 years ago
import {AfterViewInit, Component, ElementRef, EventEmitter, forwardRef, Input, OnDestroy, Output, ViewChild} from "@angular/core";
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from "@angular/forms";
declare var $: any;
const DROPDOWN_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DropdownComponent),
multi: true
};
@Component({
selector: 'dropdown-input',
template: '
<select #select class="mdb-select">
<option value="" disabled [attr.selected]="!value">{{placeholder}}</option>
<option *ngFor="let option of options" [attr.value]="option.value" [attr.selected]="option.value == value">{{option.displayValue}}</option>
</select>
<label *ngIf="label">{{label}}</label>',
providers: [DROPDOWN_VALUE_ACCESSOR],
})
export class DropdownComponent implements ControlValueAccessor, OnDestroy, AfterViewInit {
@ViewChild('select')
private select: ElementRef;
private onTouched: () => {};
private onChange: (value: string) => void;
@Input() options: Array<Option>;
@Input() value: string;
@Input() placeholder: string = 'Choose your option';
@Input() label: string = '';
@Output() dropdownChanged = new EventEmitter();
ngAfterViewInit(): void {
$(this.select.nativeElement).material_select();
$(this.select.nativeElement).on('change', (e) => this.selectValue($(':selected', this.select.nativeElement).val()));
}
writeValue(value: string) {
this.value = value;
$(this.select.nativeElement).val(value);
$(this.select.nativeElement).material_select();
}
registerOnChange(fn: any) {
this.onChange = fn;
}
registerOnTouched(fn: any) {
this.onTouched = fn;
}
selectValue(value: string) {
this.value = value;
this.onChange && this.onChange(this.value);
this.onTouched && this.onTouched();
this.dropdownChanged.next(this.value);
}
ngOnDestroy(): void {
}
}
export class Option {
constructor(readonly value: any, readonly displayValue: string) {
}
}
Then to use it, here's an example of a country select:
<div class="card-block">
<form #countryForm="ngForm" (ngSubmit)="save()">
<div class="row">
<div class="col-md-12">
<div class="md-form">
<dropdown-input [label]="'Country'" [options]="countries" [placeholder]="'Choose country'" name="inputCountry" [(ngModel)]="country"></dropdown-input>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12 text-center">
<button type="submit" class="btn btn-primary" [disabled]="countryForm.form.pristine || countryForm.form.invalid">Save</button>
</div>
</div>
</form>
</div>
The Component:
import {Component, ViewChild} from "@angular/core";
import {EditorComponent} from "../common/editor-component";
import {NgForm} from "@angular/forms";
import {Option} from "../common/dropdown-component";
import {Country} from "../../global/model/content/Country";
import {plainToClass} from "class-transformer";
@Component({
selector: 'editor-author-address',
template: require('./editor-author-address.template.html')
})
export class EditorAuthorAddressComponent extends EditorComponent {
@ViewChild("countryForm")
countryForm: NgForm;
country: string; // assign initial value if you want, in my case an ISO code like "US"
countries:Array<Option> = (<Array<Country>>plainToClass(Country, require('../../assets/countries.json')))
.map((o:Country):Option => new Option(o.ISO, o.name));
save(): void {
// save country in persistence layer
// reset form for reuse:
this.countryForm.form.markAsPristine();
this.countryForm.form.markAsUntouched();
this.countryForm.form.updateValueAndValidity();
}
}
Note there are some details regarding loading the countries, which you can ignore really. Just use your own values. Note the Option class is defined at the bottom of the dropdown component.
Benny Bottema
pro answered 4 years ago
import {AfterViewInit, Component, ElementRef, EventEmitter, forwardRef, Input, OnDestroy, Output, ViewChild} from "@angular/core";
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from "@angular/forms";
declare var $: any;
const DROPDOWN_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DropdownComponent),
multi: true
};
@Component({
selector: 'dropdown-input',
template: '
<select #select class="mdb-select">
<option value="" disabled [attr.selected]="!value">{{placeholder}}</option>
<option *ngFor="let option of options" [attr.value]="option.value" [attr.selected]="option.value == value">{{option.displayValue}}</option>
</select>
<label *ngIf="label">{{label}}</label>',
providers: [DROPDOWN_VALUE_ACCESSOR],
})
export class DropdownComponent implements ControlValueAccessor, OnDestroy, AfterViewInit {
@ViewChild('select')
private select: ElementRef;
private onTouched: () => {};
private onChange: (value: string) => void;
@Input() options: Array<Option>;
@Input() value: string;
@Input() placeholder: string = 'Choose your option';
@Input() label: string = '';
@Output() dropdownChanged = new EventEmitter();
ngAfterViewInit(): void {
$(this.select.nativeElement).material_select();
$(this.select.nativeElement).on('change', (e) => this.selectValue($(':selected', this.select.nativeElement).val()));
}
writeValue(value: string) {
this.value = value;
$(this.select.nativeElement).val(value);
$(this.select.nativeElement).material_select();
}
registerOnChange(fn: any) {
this.onChange = fn;
}
registerOnTouched(fn: any) {
this.onTouched = fn;
}
selectValue(value: string) {
this.value = value;
this.onChange && this.onChange(this.value);
this.onTouched && this.onTouched();
this.dropdownChanged.next(this.value);
}
ngOnDestroy(): void {
}
}
export class Option {
constructor(readonly value: any, readonly displayValue: string) {
}
}
Then to use it, here's an example of a country select:
<div class="card-block">
<form #countryForm="ngForm" (ngSubmit)="save()">
<div class="row">
<div class="col-md-12">
<div class="md-form">
<dropdown-input [label]="'Country'" [options]="countries" [placeholder]="'Choose country'" name="inputCountry" [(ngModel)]="country"></dropdown-input>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12 text-center">
<button type="submit" class="btn btn-primary" [disabled]="countryForm.form.pristine || countryForm.form.invalid">Save</button>
</div>
</div>
</form>
</div>
The Component:
import {Component, ViewChild} from "@angular/core";
import {EditorComponent} from "../common/editor-component";
import {NgForm} from "@angular/forms";
import {Option} from "../common/dropdown-component";
import {Country} from "../../global/model/content/Country";
import {plainToClass} from "class-transformer";
@Component({
selector: 'editor-author-address',
template: require('./editor-author-address.template.html')
})
export class EditorAuthorAddressComponent extends EditorComponent {
@ViewChild("countryForm")
countryForm: NgForm;
country: string; // assign initial value if you want, in my case an ISO code like "US"
countries:Array<Option> = (<Array<Country>>plainToClass(Country, require('../../assets/countries.json')))
.map((o:Country):Option => new Option(o.ISO, o.name));
save(): void {
// save country in persistence layer
// reset form for reuse:
this.countryForm.form.markAsPristine();
this.countryForm.form.markAsUntouched();
this.countryForm.form.updateValueAndValidity();
}
}
Note there are some details regarding loading the countries, which you can ignore really. Just use your own values. Note the Option class is defined at the bottom of the dropdown component.
Benny Bottema
pro answered 4 years ago
import {AfterViewInit, Component, ElementRef, EventEmitter, forwardRef, Input, OnDestroy, Output, ViewChild} from "@angular/core";
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from "@angular/forms";
declare var $: any;
const DROPDOWN_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DropdownComponent),
multi: true
};
@Component({
selector: 'dropdown-input',
template:
<select #select class="mdb-select">
<option value="" disabled [attr.selected]="!value">{{placeholder}}</option>
<option *ngFor="let option of options" [attr.value]="option.value" [attr.selected]="option.value == value">{{option.displayValue}}</option>
</select>
<label *ngIf="label">{{label}}</label>`,
providers: [DROPDOWN_VALUE_ACCESSOR],
})
export class DropdownComponent implements ControlValueAccessor, OnDestroy, AfterViewInit {
@ViewChild('select')
private select: ElementRef;
private onTouched: () => {};
private onChange: (value: string) => void;
@Input() options: Array<Option>;
@Input() value: string;
@Input() placeholder: string = 'Choose your option';
@Input() label: string = '';
@Output() dropdownChanged = new EventEmitter();
ngAfterViewInit(): void {
$(this.select.nativeElement).material_select();
$(this.select.nativeElement).on('change', (e) => this.selectValue($(':selected', this.select.nativeElement).val()));
}
writeValue(value: string) {
this.value = value;
$(this.select.nativeElement).val(value);
$(this.select.nativeElement).material_select();
}
registerOnChange(fn: any) {
this.onChange = fn;
}
registerOnTouched(fn: any) {
this.onTouched = fn;
}
selectValue(value: string) {
this.value = value;
this.onChange && this.onChange(this.value);
this.onTouched && this.onTouched();
this.dropdownChanged.next(this.value);
}
ngOnDestroy(): void {
}
}
export class Option {
constructor(readonly value: any, readonly displayValue: string) {
}
}`
Then to use it, here's an example of a country select:
<div class="card-block">
<form #countryForm="ngForm" (ngSubmit)="save()">
<div class="row">
<div class="col-md-12">
<div class="md-form">
<dropdown-input [label]="'Country'" [options]="countries" [placeholder]="'Choose country'" name="inputCountry" [(ngModel)]="country"></dropdown-input>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12 text-center">
<button type="submit" class="btn btn-primary" [disabled]="countryForm.form.pristine || countryForm.form.invalid">Save</button>
</div>
</div>
</form>
</div>
The Component:
import {Component, ViewChild} from "@angular/core";
import {NgForm} from "@angular/forms";
import {Option} from "../common/dropdown-component";
import {Country} from "../../global/model/content/Country"; // my own model of a country (ISO, name)
import {plainToClass} from "class-transformer"; // optional helper library to convert my JSON to a TS type
@Component({
selector: 'edit-address',
template: require('./edit-address.template.html')
})
export class EditAddressComponent {
@ViewChild("countryForm")
countryForm: NgForm;
country: string; // assign initial value if you want, in my case an ISO code like "US"
countries:Array<Option> = (<Array<Country>>plainToClass(Country, require('../../assets/countries.json')))
.map((o:Country):Option => new Option(o.ISO, o.name));
save(): void {
// save country in persistence layer
// reset form for reuse:
this.countryForm.form.markAsPristine();
this.countryForm.form.markAsUntouched();
this.countryForm.form.updateValueAndValidity();
}
}
Note there are some details regarding loading the countries, which you can ignore really. Just use your own values. Note the Option class is defined at the bottom of the dropdown component.
Benny Bottema
pro answered 4 years ago
any as key. That's because we are managing the options manually and we don't have advanced string-key-to-object-backing-list management as Angular natively does with regular <select> elements.
/edit: I updated the Option class, but Ithe forum board won't let me edit my post anymore to reflect this. Really this board is behind times.
Piotr Bender
answered 4 years ago
ubbasel pro commented 3 years ago
Hi, I use the Angular Bootstrap with Material Design Version 4.3.7 Pro. But the problem remains the same. After trying the example as eplained here https://mdbootstrap.com/angular/advanced/material-select/#multiple the selection list is still empty. Any ideas? FranckDawid Adach pro commented 3 years ago
Dear , Apparently, we had a small bug in documentation - it should be mdb-select and not mdb-ng-select , I have already fixed docs. Please update your code accordingly.
HAYK TUNYAN
answered 3 years ago
Resolved
- User: Pro
- Premium support: No
- Technology: Angular
- MDB Version: -
- Device: -
- Browser: -
- OS: -
- Provided sample code: No
- Provided link: No