在服务中排序的列表数组后,角度列表组件不会更新

时间:2018-04-22 12:14:07

标签: javascript arrays angular

我目前正在学习如何通过制作一个小项目来正确使用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

上的问题

1 个答案:

答案 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的新手,也可以使用更好的技术术语,请随时修改。

查看您的代码后

我想出了这个最容易解决的问题。

  1. 在您的排序组件中添加一个事件。
  2. 在更新contactList时发出事件。
  3. 拥有更新联系人List组件中的contactList的代码。
  4. 这就是您需要添加的所有内容。

    接触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();
      }
    

    我认为它非常自我解释,你想根据子组件中的某些条件在父组件中执行一些代码,这是我们可以利用事件发射器从子组件发出事件,并在父组件中侦听该事件。

    请尝试此操作,如果您想要上传任何说明或代码,请与我们联系。