我目前正在学习如何通过制作一个小项目来正确使用Angular(版本5+)。我已经设置了一些基本路由来通过选择导航选项卡来加载ContactList组件。另一个选项卡允许用户使用表单添加联系人,然后将表单数据发送到联系人数据服务,其中联系人在阵列中进行管理。 ContactList组件如下:
import { Component, OnInit, Input, Output,
OnChanges, DoCheck, SimpleChanges} from '@angular/core';
import { ContactDataService } from '../ContactData.service';
// import { FilterPipe } from '../../../src/pipes';
import { Contact } from '../contact.model';
@Component({
selector: 'app-contact-list-component',
templateUrl: './contact-list-component.component.html',
styleUrls: ['./contact-list-component.component.css']
})
export class ContactListComponent implements OnInit, OnChanges, DoCheck {
contactList: Contact[] = [];
searchQuery: string; // alternate subscribed data from contactDataService
contactServObj: ContactDataService;
constructor(contactServObj: ContactDataService) {
this.contactServObj = contactServObj;
}
ngOnChanges(changes: SimpleChanges) {
console.log('ngOnChanges called!');
console.log(changes);
for (const key of Object.keys(changes)) {
console.log(`${key} changed.Current: ${changes[key].currentValue}.Previous: ${changes[key].previousValue}`);
}
}
ngOnInit() {
this.contactList = this.contactServObj.getContacts();
// console.log('ngOnInit called!');
this.contactServObj.queryString.subscribe((query: string) => {
this.searchQuery = query;
});
}
ngDoCheck() {
console.log('ngDoCheck called!');
}
}
联系人数据服务(管理联系人数组)如下:
import { EventEmitter } from '@angular/core';
import { Contact } from './contact.model';
export class ContactDataService {
private contactList: Contact[] = [];
getContacts() {
return this.contactList;
}
sortContactHandler = (value) => {
console.log(value);
const field = value === 'default' ? null : value;
if (this.contactList.length > 1 && field !== null) {
this.contactList.sort(this.compareValues(field, 'asc'));
console.log(this.contactList);
}
}
compareValues = (key, order= 'asc') => {
return function(a, b) {
if (!a.hasOwnProperty(key) ||
!b.hasOwnProperty(key)) {
return 0;
}
const varA = (typeof a[key] === 'string') ?
a[key].toUpperCase() : a[key];
const varB = (typeof b[key] === 'string') ?
b[key].toUpperCase() : b[key];
let comparison = 0;
if (varA > varB) {
comparison = 1;
} else if (varA < varB) {
comparison = -1;
}
return (
(order === 'desc') ?
(comparison * -1) : comparison
);
};
}
addContactHandler(sentContact: Contact) {
let field = '';
const findExistingContact = this.contactList.findIndex((el, i) => {
// return (name === el.name) || (phone === el.phone) || (email === el.email);
if (sentContact.name === el.name) {
field = 'name';
return true;
} else if (sentContact.phone === el.phone) {
field = 'phone';
return true;
} else if (sentContact.email === el.email) {
field = 'email';
return true;
}
return false;
});
console.log(findExistingContact);
if (findExistingContact === -1) {
const newContact: Contact = sentContact;
this.contactList.push(newContact);
} else {
alert(`Contact with field ${field} already exists!`);
}
}
}
Contact Data Service在根级别注入 - 在 app.module.ts 中,如下所示:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { Routes, RouterModule } from '@angular/router';
import { AppComponent } from './app.component';
import { ContactComponent } from './contact-component/contact-component.component';
import { ContactListComponent } from './contact-list-component/contact-list-component.component';
import { AddContactComponent } from './add-contact-component/add-contact-component.component';
import { SearchContactComponent } from './search-contact-component/search-contact-component.component';
import { BackdropComponent } from './backdrop/backdrop.component';
import { ModalComponent } from './modal/modal.component';
import { EditContactComponent } from './edit-contact/edit-contact.component';
import { ContactDataService } from './ContactData.service';
import { ModalShowService } from './modal-show.service';
import { CockpitComponentComponent } from './cockpit-component/cockpit-component.component';
import { FilterContactPipe } from './filter-contact.pipe';
import { SortComponent } from './sort/sort.component';
import { ContactDetailComponent } from './contact-detail/contact-detail.component';
const appRoutes: Routes = [
{ path: '' , component: AddContactComponent },
{ path: 'contactList', component: ContactListComponent },
{ path: 'contactList/:name', component: ContactDetailComponent }
];
@NgModule({
declarations: [
AppComponent,
ContactComponent,
ContactListComponent,
AddContactComponent,
SearchContactComponent,
BackdropComponent,
ModalComponent,
EditContactComponent,
CockpitComponentComponent,
FilterContactPipe,
SortComponent,
ContactDetailComponent
],
imports: [
BrowserModule,
FormsModule,
RouterModule.forRoot(appRoutes)
],
providers: [ContactDataService, ModalShowService],
bootstrap: [AppComponent]
})
export class AppModule { }
最后,我有一个排序组件,它只是一个简单的下拉选择框,其中包含用于对联系人进行排序的3个字段。它只是将此字段发送到Contact Data Service中的sortContactHandler函数,我在console.log(this.contactList)语句中看到了这个结果。但是这种变化并没有反映在呈现数组的ContactList组件中。
问题:将这个已排序的contactList数组添加到我的ContactList组件的最佳方法是什么(它只在ngOnInit()函数中检索此数组)?
我认为这可以使用生命周期钩子完成,所以,我试图理解它们,但也许我做错了。 ngOnChanges()永远不会被调用(我从该函数中看不到一次console.log())并且我不确定如何使用ngDoCheck()。从我所读到的关于上述生命周期方法的内容来看,它们对组件的输入属性的变化作出反应,所以我不确定它们是否可以在我的情况下使用。
以下是StackBlitz
上的问题答案 0 :(得分:1)
NgOnChanges - 对使用@Input修饰符声明的属性值的更改做出反应,但组件类中有一个普通属性。它不会检测到更改。
据我了解你的场景,你在UI上有两个兄弟组件,你正在从一个组件改变服务类的属性值,并期望在另一个组件中进行更改但是你无法在除OnInit之外的组件(在加载组件时gtes执行一次),因此如果组件保留在DOM中,并且您希望反映更改。
您可以使用Observable数据流,因此基本的想法是在服务类中包含Observable数据,并且您应该在其他位置(在组件类中)订阅该数据,以便每当您在Observable上发出任何更改时流,订阅者将收到通知。
你可以尝试在你的服务中拥有可观察的'contactList`,如下所示,
private contactList = new Subject<Contact[]>();
contactList$ = this.contactList.asObservable();
然后您可以在联系人列表组件中订阅它,您希望这些更改反映如下。
serviceObj.contactList$.subscribe(
contactList => {
this.contactList= contactList;
})
并执行您在订阅功能中编写的代码,您需要在服务类中包含此代码
this.contactList.next(contactList)
上面的行是一个可观察对象的下一个方法的执行,你可以将其定义为订阅函数的第一个参数。
如果你可以在某个地方上传你的代码,我可以更好看并建议。
P.S。 - 即使我是Angular / RxJs的新手,也可以使用更好的技术术语,请随时修改。
查看您的代码后
我想出了这个最容易解决的问题。
这就是您需要添加的所有内容。
接触list.component.html
<app-sort (contactListUpdate)="fetchUpdatedList()"></app-sort>
接触list.component.ts
fetchUpdatedList(){
this.contactList = this.contactServObj.getContacts();
}
排序contact.component.ts
@Output() contactListUpdate:EventEmitter<any>=new EventEmitter<any>();
constructor(private contactServObj: ContactDataService) { }
onSelectChange(event) {
this.contactServObj.sortContactHandler(event.target.value);
this.contactListUpdate.emit();
}
我认为它非常自我解释,你想根据子组件中的某些条件在父组件中执行一些代码,这是我们可以利用事件发射器从子组件发出事件,并在父组件中侦听该事件。
请尝试此操作,如果您想要上传任何说明或代码,请与我们联系。