简体   繁体   English

Angular-应用程序组件架构

[英]Angular - application components architecture

I'm currently experimenting with the design of an application component in Angular 7.* . 我目前正在尝试在Angular 7.*设计应用程序组件。 Not having worked a lot with it, I'm finding it hard to design a clean components architecture. 没有做很多工作,我发现很难设计一个干净的组件体系结构。

This component, lets call it MainComponent receives a JSON input such as 这个组件,让我们称它为MainComponent接收JSON输入,例如

{
   "name": "name",
   "description": "description",
   "attributes": [ // Rectangle in the image
      {
         "attr1": "value", // Editable
         "attr2": "value", // Editable
         "attr3": "value"  // Editable
      },
      {
         "attr1": "value", // Editable
         "attr2": "value", // Editable
         "attr3": "value"  // Editable
      },
      ...
   ]
}

The important field is attributes . 重要的领域是attributes Each of its elements will be displayed as a separate area, which I'd like to code as a new component. 它的每个元素都将显示为一个单独的区域,我想将其编码为一个新组件。

Each attributes element become a rectangle inside the main one. 每个attributes元素在主元素内变成一个矩形。
And each field of an attribute is editable, so a FormGroup has to be constructed. 而且attribute每个字段都是可编辑的,因此必须构造一个FormGroup

在此处输入图片说明

However, saving is global, not per sub-component. 但是, 保存是全局的,而不是每个子组件。
And I need to take care of "listening" to which values have been modified inside each component. 而且,我需要注意“侦听”在每个组件中修改了哪些值。

I've thought about two solutions. 我考虑过两种解决方案。

  1. Have a FormGroup at the main level, with multiple sub- FormGroup s, one per each sub-component. 在主级别具有一个FormGroup ,具有多个子FormGroup ,每个子组件一个。 Each sub- FormGroup is inputted inside a sub- Component . 每个子FormGroup都输入到子Component内部。 On save I just look at the main FormGroup, it already contains every changed value. 保存时,我只看主要的FormGroup,它已经包含每个更改的值。

  2. Each sub-component owns a separate FormGroup . 每个子组件都拥有一个单独的FormGroup On save, the main component asks (that is call a method) each sub-component to retrieve modified values. 保存时,主要组件要求 (即称为方法)每个子组件检索修改后的值。

Which solution is most suited to Angular ? 哪种解决方案最适合Angular What would you do? 你会怎么做?

Edit : what I'm asking is what's the better way to distribute a JSON input to multiple sub-components, taking care of retrieving the edited values on save, which is at the upper/main level. 编辑 :我要问的是将JSON输入分配到多个子组件的更好的方法是什么,请注意在保存时检索上级/主要级别的已保存值。

Here is a working solution. 这是一个可行的解决方案。

I've used FormArray . 我用过FormArray For more info, read it here 欲了解更多信息,请在这里阅读

First, let's create an input component and call it MyInputComponent 首先,让我们创建一个输入组件并将其MyInputComponent

@Component({
  selector: 'my-input',
  template: `
    <div>
      Attr1: <input type="text" [ngModel]="value.attr1" 
               (ngModelChange)="updateModel($event, 'attr1')" />
    </div>
    <div>
      Attr2: <input type="text" [ngModel]="value.attr2" 
               (ngModelChange)="updateModel($event, 'attr2')" />
    </div>
  `
})
export class MyInputComponent {
  value;

  updateModel(value, attrName) {
    this.value[attrName] = value;
  }
}

It's a pretty simple component. 这是一个非常简单的组件。 It contains two inputs (you can add more) and binds a model to that input using ngModel . 它包含两个输入(您可以添加更多),并使用ngModel将模型绑定到该输入。 For now, it does not expose anything to outside world. 目前,它还没有向外界公开任何东西。 On change of any of the inputs, it updates value accordingly. 更改任何输入时,它将相应地更新value

Now, let's use it in our main.component 现在,让我们在main.component使用它

Let's say you have following data 假设您有以下数据

  attributes = [
    { 'attr1': 'value1', 'attr2': 'value12'},
    { 'attr1': 'value2', 'attr2': 'value22'},
    { 'attr1': 'value3', 'attr2': 'value32'},
  ];

And, you can use this component within your template as follows 而且,您可以按以下方式在模板中使用此组件

<div *ngFor="let attr of attributes; let i = index">
  <my-input></my-input>
  <hr />
</div>

Now, let's bind formArrayName and formControlName to that input. 现在,让我们将formArrayNameformControlName绑定到该输入。

For that, we import ReactiveFormsModule in our module and make MyInput implement ControlValueAccessor 为此,我们在模块中导入ReactiveFormsModule并使MyInput实现ControlValueAccessor

my-input.component

@Component({
  selector: 'my-input',
  template: `
    <div>
      Attr1: <input type="text" [ngModel]="value.attr1" (ngModelChange)="updateModel($event, 'attr1')" />
    </div>
    <div>
      Attr2: <input type="text" [ngModel]="value.attr2" (ngModelChange)="updateModel($event, 'attr2')" />
    </div>
  `,
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => MyInputComponent),
      multi: true
    }
  ]
})
export class MyInputComponent implements ControlValueAccessor {

  value;

  onChange;
  onTouched;
  disabled = false;

  updateModel(value, attrName) {
    this.value[attrName] = value;
    this.onChange(this.value); // now I call onChange method to update the value within form
  }

  // comes from ControlValueAccessor
  writeValue(newValue): void {
    this.value = newValue;
  }

  // comes from ControlValueAccessor
  registerOnChange(fn: (rating: number) => void): void {
    this.onChange = fn;
  }

  // comes from ControlValueAccessor
  registerOnTouched(fn: () => void): void {
    this.onTouched = fn;
  }

  // comes from ControlValueAccessor
  setDisabledState(isDisabled: boolean): void {
    this.disabled = isDisabled;
  }

}

And change the template of main component to 并将主要组件模板更改为

<div [formGroup]="myForm">
  <div formArrayName="array">
    <div *ngFor="let attr of attributes; let i = index">
      <my-input [formControlName]="i"></my-input>
      <hr />
    </div>
    <button (click)="save()">Save</button>
  </div>
</div>

And you need to create a formGroup within main component as follows 并且您需要在主组件中创建一个formGroup ,如下所示

export class AppComponent  {

  myForm = this.fb.group({
    array:  this.fb.array([])
  })

  attributes = [
    { 'attr1': 'value1', 'attr2': 'value12'},
    { 'attr1': 'value2', 'attr2': 'value22'},
    { 'attr1': 'value3', 'attr2': 'value32'},
  ];

  constructor(private fb: FormBuilder) {}

  ngOnInit() {
    const arrayFormControl = this.myForm.get('array') as FormArray;
    this.attributes.forEach(attr => 
      arrayFormControl.push(this.fb.control(attr)));
  }

  save() {
    console.log(this.myForm.value);
  }
}

I think the best way to solve these types of problems (data sharing). 我认为解决此类问题(数据共享)的最佳方法。 we should always create a common service. 我们应该始终创建共同的服务。 place a single FormGroup there. 在那里放置一个FormGroup and write methods in each component to update the value of that form group. 并在每个组件中编写方法以更新该表单组的值。 and eventually a method to get value of form group. 最后是一种获取表单组值的方法。 It is by far the best method to write shared FormGroup code in services. 到目前为止,这是在服务中编写共享FormGroup代码的最佳方法。

this.lotTwoFormGroup = this.formBuilder.group({
  title: ['', Validators.compose([Validators.required])],
  description: ['', Validators.compose([Validators.required])],
  dutchTitle: [''],
  dutchDescription: [''],
  frenchTitle: [''],
  frenchDescription: ['']
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM