Angular ngx-mat-select-search无法处理动态数据

时间:2018-10-23 05:01:16

标签: angular

我在我的项目中使用ngx-mat-select-search组件。我提到了以下示例:

此示例在我的角度项目中运行良好。但是,如果我将动态数据用作下拉选项,则搜索栏将无法正常工作。

我的代码如下:

HTML文件:

<mat-form-field>
  <mat-select [formControl]="bankCtrl"  #singleSelect>
    <ngx-mat-select-search [formControl]="bankFilterCtrl"></ngx-mat-select-search>
    <mat-option value = "select">Select bank</mat-option>
    <mat-option *ngFor="let app of apps" [value]="app">
      {{app.name}}
    </mat-option>
  </mat-select>
</mat-form-field>

TS文件:

import { Component, NgZone, OnInit, OnDestroy, ViewChild, HostListener, ViewEncapsulation } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
//import { MenuItems } from '../../shared/menu-items/menu-items';
import { MenuItems } from '../../bridle-menus/menu-items/menu-items';
import { Subscription } from 'rxjs/Subscription';
import 'rxjs/add/operator/filter';

import { TranslateService } from '@ngx-translate/core';

import { PerfectScrollbarConfigInterface, PerfectScrollbarDirective } from 'ngx-perfect-scrollbar';
import { ClientService, User, LocationService, ProcessAdminServices, Userinfo } from '../../shared/services/index';
import { AuthService } from "../../shared/services/auth.service";
import { env_host } from "../../shared/services/endpoints";
import { Globals } from '../../shared/services/globals';

import { AppDefinitionRepresentationModel, ProcessService, ProcessDefinitionRepresentation, ProcessInstance } from "../../process-services/index";
import {FormControl} from '@angular/forms';
import { Observable, ReplaySubject, Subject } from 'rxjs';
import { map, startWith, takeUntil, take } from 'rxjs/operators';
import { AppsProcessService, AuthenticationService, LogService, UserPreferencesService } from "../../core/index";
//added on 22-10-2018
import { VERSION, MatSelect } from '@angular/material';

const SMALL_WIDTH_BREAKPOINT = 960;
//added on 22-10-2018
interface Bank {
/** id: number;
 name: string;**/
 defaultAppId: string;
    deploymentId: string;
    name: string;
    description: string;
    theme: string;
    icon: string;
    id: number;
    modelId: number;
    tenantId: number;
}
@Component({
  selector: 'app-layout',
  templateUrl: './admin-layout.component.html',
  styleUrls: ['admin-layout.component.scss'],
  providers:[ClientService,AuthService,LocationService,ProcessAdminServices,AppsProcessService,ProcessService],
  encapsulation: ViewEncapsulation.None
})
export class AdminLayoutComponent implements OnInit, OnDestroy {
  banks: any;

  private _router: Subscription;

  mediaMatcher: MediaQueryList = matchMedia(`(max-width: ${SMALL_WIDTH_BREAKPOINT}px)`);
  today: number = Date.now();
  url: string;
  showSettings = false;
  dark: boolean;
  boxed: boolean;
  collapseSidebar: boolean;
  compactSidebar: boolean;
  currentLang = 'en';
  dir = 'ltr';
  sidePanelOpened;
  user;
  scopes: string;
  returnscope: string;
  userinform = [];
  locationId: string;
  dspName: string;
  dropdownStyle: string;
  apps = [];
   //Bank=[];
  statusCode: number;
  currentApp: string = "";
  selectedApp= [];
  myapp;
  processDefinitions: ProcessDefinitionRepresentation[] = [];
  processDefinitionKey:string;
  start:string="start";
  authenticated: boolean;
  userinfo: Userinfo;
  @ViewChild('sidemenu') sidemenu;
  @ViewChild(PerfectScrollbarDirective) directiveScroll: PerfectScrollbarDirective;

  public config: PerfectScrollbarConfigInterface = {};
  //Added on 22-10-2018
  version = VERSION;
  /** control for the selected bank */
  public bankCtrl: FormControl = new FormControl();

   /** control for the MatSelect filter keyword */
  public bankFilterCtrl: FormControl = new FormControl();
/*private banks: Bank[] = [
    {name: 'Bank A (Switzerland)', id: 'A'},
    {name: 'Bank B (Switzerland)', id: 'B'},
    {name: 'Bank C (France)', id: 'C'},
    {name: 'Bank D (France)', id: 'D'},
    {name: 'Bank E (France)', id: 'E'},
    {name: 'Bank F (Italy)', id: 'F'},
    {name: 'Bank G (Italy)', id: 'G'},
    {name: 'Bank H (Italy)', id: 'H'},
    {name: 'Bank I (Italy)', id: 'I'},
    {name: 'Bank J (Italy)', id: 'J'},
    {name: 'Bank Kolombia (United States of America)', id: 'K'},
    {name: 'Bank L (Germany)', id: 'L'},
    {name: 'Bank M (Germany)', id: 'M'},
    {name: 'Bank N (Germany)', id: 'N'},
    {name: 'Bank O (Germany)', id: 'O'},
    {name: 'Bank P (Germany)', id: 'P'},
    {name: 'Bank Q (Germany)', id: 'Q'},
    {name: 'Bank R (Germany)', id: 'R'}
  ];*/

    /** list of banks filtered by search keyword */
  public filteredBanks: ReplaySubject<Bank[]> = new ReplaySubject<Bank[]>(1);
    @ViewChild('singleSelect') singleSelect: MatSelect;
    /** Subject that emits when the component has been destroyed. */
  private _onDestroy = new Subject<void>();

  constructor(
    private router: Router, public menuItems: MenuItems, private globals: Globals,
    public translate: TranslateService, zone: NgZone,private clientService:ClientService,private authService: AuthService,private processAdminServices: ProcessAdminServices,
    private appsProcessService:AppsProcessService,
    private processService: ProcessService,
    private authenticationService: AuthenticationService,
        private logService: LogService,
        private userPreferenceService: UserPreferencesService

) {
          userPreferenceService.authType='BPM';

    const browserLang: string = translate.getBrowserLang();
    translate.use(browserLang.match(/en|fr/) ? browserLang : 'en');
    this.mediaMatcher.addListener(mql => zone.run(() => {
      this.mediaMatcher = mql;
    }));
  }

  ngOnInit(): void {
    this.getScopes();
    this.login();
    this.getUserInfo();
    this.url = this.router.url;
    this.dropdownStyle = "dropdown-content";
 //ADDED ON 22-10-2018
    // set initial selection
    this.bankCtrl.setValue(this.apps[0]);
     // load the initial bank list
    this.filteredBanks.next(this.apps.slice());
// listen for search field value changes
    this.bankFilterCtrl.valueChanges
      .pipe(takeUntil(this._onDestroy))
      .subscribe(() => {
        this.filterBanks();
      });




    this._router = this.router.events.filter(event => event instanceof NavigationEnd).subscribe((event: NavigationEnd) => {
      document.querySelector('.app-inner > .mat-drawer-content > div').scrollTop = 0;
      this.url = event.url;
      this.runOnRouteChange();
    });


  }

//ADDED on 22-10-2018
ngAfterViewInit() {
    this.setInitialValue();
  }

   /**
   * Sets the initial value after the filteredBanks are loaded initially
   */
  private setInitialValue() {
    this.filteredBanks
      .pipe(take(1), takeUntil(this._onDestroy))
      .subscribe(() => {
        // setting the compareWith property to a comparison function
        // triggers initializing the selection according to the initial value of
        // the form control (i.e. _initializeSelection())
        // this needs to be done after the filteredBanks are loaded initially
        // and after the mat-option elements are available
        this.singleSelect.compareWith = (a: Bank, b: Bank) => a && b && a.id === b.id;
       // this.multiSelect.compareWith = (a: Bank, b: Bank) => a && b && a.id === b.id;
      });
  }
  ngOnDestroy(): void  {
    this._router.unsubscribe();
    //added on 22-10-2018
     this._onDestroy.next();
    this._onDestroy.complete();
  }

  runOnRouteChange(): void {
    if (this.isOver()) {
      this.sidemenu.close();
    }

    this.updatePS();
  }

  isOver(): boolean {
    if (this.url === '/apps/messages' ||
      this.url === '/apps/calendar' ||
      this.url === '/apps/media' ||
      this.url === '/maps/leaflet' ||
      this.url === '/taskboard') {
      return true;
    } else {
      return this.mediaMatcher.matches;
    }
  }

  menuMouseOver(): void {
    if (this.mediaMatcher.matches && this.collapseSidebar) {
      this.sidemenu.mode = 'over';
    }
  }

  menuMouseOut(): void {
    if (this.mediaMatcher.matches && this.collapseSidebar) {
      this.sidemenu.mode = 'side';
    }
  }

  updatePS(): void  {
    if (!this.mediaMatcher.matches && !this.compactSidebar) {
      setTimeout(() => {
        this.directiveScroll.update();
      }, 350);
    }
  }

  // addMenuItem(): void {
  //   this.menuItems.add({
  //     state: 'menu',
  //     name: 'MENU',
  //     type: 'sub',
  //     icon: 'trending_flat',
  //     role: 'admin',
  //     children: [
  //       {state: 'menu', name: 'MENU'},
  //       {state: 'timeline', name: 'MENU'}
  //     ]
  //   });
  // }

logout(){
    //alert("coming in logout");
    // this.clientService.logout();
    // this.router.navigate(["/"]);
  this.clientService.logout()
     /**.subscribe(
 data => {
              this.router.navigate(['']);      
        });**/
        .subscribe(successCode => {
        //alert("logged out");
          // this.router.navigate(['/']);
          // this.router.navigate(['']);
          // this.router.navigateByUrl('');
          // this.returnUrl = this.route.snapshot.queryParams['localhost:8088'] || '/';
           //alert("returnUrl Is:"+this.returnUrl);
                 //              this.router.navigate([this.returnUrl]);
                                  //localStorage.removeItem('loggedInUserName');

    window.location.href=env_host+"/";

         }
         );
  }   

  getScopes() {
    this.authService.getScopes()
      .subscribe(
      data => {
        this.scopes = data;
        console.log("scopes=>"+this.scopes);
        if (this.scopes.includes("admin")) {
          this.returnscope = "yes";
          return this.returnscope
        }
      });
  }

  getUserInfo(){
    this.clientService.getUserInform()
      .subscribe(
        data => {

          this.userinform = data;
          console.log("userInform data=>",this.userinform);
          //localStorage.setItem('loggedInUserName', this.userinform[0].username);
          this.dspName= this.userinform[0].displayname;
          this.locationId = this.userinform[0].location_id;
          //var loggedInUser = localStorage.getItem('loggedInUserName');
          //this.getApps(loggedInUser);
}
) 
}

public getLocationId(locationIdAndName: any) {
  this.globals.locationIdAndName = locationIdAndName;
}

//lists logged in user's applications 
getApps(loggedInUser) {
                  this.processAdminServices.getApps(loggedInUser)
         .subscribe(
              data =>{ 
                let appsData = data["data"];
                      this.apps = appsData.filter(app => { 
                      if(app.id != null) { 
                     return app;
                      } 

                     });
                      },
              errorCode =>  {this.statusCode = errorCode}

                            );

 }

//On select application from drop down should redirect to start process form of the selected app
    onAppClickToStartProcess(myapp) {
    this.selectedApp = this.getSelectedAppByName(myapp);

  let appName = this.selectedApp['name'];
     let appId = this.selectedApp['id'];
                  this.processService.getProcessDefinitions(appId).subscribe(

        data => {
          this.processDefinitions = data;

          this.processDefinitionKey = this.processDefinitions[0].key;
         this.router.navigate(['app-list/activiti/start1',appId || 0,appName,this.processDefinitionKey,this.start,this.processDefinitions[0].id]);

       });
    }
  //get selected application details by app name  
getSelectedAppByName(myapp: string) {
    return this.apps.find(app => app.name === myapp);
}

public enableDropdown() {
  if (this.dropdownStyle == "dropdown-content") {
    this.dropdownStyle = "dropdown-content-enable";
  }
  else {
    this.dropdownStyle = "dropdown-content";
  }
}

@HostListener('mouseup')
  onMouseUp() {
    if (this.dropdownStyle == "dropdown-content-enable") {
    this.dropdownStyle = "dropdown-content";
    }
  }

  login() {
    this.clientService.getUserInfo()
          .subscribe(
            data => {

              this.userinfo = data;
                 this.authenticationService.login(this.userinfo.email, 'Bridle@456', true)
        .subscribe(
            (ticket: any) => {

              this.logService.info(ticket);
               this.authenticated=true;
               if(this.authenticated == true){
        this.getDeployedApps();
        }
            },
            (err: any) => {
               // this.actualLoginStep = LoginSteps.Landing;
               this.authenticated=false;
            },
            () => console.log('Login done')

        );}
    )
      }

      getDeployedApps() {

        this.appsProcessService.getDeployedApplications()
.subscribe(
    data =>{ 
      let appsData = data;

            this.apps = appsData.filter(app => { 
            if(app.id != null) { 
           return app;

            } 
           });
           /**this.Bank = appsData.filter(app => { 
            if(app.id != null) { 
           return app;

            } 
           });**/
           this.banks: Bank[] = appsData.filter(app => { 
            if(app.id != null) { 
           return app;

            } 
           });
           console.log("BANK DETAILS");
          // console.dir(this.Bank);
            },


    errorCode =>  {this.statusCode = errorCode}

                  );

}

//ADDED on 22-10-2018
private filterBanks() {
    if (!this.apps) {
      return;
    }
    // get the search keyword
    let search = this.bankFilterCtrl.value;
    if (!search) {
      this.filteredBanks.next(this.apps.slice());
      return;
    } else {
      search = search.toLowerCase();
    }
    // filter the banks
    this.filteredBanks.next(
      this.apps.filter(app => app.name.toLowerCase().indexOf(search) > -1)
    );
  }

}

我通过以下方式传递了动态数据,而不是静态库值:

this.banks: Bank[] = appsData.filter(app => { 
            if(app.id != null) { 
           return app;

            } 
           });

但是它给'Bank'仅指一种类型,但是在这里被用作值。

该如何解决? 请提供解决此问题的解决方案。

感谢与问候

希尔帕·库尔卡尼

2 个答案:

答案 0 :(得分:0)

在当前代码中,您已经在类声明的正下方声明了“ banks”类变量的类型:

export class AdminLayoutComponent implements OnInit, OnDestroy {
banks: any;
...

因此,您无需再次声明类型。只需将上面的代码片段更改为以下内容:

this.banks = appsData.filter(app => { 
    if(app.id != null) { 
        return app;
    } 
});

注意-从代码中还不清楚您实际上要完成什么。此答案将解决您提到的错误,但可能无法帮助您解决实际上要解决的问题。

答案 1 :(得分:0)

此问题已在此处回答并接受:

https://github.com/bithost-gmbh/ngx-mat-select-search/issues/72

模板需要更改为

*ngFor="let app of apps"

*ngFor="let app of filteredBanks | async"

getDeployedApps() {

    this.appsProcessService.getDeployedApplications()
    .subscribe(data =>{ 
         ...
         this.filteredBanks.next(data.slice());
    })

}

由于问题的作者已接受https://github.com/bithost-gmbh/ngx-mat-select-search/issues/72中的答案并确认解决方案有效,因此应将其作为接受的答案。