需要使用 Master/Detail 范式 (Angular) 在列表之间切换项目

Need to toggle items between lists using Master/Detail paradigm (Angular)

我想根据布尔值 属性 在 2 个列表之间切换项目。我无法理解如何让列表组件重新呈现和显示更新后的列表。

当按下 "Change Shift" 按钮时,"nocturnal" 属性 切换并且 class 发生变化。缺少的行为是我还希望该项目(即蝙蝠侠)从夜间列表移动到白天列表

我的应用程序组件包括主(列表)和详细信息组件。模板代码:

<div>
  <my-list [list]="listSource"></my-list>
  <my-detail [selected]="selectedItem"></my-detail>
</div>

列表组件模板:

<div class="column list">
  <h2>List</h2>
  <h3>Day Shift</h3>
  <ul>
    <li *ngFor="let item of listDay" class="{{ item.nocturnal ? 'night':'day'}}">{{ item.name }}</li>
  </ul>
  <h3>Night Shift</h3>
  <ul>
    <li *ngFor="let item of listNight" class="{{ item.nocturnal ? 'night':'day'}}">{{ item.name }}</li>
  </ul>
</div>

主列表在列表组件中过滤成listDaylistNight,如下所示:

ngOnInit() {
  this.listNight = this.list.filter(item => item.nocturnal);
  this.listDay = this.list.filter(item => !item.nocturnal);
}

详细信息组件模板:

<div class="column detail">
  <h2>Detail</h2>
  <ul>
    <li>name: {{selected.name}}</li>
    <li>job: {{selected.job}}</li>
    <li>shift: {{selected.nocturnal ? 'Night':'Day'}}</li>
    <li><button (click)="toggleShift()">Change Shift</button></li>
  </ul>
</div>

这里有一个基本的 Plunkr 说明了这个问题: http://plnkr.co/edit/yJLtROrmfKjEYqj5yJ1N?p=preview

好吧,你的plunker有点乱,所以我从头开始。而不是两个 child 组件对一个 parent,我只是做了一个 child 对一个 parent。但是您仍然可以通过一些更改来实现此方法。

您可以使用 ngOnChanges、observable 或可变数据来解决这个问题(此解决方案使用可变数据)。将来,我会建议从服务器获取这些数据,并使用行为主体来跟踪更新,因为它比 ngOnChanges 更能使您的应用程序陷入困境,而可观察对象是一种很好的做法。

您的方法不起作用的原因是 Angular 的更改检测不起作用,因为列表发生了变化。我就是这样绕过它的,每次进行更改时,我都使用扩展 (...) 运算符复制原始列表的内容并创建一个新列表。给你。

这里有一个 stackBlitz 的答案,您可以使用它来构建您的版本。

如果想了解更多smart/dumb master/detail模式,可以看here

不确定 FussinHussin 的现有答案是否能解决您所描述的问题。当按下切换按钮时,我能够成功地在日夜列表中来回切换 "Batman"。这是我修改的更新的 plunker 文件。

app.ts

// root app component
import {Component, NgModule, VERSION} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'

import {List} from './list.component'
import {Detail} from './detail.component'

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello {{name}}</h2>
      <my-list [list]="listSource"></my-list>
      <my-detail [selected]="selectedItem" (shiftChange)="shiftChanged($event)"></my-detail>
    </div>
  `,
})
export class App {
  name:string;
  listSource:any
  selectedItem:any;
  constructor() {
    this.name = `Angular! v${VERSION.full}`;
    this.listSource = [{
      'name':'Batman',
      'job':'Detective',
      'nocturnal':true
    },{
      'name':'Superman',
      'job':'Carpenter',
      'nocturnal':false
    },{
      'name':'Aquaman',
      'job':'Plumber',
      'nocturnal':false
    },{
      'name':'Herman',
      'job':'Physicist',
      'nocturnal':true
    }];
    this.selectedItem = this.listSource[0];
  }
shiftChanged(listItem: any) {
  let index = null;
  for (let i=0; i<this.listSource.length; i++) {
    if (listItem.name === this.listSource[i].name) {
      index = i;
      break;
    }
  }
  if (index !== null) {
    this.listSource[index].nocturnal = listItem.nocturnal;
    this.listSource = JSON.parse(JSON.stringify(this.listSource));
  }
}
}
// root module
@NgModule({
  imports: [ BrowserModule ],
  declarations: [ App, List, Detail ],
  providers:[  ],
  bootstrap: [ App ]
})
export class AppModule {}

detail.component.ts

// detail component
import {Component, Input, Output, EventEmitter} from '@angular/core'

@Component({
  selector: 'my-detail',
  template: `
    <div class="column detail">
      <h2>Detail</h2>
      <ul>
        <li>name: {{selected.name}}</li>
        <li>job: {{selected.job}}</li>
        <li>shift: {{selected.nocturnal ? 'Night':'Day'}}</li>
        <li><button (click)="toggleShift()">Change Shift</button></li>
      </ul>
    </div>
  `,
})
export class Detail {
  @Input() selected: any;
  @Output() shiftChange = new EventEmitter<any>();
  toggleShift() {
    this.selected.nocturnal = !this.selected.nocturnal;
    this.shiftChange.emit(this.selected);
  }
}

list.component.ts

// list component
import {Component, Input, OnInit, OnChanges, SimpleChange} from '@angular/core'

@Component({
  selector: 'my-list',
  template: `
    <div class="column list">
      <h2>List</h2>
      <h3>Day Shift</h3>
      <ul>
        <li *ngFor="let item of listDay" class="{{ item.nocturnal ? 'night':'day'}}">{{ item.name }}</li>
      </ul>
      <h3>Night Shift</h3>
      <ul>
        <li *ngFor="let item of listNight" class="{{ item.nocturnal ? 'night':'day'}}">{{ item.name }}</li>
      </ul>
    </div>
  `,
})

export class List implements OnInt, OnChanges{
  @Input() list: any;
  listNight:any;
  listDay:any;
  ngOnInit() {
    this.listNight = this.list.filter(item => item.nocturnal);
    this.listDay = this.list.filter(item => !item.nocturnal);
  }

  ngOnChanges(change: SimpleChange) {
    for (let prop in change) {
      if (prop === 'list') {
        let list = change[prop];
         this.listNight = list.currentValue.filter(item => item.nocturnal);
         this.listDay = list.currentValue.filter(item => !item.nocturnal);
      }
    }
  }
}

您可以进一步修改文件以进行优化。但这会给你一个良好的开端,因为我只专注于让功能为你的 plunker 工作。 (确认这可以在 plunker 中本地工作)。希望对你有帮助。