将值传递给子组件Angular 7
Posted
技术标签:
【中文标题】将值传递给子组件Angular 7【英文标题】:Pass values to child component Angular 7 【发布时间】:2019-06-10 00:45:23 【问题描述】:我查看了this,并了解到在声明数据绑定输入属性后,Angular 应该自动更新输入值。在我创建的组件中,它似乎不是那样的。
当我单击父项网格上的项目时,它会正确显示详细信息。之后当我单击另一个项目时,它不会更新子组件。我放了一个 console.log 来监控所选记录。它会根据用户的选择不断变化。
你能帮我看看问题出在哪里吗?
lists.component.html [父级]
<div class="container-fluid">
<div class="row mt-2 mb-2">
<div class="col-8">
<app-list-item-add *ngIf="showAddnewScreen" (notifyParentOnUpdate)='onAddItem($event)'></app-list-item-add>
<app-list-item-view *ngIf="showViewScreen" [studentObject]="selectedstudent" (notifyParentOnUpdate)='onViewItem($event)'></app-list-item-view>
</div>
</div>
</div>
lists.component.ts [父级]
import Component, OnInit, ViewChild from '@angular/core';
import studentsService, student from '../services/students.service';
import Router, ActivatedRoute from '@angular/router';
import GridComponent, ToolbarItems, SortEventArgs, RowSelectEventArgs, SelectionSettingsModel from '@syncfusion/ej2-ng-grids';
import ClickEventArgs from '@syncfusion/ej2-ng-navigations';
import * as moment from 'moment';
import Internationalization from '@syncfusion/ej2-base';
@Component(
selector: 'app-lists',
templateUrl: './lists.component.html',
styleUrls: ['./lists.component.scss']
)
export class ListsComponent implements OnInit
constructor(public router: Router, private route: ActivatedRoute, private studentsService: studentsService)
selectedstudent: student = null;
students: student[] = new Array<student>();
intl: Internationalization = new Internationalization();
showAddnewScreen = false;
showViewScreen = false;
// Syncfusion GRID settings for the students grid.
// Documentation: https://ej2.syncfusion.com/16.1.32/angular/documentation/grid/getting-started.html
studentsGridId = 'studentsGrid';
@ViewChild('studentsGrid')
studentsGrid: GridComponent;
toolbar: ToolbarItems[];
// https://ej2.syncfusion.com/16.1.32/angular/documentation/grid/api-filterSettings.html
studentsFilteringSettings =
;
// https://ej2.syncfusion.com/16.1.32/angular/documentation/grid/api-pageSettings.html
studentsPageSettings =
currentPage: 1,
enableQueryString: true,
pageSizes: [10, 25, 50, 100],
pageSize: 10
;
// https://ej2.syncfusion.com/16.1.32/angular/documentation/grid/api-selectionSettings.html
studentsSelectionOptions: SelectionSettingsModel;
studentsToolbarClick(args: ClickEventArgs)
// handles multiple grids on the page by prepending the Grid ID to the _eventname
// E.g.
// if (args.item.id == studentsGrid_excelexport)....
if (args.item.id === (this.studentsGridId + '_excelexport'))
this.studentsGrid.excelExport();
if (args.item.id === (this.studentsGridId + '_pdfexport'))
this.studentsGrid.pdfExport();
studentsRowSelected(args: RowSelectEventArgs)
const selectedrowindex: number[] = this.studentsGrid.getSelectedRowIndexes(); // Get the selected row indexes.
console.log(selectedrowindex);
const selectedRecords: student[] = this.studentsGrid.getSelectedRecords() as student[]; // Get the selected records.
const selectedRecord = selectedRecords[0];
if (selectedRecord)
gridActionHandler(args: SortEventArgs)
console.log(args.requestType + ' ' + args.type);
ngOnInit()
this.toolbar = ['Print', 'Search', 'ExcelExport', 'PdfExport'];
this.studentsSelectionOptions =
type: 'Single',
mode: 'Row'
;
this.studentsService.getstudents(1000).subscribe((students) =>
this.students = students;
this.students.sort(this.sortBystudentNumber);
this.studentsGrid.dataSource = this.students;
);
// Listen for changes to list items
this.studentsService.studentAdded$.subscribe(student =>
// convert the students date strings into dates
student.createdOn = moment(student.createdOn).toDate();
student.modifiedOn = moment(student.modifiedOn).toDate();
// Add the new student to the list
this.students.push(student);
// resort the grid data
this.students.sort(this.sortBystudentNumber);
// refresh the grid
this.studentsGrid.refresh();
);
this.studentsService.studentChanged$.subscribe(student =>
// convert the students date strings into dates
student.createdOn = moment(student.createdOn).toDate();
student.modifiedOn = moment(student.modifiedOn).toDate();
// Update the student in the list.
this.students.splice(this.students.findIndex(s => s.id === student.id), 1, student);
// resort the grid data
this.students.sort(this.sortBystudentNumber);
// refresh the grid
this.studentsGrid.refresh();
);
this.studentsService.studentDeleted$.subscribe(id =>
// Remove the student from the list
this.students.splice(this.students.findIndex(s => s.id === id), 1);
// resort the grid data
this.students.sort(this.sortBystudentNumber);
// refresh the grid
this.studentsGrid.refresh();
);
addNew()
this.showAddnewScreen = true;
this.showViewScreen = false;
viewstudent(data: student)
console.log(data);
this.selectedstudent = data;
this.showViewScreen = true;
this.showAddnewScreen = false;
onAddItem(student: student): void
this.showAddnewScreen = false;
onViewItem(command: string)
this.showViewScreen = false;
if (command === 'cancel')
else if (command === 'save')
else if (command === 'delete')
sortBystudentNumber = (s1, s2) => s1.studentNumber - s2.studentNumber;
list-item-view.component.html [子]
<div class="row">
<div class="col-12">
<section class="studentDetails">
<app-section-title heading="student Details" level="4"></app-section-title>
<form #studentForm="ngForm" class="pt-2">
<div class="row">
<div class="col-10">
<div class="form-group">
<div class="row">
<div class="col-4">
<span>student number</span>
</div>
<div class="col-6">
<input type="text" class="form-control" aria-label="student number"
[(ngModel)]="student.studentNumber" name="student Number" />
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-4">
<span>student name</span>
</div>
<div class="col-6">
<input type="text" class="form-control" aria-label="student name"
[(ngModel)]="student.studentName" name="student Name" />
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-4">
<span>student description</span>
</div>
<div class="col-6">
<input type="text" class="form-control" aria-label="student description"
[(ngModel)]="student.description" name="Description" />
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-4">
<span>Created date</span>
</div>
<div class="col-6">
<ejs-datepicker placeholder='Enter date' format="dd-MM-yyyyy" aria-label="Created date" [readonly]="true"
[(ngModel)]="student.createdOn" name="Created On"></ejs-datepicker>
<label class="col-8 col-lg-9 col-form-label">(student.createdOn | timeago)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-4">
<span>Created by</span>
</div>
<div class="col-6">
<input type="text" class="form-control" aria-label="Created by" [readonly]="true"
[(ngModel)]="student.createdBy" name="Created By" />
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-4">
<span>Modified date</span>
</div>
<div class="col-6">
<ejs-datepicker placeholder='Enter date' format="dd-MM-yyyyy" aria-label="Modified date"
[(ngModel)]="student.modifiedOn" name="Modified On"></ejs-datepicker>
<label *ngIf="student.modifiedOn" class="col-8 col-lg-9 col-form-label">(student.modifiedOn | timeago)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-4">
<span>Modified by</span>
</div>
<div class="col-6">
<input type="text" class="form-control" aria-label="Modified by"
[(ngModel)]="student.modifiedBy" name="Modified By" />
</div>
</div>
</div>
</div>
</div>
</form>
</section>
</div>
</div>
list-item-view.component.ts [子]
import Component, OnInit, ViewChild, EventEmitter, Output, Input from '@angular/core';
import studentsService, student from '../services/students.service';
import ActivatedRoute from '@angular/router';
import DatePicker from '@syncfusion/ej2-calendars';
import * as moment from 'moment';
import NgForm from '@angular/forms';
@Component(
selector: 'app-list-item-view',
templateUrl: './list-item-view.component.html',
styleUrls: ['./list-item-view.component.scss']
)
export class ListItemViewComponent implements OnInit
@Output() notifyParentOnUpdate: EventEmitter<any> = new EventEmitter<any>();
@Input() studentObject: student;
studentNumber: number;
constructor(private route: ActivatedRoute, private studentsService: studentsService)
@ViewChild(NgForm) studentForm: NgForm;
public student = new student();
ngOnInit()
this.student = this.studentObject;
save()
this.studentsService.updatestudent(this.student).subscribe(newstudent =>
this.notifyParentOnUpdate.emit('save');
);
delete()
this.studentsService.deletestudent(this.student.id).subscribe(newstudent =>
this.notifyParentOnUpdate.emit('delete');
);
editOnBlur()
this.notifyParentOnUpdate.emit('editOnBlur');
cancel()
this.notifyParentOnUpdate.emit('cancel');
【问题讨论】:
显然,您的方法是正确的。您是否在控制台中遇到任何错误? 我认为您需要将此行更改为双向数据绑定。[schoolObject]="selectedSchool"
到 [(schoolObject)]="selectedSchool"
对不起。我刚试过 [(schoolObject)]="selectedSchool"。这没什么区别。 :-(
我也会用此页面的屏幕截图更新问题。它会给你一个清晰的画面
您能否使用stackblitz.com 为我们创建一个演示来重现您的问题?谢谢你:)
【参考方案1】:
当您在 Angular 7 中编写子组件时,它会在输入更改时更新其内容。因此,您可以将所有必要的计算添加到 ngOnChanges
生命周期挂钩。 ngOnInit
只调用一次。
请将以下代码添加到list.item-view.component.ts
ngOnChanges()
this.school = this.schoolObject;
祝你好运!
【讨论】:
【参考方案2】:我认为正在发生的事情是:您正在“schoolObject”上获取学校信息。但是您在 html 文件上绑定的值是“学校”对象的属性。在您的 ts 文件的当前版本中,我看到学校对象仅在 ngOnInit 上设置一次(忽略初始化)。
我认为每次 schoolObject 获得新的 Input 时都需要设置 school 对象。 然后它会运行良好。这是你可以做的:
schoolObject: School;
@Input()
set SchoolObject(schoolObj)
this.schoolObject = schoolObj;
this.school = schoolObj;
您需要更新 html 以使用父母上的 SchoolObject 获取值:
<app-list-item-view *ngIf="showViewScreen" [SchoolObject]="selectedSchool" (notifyParentOnUpdate)='onViewItem($event)'></app-list-item-view>
【讨论】:
对不起,这个解决方案对我不起作用。谢谢 @alchi,您的概念是正确的。每次 schoolObject 获得新的 Input 时,Robert 都需要设置 school 对象。 我想知道为什么它不起作用。每次更改输入值时,都会将新值传递给 SchoolObject 的设置器。以上是关于将值传递给子组件Angular 7的主要内容,如果未能解决你的问题,请参考以下文章
传递给子组件的原始值在 Angular 2 的构造函数中未定义