需要使用 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>
主列表在列表组件中过滤成listDay
和listNight
,如下所示:
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 中本地工作)。希望对你有帮助。
我想根据布尔值 属性 在 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>
主列表在列表组件中过滤成listDay
和listNight
,如下所示:
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 中本地工作)。希望对你有帮助。