#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
anddata-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 инициализировал компоненты.
Следовательно, в настоящее время я согласен с решением, которое я нашел, хотя и с потенциальным вопросом о производительности в будущем, когда приложение масштабируется.