typescript - ngform - Seleccionar basado en enum en Angular2
ngform angular 6 (9)
Tengo esta enumeración (estoy usando TypeScript ):
export enum CountryCodeEnum {
France = 1,
Belgium = 2
}
Me gustaría crear una selección en mi formulario , con para cada opción el valor entero de enumeración como valor y el texto de enumeración como etiqueta, de esta manera:
<select>
<option value="1">France</option>
<option value="2">Belgium</option>
</select>
Cómo puedo hacer esto ?
A partir de Angular 6.1 y superior, puede usar el
KeyValuePipe
como se
KeyValuePipe
a continuación (pegado de documentos angular.io).
Supongo que una enumeración contiene cadenas legibles para los humanos, por supuesto :)
@Component({
selector: ''my-app'',
providers: [],
template: `
<select>
<option *ngFor="let key of keys" [value]="key" [label]="countries[key]"></option>
</select>`,
directives: []
})
export class App {
countries = CountryCodeEnum;
constructor() {
this.keys = Object.keys(this.countries)
.filter(f => !isNaN(Number(f)))
.map(k => parseInt(k));;
}
}
Aquí hay una forma muy sencilla para Angular2 v2.0.0.
En aras de la integridad, he incluido un ejemplo de establecer un valor predeterminado del
country
seleccionado a través de
formularios reactivos
.
export function enumSelector(definition) {
return Object.keys(definition)
.map(key => ({ value: definition[key], title: key }));
}
Con las enumeraciones de cadenas puedes probar esto.
Mi string enum tiene la siguiente definición:
{
Published: "published",
published: "Published",
Draft: "draft",
draft: "Draft"
}
y se traduce a js de la siguiente manera:
@Injectable()
export class UtilsService {
stringEnumToKeyValue(stringEnum) {
const keyValue = [];
const keys = Object.keys(stringEnum).filter((value, index) => {
return !(index % 2);
});
for (const k of keys) {
keyValue.push({key: k, value: stringEnum[k]});
}
return keyValue;
}
}
Tengo algunos de estos en mi proyecto, así que creé una pequeña función auxiliar en una biblioteca de servicio compartido:
statusSelect;
constructor(private utils: UtilsService) {
this.statusSelect = this.utils.stringEnumToKeyValue(StatusEnum);
}
Inicie en su constructor de componentes y vincúlelo a su plantilla de esta manera:
En componente:
<option *ngFor="let status of statusSelect" [value]="status.value">
{{status.key}}
</option>
En plantilla:
import { Component } from ''@angular/core'';
enum AgentStatus {
available =1 ,
busy = 2,
away = 3,
offline = 0
}
@Component({
selector: ''my-app'',
template: `
<h1>Choose Value</h1>
<select (change)="parseValue($event.target.value)">
<option>--select--</option>
<option *ngFor="let name of options"
[value]="name">{{name}}</option>
</select>
<h1 [hidden]="myValue == null">
You entered {{AgentStatus[myValue]}}
</h1>`
})
export class AppComponent {
options : string[];
myValue: AgentStatus;
AgentStatus : typeof AgentStatus = AgentStatus;
ngOnInit() {
var x = AgentStatus;
var options = Object.keys(AgentStatus);
this.options = options.slice(options.length / 2);
}
parseValue(value : string) {
this.myValue = AgentStatus[value];
}
}
No olvide agregar el Servicio de servicios a la matriz de proveedores en su app.module.ts para que pueda inyectarlo fácilmente en diferentes componentes.
Soy un novato mecanografiado, así que corríjame si me equivoco o si hay mejores soluciones.
He preferido tener una función de utilidad simple compartida en mi aplicación angular, para convertir la
enum
en una matriz estándar para crear selecciones:
public countries = enumSelector(CountryCodeEnum);
para llenar una variable en el Componente con:
<md-select placeholder="Country" [(ngModel)]="country" name="country">
<md-option *ngFor="let c of countries" [value]="c.value">
{{ c.title }}
</md-option>
</md-select>
y luego llene mi Material Select como mis antiguos basados en matriz:
@Component({
selector: ''my-app'',
providers: [],
template: `
<select>
<option *ngFor="let key of keys" [value]="key" [label]="countries[key]"></option>
</select>`,
directives: []
})
export class App {
countries = CountryCodeEnum;
constructor() {
this.keys = Object.keys(this.countries).filter(f => !isNaN(Number(f)));
}
}
// ** NOTE: This enum contains 0 index **
export enum CountryCodeEnum {
Unset = 0,
US = 1,
EU = 2
}
Gracias por este hilo!
Otra solución similar, que no omite "0" (como "Unset"). Usar filtro (Número) en mi humilde opinión no es un buen enfoque.
@Component({
selector: ''keyvalue-pipe'',
template: `<span>
<p>Object</p>
<div *ngFor="let item of object | keyvalue">
{{item.key}}:{{item.value}}
</div>
<p>Map</p>
<div *ngFor="let item of map | keyvalue">
{{item.key}}:{{item.value}}
</div>
</span>`
})
export class KeyValuePipeComponent {
object: {[key: number]: string} = {2: ''foo'', 1: ''bar''};
map = new Map([[2, ''foo''], [1, ''bar'']]);
}
Otro giro de esta respuesta, pero en realidad esto asigna los valores como números, en lugar de convertirlos en cadenas, lo cual es un error. También funciona con 0 enumeraciones basadas
enum StatusEnum {
Published = <any> ''published'',
Draft = <any> ''draft''
}
Una solución más si no desea crear una nueva tubería. También puede extraer claves en la propiedad auxiliar y usarla:
@Component({
selector: ''my-app'',
providers: [],
template: `
<div>
<select id="country" formControlName="country">
<option *ngFor="let key of keys" [value]="key">{{countries[key]}}</option>
</select>
</div>
`,
directives: []
})
export class App {
keys: any[];
countries = CountryCodeEnum;
constructor(private fb: FormBuilder) {
this.keys = Object.keys(this.countries).filter(Number);
this.country = CountryCodeEnum.Belgium; //Default the value
}
}
Demostración: http://plnkr.co/edit/CMFt6Zl7lLYgnHoKKa4E?p=preview
Editar:
si necesita las opciones como números en lugar de cadenas:
-
reemplazar
[value]
con[ngValue]
-
agregue
.map(Number)
después de.filter(...)
Esta es la mejor opción que puede aplicar sin tuberías ni código adicional.
import { Component } from ''@angular/core''; enum AgentStatus { available =1 , busy = 2, away = 3, offline = 0 } @Component({ selector: ''my-app'', template: ` <h1>Choose Value</h1> <select (change)="parseValue($event.target.value)"> <option>--select--</option> <option *ngFor="let name of options" [value]="name">{{name}}</option> </select> <h1 [hidden]="myValue == null"> You entered {{AgentStatus[myValue]}} </h1>` }) export class AppComponent { options : string[]; myValue: AgentStatus; AgentStatus : typeof AgentStatus = AgentStatus; ngOnInit() { var x = AgentStatus; var options = Object.keys(AgentStatus); this.options = options.slice(options.length / 2); } parseValue(value : string) { this.myValue = AgentStatus[value]; } }
update2 simplificado creando una matriz
@NgModule({
declarations: [KeysPipe],
exports: [KeysPipe],
}
export class SharedModule{}
actualizar
en lugar de
pipes: [KeysPipe]
utilizar
@NgModule({
...
imports: [SharedModule],
})
@Pipe({name: ''keys''})
export class KeysPipe implements PipeTransform {
transform(value, args:string[]) : any {
let keys = [];
for (var enumMember in value) {
if (!isNaN(parseInt(enumMember, 10))) {
keys.push({key: enumMember, value: value[enumMember]});
// Uncomment if you want log
// console.log("enum member: ", value[enumMember]);
}
}
return keys;
}
}
@Component({ ...
pipes: [KeysPipe],
template: `
<select>
<option *ngFor="let item of countries | keys" [value]="item.key">{{item.value}}</option>
</select>
`
})
class MyComponent {
countries = CountryCodeEnum;
}
original
Uso de la tubería de
keys
de
https://.com/a/35536052/217408
Tuve que modificar un poco la tubería para que funcione correctamente con las enumeraciones (consulte también ¿Cómo obtener los nombres de las entradas de enumeración? )
@Component({
selector: ''my-app'',
providers: [],
template: `
<div>
<select>
<option *ngFor="let key of keys" [value]="key" [label]="countries[key]"></option>
</select>
</div>
`,
directives: []
})
export class App {
countries = CountryCodeEnum
constructor() {
this.keys = Object.keys(this.countries).filter(Number)
}
}
Consulte también ¿Cómo iterar claves de objeto usando * ngFor?