Передача данных правого элемента из цикла ngfor дочернему компоненту

#angular #parent-child #ngfor #angular-arrays

#angular #родительский-дочерний #ngfor #angular-массивы

Вопрос:

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

Пока @input() saleItem: SaleItem; свойство в модели дочернего компонента принимает данные только первого элемента в массиве в шаблоне родительского компонента, независимо от того, какой «товар для продажи» я нажимаю на шаблон родительского компонента. Как я могу добиться желаемого поведения каждого модального рендеринга, содержащего данные нужного элемента в цикле ngfor?

Уже пробовал использовать изменения в дочернем компоненте. Это не работает, и я предполагаю, что ссылка на массив в цикле ngFor фактически не изменяется.

Редактировать

Итак, я немного покопался в инструментах разработки, и вот мгновенный снимок со вкладки «Элементы» в Chrome. Привязка вкладки элементов Это показывает, что данные фактически передаются в отдельно отображаемый шаблон дочернего компонента и отображаются в модальных элементах, но когда я нажимаю в любом месте шаблона родительских компонентов, запускается только модальный с данными первых элементов. Как мне получить правильный модальный режим для запуска, когда я нажимаю на элемент dom в шаблоне родительских компонентов, который должен запускать модальный режим, как показано в предоставленном коде? Модель родительского компонента

 import { SaleItemsServices } from './../Services/saleItem-service.service';
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-sales-page',
  templateUrl: './sales-page.component.html',
  styleUrls: ['./sales-page.component.scss']
})
export class SalesPageComponent implements OnInit {
  // other inits
  saleItems: any = [];

  imageUrl: String = this.saleItemsService.getItemImageURI();
  constructor(private saleItemsService: SaleItemsServices) {}

  ngOnInit() {
    console.log('im here');
    this.populateSaleItems();
  }
  populateSaleItems() {
    this.saleItemsService.getSalesItems().subscribe(
      data => {
        console.log('data available');
        this.saleItems = data;
        console.log(this.saleItems);
      },
      err => {
        console.log('there was an error fetching the data');
      },
      () => {
        console.log('done loading sale item data');
      }
    );
    console.log('sale items received are as such'   this.saleItems);
  }
}
 

Шаблон родительского компонента

 <div id="backGroundImage">
  <div id="salesPageContainer">
    <div id="saleItemsContainer">
      <p id="banner">This is where the banner will come</p>
      <div
        *ngFor="let saleItem of saleItems"
        id="itemContainer"
        data-toggle="modal"
        data-target="#modalID"
      >
        <app-saleitem-modal [saleItem]="saleItem"></app-saleitem-modal>
        <img [src]="imageUrl   saleItem.imageID" alt="" id="itemImage" />
        <p id="itemName">{{ saleItem.itemName }}</p>
        <p id="itemPrice">{{ saleItem.itemPrice }}</p>
      </div>
    </div>
  </div>
</div>
 

Модель дочернего компонента

 import { SaleItem } from './../../models/saleitem';
import {
  Component,
  OnInit,
  Input,
  OnChanges,
  SimpleChanges
} from '@angular/core';
import { SaleItemsServices } from '../../Services/saleItem-service.service';

@Component({
  selector: 'app-saleitem-modal',
  templateUrl: './saleitem-modal.component.html',
  styleUrls: ['./saleitem-modal.component.scss']
})
export class SaleitemModalComponent implements OnInit, OnChanges {
  @Input() saleItem: SaleItem;
  imageUrl: String = this.saleItemsService.getItemImageURI();

  constructor(private saleItemsService: SaleItemsServices) {}
  ngOnChanges(changes: SimpleChanges) {
    if (changes.saleItem) {
      console.log(
        'the previous value of sale items is'  
          JSON.stringify(changes.saleItem.previousValue)
      );
      console.log(
        'the new value of sale items is '  
          JSON.stringify(changes.saleItem.currentValue)
      );
    }
  }
  ngOnInit() {
    console.log(this.saleItem);
  }
}
 

Шаблон дочернего компонента

 <div class="modal fade" id="modalID">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h3 id="saleItemName">{{ saleItem.itemName }}</h3>
      </div>
      <div class="modal-body">
        <img
          [src]="imageUrl   saleItem.imageID"
          alt=""
          id="saleItemModalImage"
        />
        <p id="itemWeight">{{ saleItem.itemWeight }}</p>
        <p id="itemPrice">{{ saleItem.itemPrice }}</p>
        <p id="itemCompany">{{ saleItem.itemCompany }}</p>
        <p id="itemCategory">{{ saleItem.itemCategory }}</p>
        <!-- Body here -->
        <div class="modal-footer">
          <div class="col-6">
            <!-- Buttons here -->
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
 

Комментарии:

1. Похоже, что он передает данные правильно. Он создает дочерний модальный элемент для каждого элемента. Где находится метод, который обрабатывает щелчок?

2. Я использую базовую начальную загрузку, поэтому модальный запуск из элемента dom, который содержит атрибуты data-toggle and data-target , которые можно увидеть примененными в шаблоне родительских компонентов.

3. Ах. Хорошо. Я не знаком с модальностями начальной загрузки. Я знаком с компонентами PrimeNG. Всякий раз, когда на странице есть несколько компонентов одного и того же типа, каждому компоненту требуется идентификатор, поэтому, когда они открываются или закрываются, PrimeNG может отслеживать их. Что, если вы передадите modalId дочернему компоненту и поместите его в атрибут id div с классом modal ? Либо это, либо поместить модальный в родительский компонент, а тело модального — в дочерний компонент.

4. Спасибо, что потратили время. Ваш ответ навел меня на правильный путь.

Ответ №1:

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

шаблон родительского компонента

 
  <div id="salesPageContainer">
    <div id="saleItemsContainer">
      <p id="banner">This is where the banner will come</p>
      <div *ngFor="let saleItem of saleItems" id="itemContainer">
        <img
          [src]="imageUrl   saleItem.imageID"
          alt=""
          id="itemImage"
          (click)="passSaleItem(saleItem)"
          data-toggle="modal"
          data-target="#modalID"
        />
        <app-saleitem-modal [saleItem]="saleItemToPass"></app-saleitem-modal>
        <p id="itemName">{{ saleItem.itemName }}</p>
        <p id="itemPrice">{{ saleItem.itemPrice }}</p>
      </div>
    </div>
  </div>
</div>
 

добавление модели родительских компонентов

 passSaleItem(saleItem: SaleItem) {
    this.saleitemModal.saleItem = saleItem;
  }
 

Модальности по-прежнему визуализируются каждый раз заново для каждого компонента, что немного затрудняет процесс. В идеале мне бы хотелось, чтобы модальный объект отображался один раз и данные передавались в него для каждого элемента при нажатии на изображение. Это дало cannot read property of undefined ошибку, так как модель @Input() saleItem дочернего компонента не инициализировалась никакими значениями, когда angular инициализировал компоненты.

Следовательно, в настоящее время я согласен с решением, которое я нашел, хотя и с потенциальным вопросом о производительности в будущем, когда приложение масштабируется.