Búsqueda de sitios web

typescript - ¿Propiedades dinámicas en ngFormModel?


He estado intentando trabajar con ngFormModel y propiedades dinámicas de clases, sin ningún éxito. Lo que sucede es que el primer valor se enlaza correctamente, pero tan pronto como cambio la variable a otro valor, el ngFormModel no se actualiza para reflejarlo. Aquí hay una pequeña demostración de lo que está pasando:

http://plnkr.co/edit/XnbvYtPW9BFDMcdDp0St

export class HeroForm {
  protected ssn: Control;
  protected address: Control;

  build(): ControlGroup
  {
    this.ssn = new Control('', Validators.required);
    this.address = new Control('');

    return new ControlGroup({
        ssn: this.ssn,
        address: this.address
    });
  }
}

En esta demostración, cada Héroe puede tener un FormaHéroe específica. Cada FormaHéroe puede contener diferentes campos y valores, por eso el ngFormModel tiene que ser dinámico. En mi plantilla, estoy vinculando ngFormModel a la propiedad form del Héroe seleccionado actualmente. Para reproducir el problema, selecciona un héroe, llena el formulario y envíalo. Verás que todo está bien en la consola. Pero intenta seleccionar otro héroe: ahora el formulario siempre está vacío.

Además, otra pregunta sobre el mismo tema y demostración: ¿cómo puedo tener plantillas dinámicas basadas en cada clase HeroForm? Por ejemplo, AnotherHeroForm contiene campos diferentes a HeroForm, entonces, ¿cómo puedo tener un marcado para cada una?

Respuesta #1

Creo que deberías usar ngFormControl en lugar de ngControl en la clase HeroDetailComponent (archivo app/hero-detail.component.ts), como se describe a continuación:

<form [ngFormModel]="hero.form">
  <p>SSN: <input type="text"
      [ngFormControl]="hero.form.controls.ssn"></p>  <-------
  <p>Address: <input type="text" 
      [ngFormControl]="hero.form.controls.address"></p>  <-------
</form>

Aquí está el plunkr refactorizado: http://plnkr.co/edit/8eENXoDkcm4vYhZ0XY1H?p=preview.

La directiva NgFormControl permite configurar los controles que definiste con componentes. Usando interpolación (con corchetes) utilizarás las referencias de los controles...

Editar

Siguiendo tu comentario, actualicé mi plunkr para hacer las cosas dinámicas.

  • Actualicé la clase Hero para contener los campos que queremos actualizar:

    export class Hero {
      constructor(public id: number, public name: string,
                  public ssn: string, public address: string,
                  public form: ControlGroup) {
        this.form = form.build();
      }
    }
    
  • Creé instancias de Hero con valores correspondientes:

    var HEROES: Hero[] = [
      new Hero(1, "Narco", 'ssn1', 'address1', new HeroForm()),
      new Hero(2, "Magma", 'ssn2', 'address2', new HeroForm()),
      new Hero(3, "Tornado", 'ssn3', 'address3', new HeroForm()),
    ];
    
  • Actualicé el componente HeroDetailComponent para que sea dinámico, es decir, para iterar sobre los campos del héroe proporcionado:

    @Component({
      selector: 'my-hero-detail',
      template: `
        <div *ngIf="hero">
          <h2>{{hero.name}} details!</h2>
          <div *ngIf="hero">
            <form [ngFormModel]="hero.form">
              <div *ngFor="#elt of hero | fields">
                <p>{{elt}}:
                  <input type="text" [(ngModel)]="hero[elt]" 
                      [ngFormControl]="hero.form.controls[elt]">
                  - Valid: {{hero.form.controls[elt].valid}}
                </p>
              </div>
            </form>
          </div>
        </div>
       `,
       pipes: [FieldsPipe]
     })
     export class HeroDetailComponent {
       @Input()
       public hero: Hero;
     }
    

    Tanto ngModel como ngFormControl están vinculados dinámicamente al elemento actual en el bucle (para un campo en particular). Muestro la validez del control correspondiente para ver que se tienen en cuenta las actualizaciones...

  • Para obtener la lista de campos para los inputs, creé un pipe personalizado para obtenerlos y filtrarlos:

    @Pipe({
      name: 'fields'
    })
    export class FieldsPipe {
      transform(array, args: string): Array<string> {
        // Get fields
        var fields = [];
        for (let elt in array) {
          // Exclude non updatable fields (form, id and name)
          if (elt!=='form' && elt!=='id' && elt!=='name') {
            fields.push(elt);
          }
        }
        return fields;
      }
    }
    

El enlace de plunkr sigue siendo el mismo: http://plnkr.co/edit/8eENXoDkcm4vYhZ0XY1H?p=preview.

Respuesta #2

¿Has intentado enlazar ngModel como en este ejemplo? https://angular.io/docs/ts/latest/api/common/NgFormModel-directive.html

Artículos relacionados