Мне нужно связать класс машинописи с компонентом angular - PullRequest
1 голос
/ 02 мая 2020

Вот класс элементов

export class Element {
    fields = []
}

А вот класс 2 полей

export class SmallText {
    value
    constructor(value) {
        this.value = value
    }
}

export class LargeText {
    value
    constructor(value) {
        this.value = value
    }
}

Допустим, у нас есть этот элемент

export class Element {
    fields = []
    constructor(){
        this.fields.push(new SmallText("foo"))
        this.fields.push(new LargeText("bar"))
    }
}

Каждое поле имеет например, уникальный шаблон

<!-- the small text is an input -->
<input>
<!-- but the large text is a textera -->
<textera></textera> 

Теперь я хочу l oop массив полей и для каждого поля показать соответствующий шаблон.

Решение, которое я использую сейчас, выглядит следующим образом.

<field *ngFor="let field of element.fields" [inputField]="field"></field>

А внутри компонента поля есть что-то вроде этого:

<input *ngIf="inputField.constructor.name == 'SmallText'">
<textarea *ngIf="fieinputFieldd.constructor.name == 'LargeText'"></textarea> 

Это хлопотно, потому что, когда я создаю производство, все имена классов перезаписываются, поэтому я должен сохранить индекс всех имен классов в сервисе.

Я хотел бы иметь компонент SmallText и компонент LargeText, чтобы при создании экземпляра il oop внутри массива element.fields каждый компонент создавался. Таким образом, мне не нужно делать глупые логи c, чтобы показать правильный шаблон для правильного поля.

Есть ли лучшее решение, чем это?

Ответы [ 3 ]

0 голосов
/ 02 мая 2020

Попробуйте: https://stackblitz.com/edit/angular-foreach-field-in-component?file=src%2Fapp%2Fapp.component.html

То же самое, но с компонентами.

Вы можете выбрать и передать тип в свой компонент field.

// field.component.ts
import { Component, Input } from '@angular/core';

@Component({
  selector: 'field',
  template: `
    <input *ngIf="type == 'small-text'" name="{{name}}" [value]="value" />
    <textarea *ngIf="type == 'large-text'" name="{{name}}" [value]="value"></textarea>
  `
})
export class FieldComponent  {
  @Input() type;
  @Input() name;
  @Input() value;

}

И вызовите его в шаблоне компонента:

<!-- app.component.html -->
<div *ngFor="let field of fields">
  <label>{{field.name}}: </label>
  <field [type]="field.type" value="{{field.value}}"></field><br><br>
</div>

Массив компонента:

fields = [
    { type: 'small-text', name: 'foo', value: 'foo' },
    { type: 'large-text', name: 'bar', value: 'bar' },
    { type: 'small-text', name: 'moo', value: 'moo' },
  ];
0 голосов
/ 02 мая 2020

Я вижу, что ваши "поля" являются реальными JavaScript классом, инициализированным, например, new LargeText (...), поэтому в этом случае я думаю, что вашим лучшим другом является оператор instanceof . Кстати, эта ссылка не прекратится после сборки продукта.

Что-то выглядит так:

шаблон

<input *ngIf="isSmallText(inputField)">
<textarea *ngIf="isLargeText(inputField)"></textarea> 

компонент

public isSmallText(field: SmallText | LargeText): boolean {
  return field instanceof SmallText;
}

public isLargeText(field: SmallText | LargeText): boolean {
  return field instanceof LargeText;
}

Также, как указал @chris, у людей могут возникнуть проблемы с использованием вызовов методов в шаблоне Angular, поскольку это вызывает обнаружение изменений больше, чем ожидаемые обновления в этом фрагменте кода шаблона. (случай может отличаться в зависимости от вашей стратегии обнаружения изменения компонентов)

Ниже приведен пример более готового кода (все еще используется instanceof)

template

<input *ngIf="isSmallText$ | async">
<textarea *ngIf="isLargeText$ | async"></textarea> 

компонент

// your field observable monitored when input changes
public inputField$ = ...;

public isSmallText$ = this.inputField$.map(field => field instanceof SmallText);

public isLargeText$ = this.inputField$.map(field => field instanceof LargeText);

И, конечно, когда ваша бизнес-логика c становится более сложной (например, дюжина полей различного типа), вы Я захочу немного изменить рефакторинг для единой проверки этих типов, но это будет выходить за рамки первоначальной проблемы, которую вы хотите решить здесь.

Но ИМХО жертва производительности это то, что стоит принять, когда вы только начали изучать Angular. Это естественно go исчезнет, ​​когда вы запачкаете руки в реактивном программировании.

0 голосов
/ 02 мая 2020

Используйте stati c, чтобы после компиляции он оставался таким же

export class SmallText {
    static type = 'SmallText';
    value
    constructor(value) {
        this.value = value
    }
}

export class LargeText {
    static type = 'LargeText';
    value
    constructor(value) {
        this.value = value
    }
}

шаблон:

<input *ngIf="inputField.type == 'SmallText'">
<textarea *ngIf="fieinputFieldd.type == 'LargeText'"></textarea> 

но я думаю, что лучше делать с компонентами

AppModule:

@NgModule({
  imports:      [ BrowserModule ],
  declarations: [ AppComponent, SmallTextComponent, LargeTextComponent ],
  bootstrap:    [ AppComponent ],
  entryComponents: [SmallTextComponent, LargeTextComponent]
})
export class AppModule { }

SmallTextComponent:

@Component({
  selector: 'app-small-text',
  template: '<input/>',
})
export class SmallTextComponent { }

LargeTextComponent:

@Component({
  selector: 'app-large-text',
  template: '<textarea></textarea>',
})
export class LargeTextComponent { }

AppComponent:

@Component({
  selector: 'my-app',
  template: '<ng-container #container></ng-container>'
})
export class AppComponent implements AfterViewInit {
  @ViewChild('container', { read: ViewContainerRef }) container: ViewContainerRef;
  private _components: Type<any>[];

  constructor(
    private _cfr: ComponentFactoryResolver,
    private _injector: Injector,
  ) {
    this._components = [LargeTextComponent, SmallTextComponent, LargeTextComponent];
  }

  ngAfterViewInit() {
    this._components.forEach(component => {
      const componentFactory = this._cfr.resolveComponentFactory(component);
      const componentRef = componentFactory.create(this._injector);
      this.container.insert(componentRef.hostView);
    });
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...