【问题标题】:Angular2 transform model for custom select Component自定义选择组件的Angular2变换模型
【发布时间】:2017-08-20 08:05:02
【问题描述】:

在我的 angular2 应用程序中,我希望有一个可重用的选择组件,在初稿中,它看起来像这样:

import {Component, Input, Output, EventEmitter} from "@angular/core";
@Component({
    selector: 'my-select',
    template: `
        <select [(ngModel)]="selectedValue" (ngModelChange)="selectionChanged()">
            <option disabled="disabled" selected="selected" name="choose" value="choose">choose ...</option>
            <option *ngFor="let opt of selectModel" [ngValue]="opt">
                {{opt}}
            </option>
        </select>
    `
})
export class SelectComponent {

    @Output()
    changed: EventEmitter<any> = new EventEmitter();

    @Input()
    selectModel: any[] = [];

    selectedValue: any = 'choose';

    selectionChanged() {
        this.changed.emit(this.selectedValue);
    }
}

不幸的是,这仅适用于字符串数组作为输入参数,因为

{{ opt }}

只会为其他类型打印出[Object object]。因此,EventEmitter 只会发出字符串。
现在,我想要的是一个组件,我可以像这样使用它:

import {Component} from "@angular/core";

export class Foo {
    bar: string;
    id: number;
    userFriendlyString: string = `id=${this.id}|bar=${this.bar}`;

    constructor(bar: string, id: number) {
        this.bar = bar;
        this.id = id;
    }
}

@Component({
    template: `<my-select [selectModel]="model" (changed)="handle($event)"></my-select>`
})
export class AppComponent {
    model: Foo[] = [new Foo('first', 1), new Foo('second', 2)];
    handle(foo: Foo): void {/* ... */}
}

我的意图:

  1. 告诉my-select 组件,显示的值应该是FoouserFriendlyString 属性。我不想硬编码,因为其他组件应该能够使用my-select 以及其他模型类。我无法想象该怎么做。我的第一个方法是为my-select 组件设置一个回调函数为@Input(),但这不起作用,不应该这样做according to this answer。第二种方法是覆盖 Foo 中的 toString。也不起作用(我假设 any 中缺少动态调度...?!)。
  2. EventEmitter 工作为“预期”:应该可以在句柄函数中有一个正确的foo: Foo

那么,我还有希望吗? :)

【问题讨论】:

    标签: angular components ngmodel


    【解决方案1】:

    我想我要做的是创建一个通用接口,组件可以将它们的对象映射到例如:

    export interface SelectListObject{
        key: string;
        value: any;
    }
    

    然后将其用作选择列表组件的输入类型:

    @Component({
        selector: 'my-select',
        template: `
            <select [(ngModel)]="selectedValue" (ngModelChange)="selectionChanged()">
                <option disabled="disabled" selected="selected" name="choose" value="choose">choose ...</option>
                <option *ngFor="let opt of selectModel" [ngValue]="opt.value">
                    {{opt.key}}
                </option>
            </select>
        `
    })
    export class SelectComponent {
    
        @Output()
        changed: EventEmitter<any> = new EventEmitter();
    
        @Input()
        selectModel: SelectListObject[] = [];
    
        selectedValue: any = 'choose';
    
        selectionChanged() {
            this.changed.emit(this.selectedValue);
        }
    }
    

    这样,您的所有组件都可以使用一个通用接口,并且在 option 元素中使用 ngValue 可以让您将整个对象作为值发出。

    您最了解您的其他数据模型,但您也许可以将 map 函数放在 select 组件的 @Input 中,这样每个组件就不必在将其数据发送到 SelectComponent 之前对其进行转换:

    internalSelectModel: SelectListObject[] = [];
    @Input('selectModel')
    set selectModel(value){
        this.internalSelectModel = value.map(x => <SelectListObject>{key: value.name, value: value};
    }
    

    handle 函数对于使用SelectComponent 的每个组件都是唯一的,因此该值可以是您需要(发送)的任何类型。

    希望对您有所帮助。

    【讨论】:

    • 像魅力一样工作 :) 我也有类似的想法,但是界面的两个部分,keyvalue 是缺失的东西
    【解决方案2】:

    你能做这样的事情吗,使用$event,这样你就可以返回值和你想要的任何东西,并将输入设置为获取带有显示和值的对象数组:-

    import {Component, Input, Output, EventEmitter} from "@angular/core";
    
    interface selectModel {
        display: string;
        value: any;
    }
    
    @Component({
    selector: 'my-select',
    template: `
        <select [(ngModel)]="selectedValue" (ngModelChange)="selectionChanged($event)">
            <option disabled="disabled" selected="selected" name="choose" value="choose">choose ...</option>
            <option *ngFor="let opt of selectModel" [ngValue]="opt.value">
                {{opt.display}}
            </option>
        </select>
    `
    })
        export class SelectComponent {
    
        @Output()
        changed: EventEmitter<any> = new EventEmitter();
    
        @Input()
        selectModel: selectModel[];
    
        selectedValue: any = 'choose';
    
        selectionChanged(event) {
            let response = {
                value: event.target.value,
                foo: "something else"
            }
            this.changed.emit(response);
        }
    }
    

    【讨论】:

    • 和上面的有点像……不过我喜欢通用的输入输出接口
    • 啊,我想我比他晚了 2 分钟才回答 :) 很高兴你解决了你的问题。
    猜你喜欢
    • 2019-04-01
    • 2013-09-13
    • 1970-01-01
    • 2019-05-14
    • 2021-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多