Holiday Notice: Support will be provided on a limited scale from December 24th, 2024, to January 2nd, 2025. Happy holidays and a wonderful New Year!


Topic: Material Select Issues with binding

stgiaf pro asked 6 years ago


Could you please provide an example of material select with 2 way binding and values coming from an API? It seems that in 2 way binding the material select triggers the change event when rendered, and ruins the object that it is bound to when loaded causing and undefined value. the code is following , together with a normal select element that is working fine: ts file import { Observable } from 'rxjs/Observable'; import { DepartmentService } from './../department.service'; import { UserService } from './../user.service'; //import { User } from './../models/user.type'; import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { IUser } from '../models/user'; import 'rxjs/add/observable/forkJoin'; @Component({ selector:'app-user-card', templateUrl:'./user-card.component.html', styleUrls: ['./user-card.component.scss'] }) export class UserCardComponent implements OnInit { loading:boolean; privatedepartments= []; privateuser:IUser= { id:0, name:' ', department : { id :"0", name:' ' } }; constructor(privateroute:ActivatedRoute, privateuserService:UserService, privatedepartmentService:DepartmentService) { this.route.params.subscribe ( p=> { this.user.id=+p['id'] ||0; }) } ngOnInit() { this.loading=true; varsources= [ this.departmentService.getDepartments(), this.userService.GetUser(this.user.id) ] Observable.forkJoin(sources).subscribe( data=> { console.log(data); data[0].forEach(element=> { this.departments.push( {'value': element.id, 'label' :element.name }); }); //this.departments = this.departments.slice(); if (this.user.department.id) { console.log('Department exists'); } this.setUser(data[1]); this.loading=false; }); } AddDepartment(){ //this.departments.push({value:"2", label:"Test"}) //console.log(this.departments); //this.departments = this.departments.slice(); //this.user.department.id="2"; console.log(this.user); } SelectOnChange(event) { console.log(this.user); console.log(event); } setUser( user:IUser){ this.user.id=user.id; this.user.name=user.name; this.user.department.id=user.department.id ; this.user.department.name=user.department.name console.log("user:" , this.user) } } html <div class="row"> <divclass=col-md-4> <divclass="card card-cascade narrower"> <divclass="view card-header text-center blue-gradient white-text"> <h4class="h4-responsive mb-0">User Card</h4> </div> <divclass="card-body"> <div *ngIf="loading"class="progress primary-color-dark"> <divclass="indeterminate"></div> </div> <form> <divclass="md-form mt-5"> <iclass="fa fa-user prefix gray-text"></i> <inputmdbActivetype="text"id="name"name="name" [(ngModel)]="user.name"> <labelclass="active"for="name">Your Name</label> </div> <divclass="md-form"> <divclass="row"> <divclass="col-md-6"> <mdb-selectname="department" [options]="departments" [(ngModel)]="user.department.id"placeholder="Choose Department"></mdb-select> <labelclass="active">Department</label> </div> </div> </div> <buttonclass="btn btn-primary" (click)="AddDepartment()">Add Department</button> </form> </div> </div> </div> <divclass=col-md-4> <divclass="card card-cascade narrower"> <divclass="view card-header text-center blue-gradient white-text"> <h4class="h4-responsive mb-0">User Card</h4> </div> <divclass="card-body"> <div *ngIf="loading"class="progress primary-color-dark"> <divclass="indeterminate"></div> </div> <form> <divclass="md-form mt-5"> <iclass="fa fa-user prefix gray-text"></i> <inputmdbActivetype="text"id="name"name="name" [(ngModel)]="user.name"> <labelclass="active"for="name">Your Name</label> </div> <divclass="md-form"> <divclass="row"> <divclass="col-md-6"> <labelclass="active">Department</label> </div> </div> </div> <buttonclass="btn btn-primary" (click)="AddDepartment()">Add Department</button> </form> </div> </div> </div> </div> <select class="browser-default mdb-select" [(ngModel)]="user.department.id" name="department"> <option *ngFor="let d of departments"value="{{d.value}}">{{ d.label}}</option> </select> Additionally it seems that mbd-select class cannot be applied to normal select element.

nthieu13 pro answered 6 years ago


I got the same issue. Look at my sample code:

 this.service.getData().subscribe(resp => {
    // for demo ignore the resp, bring this hardcode options outside the subscribe block and observe the 2-way binding works.
    this.options = [{ value: 1, label: 'Today'},
        { value: 2, label: 'Yesterday' },
        { value: 3, label: 'Last 7 days' },
        { value: 4, label: 'Last 30 days' },
        { value: 5, label: 'Last week' },
        { value: 6, label: 'Last month' }];
    });
 }

The above code is in ngOnInit() and  mdb-select is used in a Reactive Form. I believe mdb-select has not managed its state correctly against async changes. Additionally, the arrow is missing, adding 'z-index: 1' in global css makes the arrow appears but clicking on that arrow opens the option list and close it immediately. The label not floating like input text which I have to make a wrapper for it. I hope the mdb-select will be like https://material.angular.io/components/select/overview in future release.


Damian Gemza staff commented 6 years ago

Dear nthieu13, which problem do you have with your code?

itdev pro commented 6 years ago

I am having the same issue. The Arrow does not appear and the selected value does not work when changes are made within an observable.

Damian Gemza staff answered 6 years ago


Hello stgiaf, Yes, I'm obtaining data from fake API in asynchronous way. Here's my code, so u can check it: .html file:
<div class="row">

<div class="col-md-6 mx-auto my-5">

<mdb-select [(ngModel)]="choosen.department.id" [options]="optionsSelect" placeholder="Choose your option"></mdb-select>

<label>Example label</label>

</div>

</div>

<div class="row">

<divclass="col-md-6 mx-auto my-5">

<div>

OPCJA: {{choosen.department.id}}

</div>

</div>

</div>
.ts file:
optionsSelect: Array<any>;

privatechoosen= {

id:0,

title:'',

department: {

id:0,

}

};

url='https://jsonplaceholder.typicode.com/posts';

constructor(privatehttp:Http) { }

getData() {

returnthis.http.get(this.url).map(res=>res.json());

}

ngOnInit() {

this.getData().subscribe(next=> {

console.log(next);

this.optionsSelect= [

{ value: next[0].id, label: next[0].title },

{ value: next[1].id, label: next[1].title },

{ value: next[2].id, label: next[2].title },

{ value: next[3].id, label: next[3].title },

{ value: next[4].id, label: next[4].title },

{ value: next[5].id, label: next[5].title },

];

});

}

}
For me, everything works fine.
Best Regards,
Damian

Damian Gemza staff answered 6 years ago


Hello stgiaf, It's looks like that i've posted you solution of this problem at your's email. Please check it. For now i will mark post as resolved. Best Regards, Damian

stgiaf pro commented 6 years ago

Hello Damian, No this is something different, with material-select

Damian Gemza staff commented 6 years ago

Dear stgiaf, I've tried to reproduce your error following closely your steps, but for me, everything is working as expected. Could you tell me one more time, which thing doesn't work for you well, in which way works now, and what is your expected behavior of this thing? Best Regards, Damian

stgiaf pro commented 6 years ago

Hello Damian, Did you try to recieve the data via a service asynchronously, and the behavior of your material select was the same as a normal select? I my case, when everything is completed the variable that ngModel is bound to is "undefined" , although from the service it comes correctly and also the values exists in the [options] input. This happens, possibly because at the time of rendering the control, the observable has not yet been completed and then the values are lost somehow. if you remove two way binding and do it with one way it works. The issue here is that mdb material select works differently from normal select element. If you have a working example of material select with values coming from a service (http) via objssrvable and values bound to a model of yours with ngModel, then supply it to me , so that I can replicate.


Please insert min. 20 characters.

FREE CONSULTATION

Hire our experts to build a dedicated project. We'll analyze your business requirements, for free.

Status

Answered

Specification of the issue

  • ForumUser: Pro
  • Premium support: No
  • Technology: MDB Angular
  • MDB Version: -
  • Device: -
  • Browser: -
  • OS: -
  • Provided sample code: No
  • Provided link: No
Tags