当前位置: 首页 > 知识库问答 >
问题:

角材料-自定义自动完成组件

公羊雅达
2023-03-14

我试图创建自己的自定义angular material组件,该组件能够使用mat-form-field控件。

除此之外,我希望该控件使用mat-autocomplete指令。

我的目的只是创建一个更好看的mat-autocomplete组件,该组件包含一个集成的clear按钮和自定义css箭头,如下图所示。我使用标准组件成功地获得了它,并添加了我想要的内容,但现在我想将它导出到泛型组件中。

    null
  • 即使正确选择了值,我的窗体也无效。
  • 选择某个选项后,占位符自身设置不正确。
  • 自动完成筛选选项根本不起作用
  • 如果我没有具体单击输入,焦点就不会正确触发。

我认为我的前三个问题是由自动完成值导致的,该值没有正确地链接到我的反应表单

这里有一个与该项目的个人公共存储库的直接链接(因为在这里显示的问题有点大):Git存储库:https://github.com/tenmak/Material。

  <mat-form-field>
    <div fxLayout="row">
      <input matInput placeholder="Thématique" [matAutocomplete]="thematicAutoComplete" formControlName="thematique" tabindex="1">

      <div class="mat-select-arrow-wrapper">
        <div class="mat-select-arrow" [ngClass]="{'mat-select-arrow-down': !thematicAutoComplete.isOpen, 'mat-select-arrow-up': thematicAutoComplete.isOpen}"></div>
      </div>
    </div>
    <button mat-button *ngIf="formDossier.get('thematique').value" matSuffix mat-icon-button aria-label="Clear" (click)="formDossier.get('thematique').setValue('')">
      <mat-icon>close</mat-icon>
    </button>

    <mat-hint class="material-hint-error" *ngIf="!formDossier.get('thematique').hasError('required') && formDossier.get('thematique').touched && formDossier.get('thematique').hasError('thematiqueNotFound')">
      <strong>
        Veuillez sélectionner un des choix parmi les options possibles.
      </strong>
    </mat-hint>
  </mat-form-field>

  <mat-autocomplete #thematicAutoComplete="matAutocomplete" [displayWith]="displayThematique">
    <mat-option *ngFor="let thematique of filteredThematiques | async" [value]="thematique">
      <span> {{thematique.code}} </span>
      <span> - </span>
      <span> {{thematique.libelle}} </span>
    </mat-option>
  </mat-autocomplete>
  <mat-form-field>
    <siga-auto-complete placeholder="Thématique" [tabIndex]="1" [autoCompleteControl]="thematicAutoComplete" formControlName="thematique">
    </siga-auto-complete>

    <mat-hint class="material-hint-error" *ngIf="!formDossier.get('thematique').hasError('required') && formDossier.get('thematique').touched && formDossier.get('thematique').hasError('thematiqueNotFound')">
      <strong>
        Veuillez sélectionner un des choix parmi les options possibles.
      </strong>
    </mat-hint>
  </mat-form-field>

  <mat-autocomplete #thematicAutoComplete="matAutocomplete" [displayWith]="displayThematique">
    <mat-option *ngFor="let thematique of filteredThematiques | async" [value]="thematique">
      <span> {{thematique.code}} </span>
      <span> - </span>
      <span> {{thematique.libelle}} </span>
    </mat-option>
  </mat-autocomplete>

下面是我对泛型组件代码的尝试(简化):

class AutoCompleteInput {
    constructor(public testValue: string) {
    }
}

@Component({
    selector: 'siga-auto-complete',
    templateUrl: './autocomplete.component.html',
    styleUrls: ['./autocomplete.component.scss'],
    providers: [
        {
            provide: MatFormFieldControl,
            useExisting: SigaAutoCompleteComponent
        },
        {
            provide: NG_VALUE_ACCESSOR,
            useExisting: forwardRef(() => SigaAutoCompleteComponent),
            multi: true
        }
    ],
})
export class SigaAutoCompleteComponent implements MatFormFieldControl<AutoCompleteInput>, AfterViewInit, OnDestroy, ControlValueAccessor {
    ...
    parts: FormGroup;
    ngControl = null;

    ...

    @Input()
    get value(): AutoCompleteInput | null {
        const n = this.parts.value as AutoCompleteInput;
        if (n.testValue) {
            return new AutoCompleteInput(n.testValue);
        }
        return null;
    }
    set value(value: AutoCompleteInput | null) {
        // Should set the value in the form through this.writeValue() ??
        console.log(value);
        this.writeValue(value.testValue);
        this.stateChanges.next();
    }

    @Input()
    set formControlName(formName) {
        this._formControlName = formName;
    }
    private _formControlName: string;

    // ADDITIONNAL
    @Input() autoCompleteControl: MatAutocomplete;
    @Input() tabIndex: string;

    private subs: Subscription[] = [];

    constructor(fb: FormBuilder, private fm: FocusMonitor, private elRef: ElementRef) {
        this.subs.push(
            fm.monitor(elRef.nativeElement, true).subscribe((origin) => {
                this.focused = !!origin;
                this.stateChanges.next();
            })
        );

        this.parts = fb.group({
            'singleValue': '',
        });

        this.subs.push(this.parts.valueChanges.subscribe((value: string) => {
            this.propagateChange(value);
        }));
    }

    ngAfterViewInit() {
        // Wrong approach but some idea ?
        console.log(this.autoCompleteControl);
        this.autoCompleteControl.optionSelected.subscribe((event: MatAutocompleteSelectedEvent) => {
            console.log(event.option.value);
            this.value = event.option.value;
        })
    }

    ngOnDestroy() {
        this.stateChanges.complete();
        this.subs.forEach(s => s.unsubscribe());
        this.fm.stopMonitoring(this.elRef.nativeElement);
    }

    ...

    // CONTROL VALUE ACCESSOR
    private propagateChange = (_: any) => { };

    public writeValue(a: string) {
        console.log('wtf');

        if (a && a !== '') {
            console.log('value => ', a);
            this.parts.setValue({
                'singleValue': a
            });
        }
    }
    public registerOnChange(fn: any) {
        this.propagateChange = fn;
    }

    public registerOnTouched(fn: any): void {
        return;
    }

    public setDisabledState?(isDisabled: boolean): void {
        this.disabled = isDisabled;
    }
}

共有1个答案

杨良才
2023-03-14

终于解决了!!!

>

  • 这里的问题是,当在子[SigaAutoCompleteComponent]中创建输入字段时,父[CreateDossierComponent]必须知道在子[CreateDossierComponent]中填充的值,这部分丢失了,这就是它不能变为有效的原因,因为它认为输入字段没有被触及[保持无效]--通过向父[SigaAutoCompleteComponent]发出值,然后根据需要操作窗体控件来解决这个问题。
  • 溢出mat-form-field和input导致了这个问题--通过将mat-form-field元素移动到child来解决这个问题,其他代码保持不变,这解决了占位符重叠和单击箭头图标来显示
  • 这是可以做到的--[重新设计的一种方法],将服务注入子组件并在那里执行自动完成功能[我还没有实现这一点,但这将工作,因为它只是部门字段的副本]

    在create-doiser.component.html

          <!-- </div> -->
          <mat-autocomplete #thematicAutoComplete="matAutocomplete" [displayWith]="displayThematique">
            <mat-option *ngFor="let thematique of filteredThematiques | async" [value]="thematique">
              <span> {{thematique.code}} </span>
              <span> - </span>
              <span> {{thematique.libelle}} </span>
            </mat-option>
          </mat-autocomplete>
    

    在autocomplete.component.html中

    <mat-form-field style="display:block;transition:none ">
    <div fxLayout="row">
      <input  matInput   placeholder="Thématique" [matAutocomplete]="autoCompleteControl" (optionSelected)="test($event)" tabindex="{{tabIndex}}">
      <div class="mat-select-arrow-wrapper" (click)="focus()">
        <div class="mat-select-arrow" [ngClass]="{'mat-select-arrow-down': !autoCompleteControl.isOpen, 'mat-select-arrow-up': autoCompleteControl.isOpen}"></div>
      </div>
    </div>
    
    </mat-form-field>
    

    在autocomplete.component.ts中

    in set value emit the value to parent
    this.em.emit(value);
    

    create-dosier.component.ts

      this.thematique = new FormControl( ['', [Validators.required, this.thematiqueValidator]]
    
        ); 
    
    this.formDossier.addControl('thematique',this.thematique);
    call(event){
    
        this.thematique.setValue(event);
        this.thematique.validator=this.thematiqueValidator();
        this.thematique.markAsTouched();
        this.thematique.markAsDirty();
    
      }
    }
    

  •  类似资料:
    • 当我在material design上用autocomplete实现时,我有一个关于angular 2的错误,我不知道为什么,因为这是我第一次用后端ASP.NET核心实现它。我尝试安装一些ng2库,但根本不起作用。下面是我的代码: 错误如下:

    • 我正在尝试使用Angular Material版本7和Angular 6制作一个自定义MatFormFieldControl。自定义输入是一个重量输入,它有一个值(输入类型=“数字”)和一个单位(选择“kg”、“g”、…)。它必须放在mat form字段控件中,使用反应式表单(formControlName=“weight”)并支持错误状态(

    • 我想在表单中使用jQuery.AutoComplete.js插件进行输入。我想在客户端进行搜索,不能使用Ajax。但我不想在数组中使用一些简单的基于“包含”的搜索算法。我要做的是用javascript编写一个自定义搜索函数,对结果进行搜索和排序。这可能吗?怎么可能? 谢谢你抽出时间。

    • 我正在将Angular 2与角度材料一起使用,我需要创建自定义主题,以便为组件使用自定义颜色。我遵循了有角度的文档,但我无法让它运行。 到目前为止我所做的: 1.我创建了一个文件my-theme.scss: 2.我将创建的SASS文件导入styles.css 3.我在.angular cli中引用了它。样式部分中的json文件: 我在本地主机下的网站告诉我“编译失败”模块未找到:“../node_

    • 问题内容: 如何通过“静态”方面和“动态”方面自定义的完成?静态方面是因为某些条目是已知的,并在构造时使用添加到了组合框文本中。动态方面是因为我还需要通过一些回调函数来完成,也就是说,一旦键入了几个字符,即在创建窗口小部件之后 动态地 完成。 我的应用程序使用的是Boehm的GC(当然不包括GTK对象),例如Guile或SCM或Bigloo。它可以看作是一种实验 性的持久性 动态类型的编程语言实现

    • 我在Angular 5中构建了一个动态表单组件(基于https://angular.io/guide/dynamic-form的留档和示例)。 一切正常,直到我尝试使用有棱角的材料。 我在这里读过很多关于类似问题的文章,但它们似乎都是因为人们没有导入正确的模块,或者没有使用mdInput或mat Input而不是matInput。我遇到的问题并非如此。 任何想法或建议将不胜感激。 已更改代码-因错