Topic: MDB Select is not working in Angular 2
Bartłomiej Malanowski staff pro premium answered 8 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 8 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 8 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 8 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 8 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 8 years ago
Hello,In response to your issue, I wanted to let you know about just released MDBootstrap Angular kit, that may be a sufficient solution to this or any other issues you have had with Angular integration so far.The kit can be found at the following link:https://mdbootstrap.com/angular/It contains all the components you could find in MDB jQuery version.We encourage you to try it out and report any bugs or issues at contact@mdbootstrap.com with [Angular] prefix or create a thread on this forum.Have a great day!
ubbasel pro commented 7 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 7 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 6 years ago
FREE CONSULTATION
Hire our experts to build a dedicated project. We'll analyze your business requirements, for free.
Resolved
- User: Pro
- Premium support: No
- Technology: MDB Angular
- MDB Version: -
- Device: -
- Browser: -
- OS: -
- Provided sample code: No
- Provided link: No