需要使用Master / Detail范例(Angular)

时间:2017-10-03 16:00:21

标签: angular typescript master-detail

我想基于布尔属性在两个列表之间切换项目。我无法理解如何让列表组件重新渲染并显示更新的列表。

当"改变转变"按下按钮," nocturnal"属性切换和类更改。缺少的行为是我还希望项目(即蝙蝠侠)从夜间列表移动到日期列表

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

<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>

主列表在List组件中被过滤为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

2 个答案:

答案 0 :(得分:1)

好吧,你的捡拾器有点乱,所以我从头开始。而不是两个子组件给一个父母,我只做了一个孩子到一个父母。但是这种方法你仍然可以通过一些改变来实现。

您可以使用ngOnChanges,observables或可变数据解决此问题(此解决方案使用可变数据)。在将来,我建议从服务器获取此数据,并使用行为主题来跟踪更新,因为它会使您的应用程序陷入低于ngOnChanges,并且可观察性是一种很好的做法。

你的方法不起作用的原因是Angular的变化检测不起作用,因为列表发生了变异。这就是我如何解决它,每次进行更改时,我都使用spread(...)运算符来复制原始列表的内容并创建一个新列表。你走了。

这是答案的stackBlitz,您可以使用它来构建您的版本。

如果您想了解有关智能/哑主/详细模式的更多信息,可以查看here

答案 1 :(得分:1)

不确定FussinHussin现有的答案是否能为您提供您所描述的问题。我成功转移了蝙蝠侠&#34;按下切换按钮时,从日夜列表中来回切换。以下是我修改过的更新的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本地工作)。希望它有所帮助。