Как использовать один компонент для проверки двух других компонентов?

У меня есть три компонента: GalleryAddComponent для добавления нового элемента, GalleryItemComponent, для редактирования элемента, FieldsComponent, форма, которую я хочу использовать в компонентах: GalleryAddComponent и GalleryItemComponent. Все компоненты находятся внутри GalleryComponent. Но когда я перехожу к компоненту GalleryAddComponent, чтобы добавить новый элемент, я получаю сообщение об ошибке: ERROR TypeError: Cannot read property 'controls' of undefined. Также в компоненте: GalleryItemComponent.

Помогите решить эту проблему, чтобы логика редактирования и добавления работала правильно.

шаблон GalleryAddComponent

<div class = "card">
    <div class = "card-body">
        <form [formGroup] = "angForm" novalidate>
                <app-fields [formGroup] = "angForm"></app-fields>
            <div class = "form-group but-group">
                <button (click) = "addPost(title.value, url.value);  angForm.reset(title.value, url.value)"
                        [disabled] = "angForm.pristine || angForm.invalid"
                        class = "btn btn-primary">Add
                </button>
                <a routerLink = "/" class = "btn btn-danger">Back</a>
            </div>
        </form>
    </div>
</div>

код GalleryAddComponent

export class GalleryAddComponent implements OnInit {
    angForm: FormGroup;
    isAdded: boolean = false;
    constructor(private fb: FormBuilder, private galleryService: GalleryService) {}

    ngOnInit() {
        this.angForm = this.fb.group({
            title: ['', Validators.required],
            url: ['', Validators.required]
        });
    }

    addPost(title: string, url: string): void {
        this.galleryService.add(title, url).subscribe(res => {
            this.isAdded = true;
        });
    }
}

шаблон GalleryItemComponent

    <div class = "card" *ngIf = "toggleEdit">
        <h4>Edit your post</h4>
        <div class = "card-body">
            <form [formGroup] = "angForm" novalidate>
                <app-fields [formGroup] = "angForm"></app-fields>
                <div class = "form-group but-group">
                    <input type = "button"
                           (click) = "updatePost(title.value, url.value)"
                           [disabled] = " angForm.invalid"
                           class = "btn btn-primary" value = "Update Post">
                </div>
            </form>
        </div>
    </div>

код GalleryItemComponent

export class GalleryItemComponent implements OnInit {
   pic: Picture;
   angForm: FormGroup;
   
    constructor(private route: ActivatedRoute,
    private galleryService: GalleryService, private fb: FormBuilder) {}

    ngOnInit() {
        this.angForm = this.fb.group({
            title: ['', Validators.required],
            url: ['', Validators.required]
        });
        this.showPost();
    }

    showPost(): void {
        this.route.params.subscribe(params => {
            this.galleryService.getPicture(params['id']).subscribe(res => {
                this.pic = res;
                this.angForm.setValue({title: res.title, url: res.url})
            })
        })
    }
    updatePost(title: string, url: string): void {
        this.route.params.subscribe(params => {
            this.galleryService.update(title, url, params['id']).subscribe(res => {
                if (res.id === this.pic.id) {
                    this.pic.title = title;
                    this.pic.url = url;
                } 
            });
        });
    }
}

шаблон FieldsComponent

<div [formGroup] = "formGroup">
    <div class = "form-group">
        <label class = "col-md-4">Picture Title</label>
        <input type = "text" class = "form-control" formControlName = "title" minlength = "1" #title/>
    </div>
    <div *ngIf = "angForm.controls['title'].invalid && (angForm.controls['title'].dirty || angForm.controls['title'].touched)"
         class = "alert alert-danger">
        <div *ngIf = "angForm.controls['title'].errors.required">
            Title is required.
        </div>
    </div>
    <div class = "form-group">
        <label class = "col-md-4">Picture Address (url)</label>
        <input type = "url" class = "form-control" formControlName = "url" #url pattern = "https?://.+"
               title = "Include http://"/>
    </div>
    <div *ngIf = "angForm.controls['url'].invalid && (angForm.controls['url'].dirty || angForm.controls['url'].touched)"
         class = "alert alert-danger">
        Address(url) is required.
        <div *ngIf = "angForm.controls['url'].errors.required ">

        </div>
    </div>
</div>

код FieldsComponent

export class FieldsComponent implements OnInit {
@Input() formGroup: FormGroup;

  constructor() {}

  ngOnInit() {}

}

Не могли бы вы сделать из ваших файлов пример StackBlitz? См. stackblitz.com

Roy 20.10.2018 17:07

@Roy stackblitz.com/edit/angular-cvf4ut Я подумываю вырезать те же входные данные с валидацией из компонентов «GalleryAddComponent» и «GalleryitemComponent» и вставить их в отдельный компонент. Затем подключите этот компонент в форме в компоненте «GalleryAddComponent» и в форме компонента «GalleryitemComponent». Но как это реализовать, не нарушая логики?

Igor Shvets 21.10.2018 18:34

Не могли бы вы исправить свой проект stackblitz, чтобы его можно было запустить?

Balázs Takács 22.10.2018 11:46

@ Балаж Такач stackblitz.com/github/gorillasz/gallery

Igor Shvets 22.10.2018 11:57
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
7
4
460
3

Ответы 3

Вы получаете эту ошибку, потому что вы ссылаетесь на angForms.controls в своем FieldsComponent, который имеет только одну переменную: formGroup.

Просто замените angForms в HTML-коде шаблона на formGroup, и проблема должна быть решена.

<div [formGroup] = "formGroup">
  <div class = "form-group">
    <label class = "col-md-4">Picture Title</label>
    <input type = "text" class = "form-control" formControlName = "title" minlength = "1" #title />
  </div>
  <div *ngIf = "formGroup.controls['title'].invalid && (formGroup.controls['title'].dirty || formGroup.controls['title'].touched)"
    class = "alert alert-danger">
    <div *ngIf = "formGroup.controls['title'].errors.required">
      Title is required.
    </div>
  </div>
  <div class = "form-group">
    <label class = "col-md-4">Picture Address (url)</label>
    <input type = "url" class = "form-control" formControlName = "url" #url pattern = "https?://.+" title = "Include http://" />
  </div>
  <div *ngIf = "formGroup.controls['url'].invalid && (formGroup.controls['url'].dirty || formGroup.controls['url'].touched)"
    class = "alert alert-danger">
    Address(url) is required.
    <div *ngIf = "formGroup.controls['url'].errors.required ">

    </div>
  </div>
</div>

Я сделал это, ошибка была такой же, поэтому я создал свой проект в «StackBlitz» без компонента «FieldsComponent», чтобы показать мне, как поместить поля в отдельный компонент и подключиться к компонентам: «GalleryAddComponent» и «GalleryitemComponent», не теряя своей логики

Igor Shvets 21.10.2018 18:55

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

Wrokar 23.10.2018 01:00

[formGroup] = "formGroup", это не нужно в элементе div

djain4 24.10.2018 09:17

Я думаю, что простое решение здесь - настроить группу форм в родительском компоненте и передать ее дочерним компонентам в качестве входных данных, поэтому она передается дочернему компоненту до загрузки дочернего компонента html.

Другое решение, которое я бы порекомендовал, - это использовать технику разрешения, предлагаемую Angular, это позволяет загружать все данные до загрузки компонента с довольно простой настройкой.

Вот несколько ссылок:

Невозможно прочитать "элементы управления" свойства undefined. Эта ошибка может появиться только потому, что вместо formGroup вы использовали angForm. Попробуйте заменить его, как поделился @Wrokar. Я также понимаю, что вы хотите отображать сводные сообщения об ошибках. Поэтому вместо того, чтобы делать это в html для каждого элемента управления формы, вы должны сделать это в component.ts и сделать его более общим, подписавшись на изменение значения каждого элемента управления, как показано ниже, и показать консолидированное сообщение об ошибке.

for (const field in this.formGroup.controls) { // 'field' is a string
  const control = this.form.get(field); // 'control' is a FormControl
  control.valueChanges.subscribe(
    (res) => {
       // check if it is pristine, dirty,  invalid, touched, pattern match if 
           any
       // you can access control.errors
       // create the consolidated list and append it in the list of error 
          messages
    }
  )
}

Лучше сделать его универсальным, потому что завтра ваша форма может иметь дополнительные поля, и тогда вам не придется менять FieldsComponent.

Другие вопросы по теме