我正在通过
Aurelia tutorials
而且,在完成ContactManager教程后,我想我应该通过将ContactManager站点修改为任务列表站点来进行一些练习。我已将联系人列表组件和联系人详细信息组件更改为使用任务而不是联系人。基本上,当我单击任务列表中的任务时,路由器会打开一个任务详细信息组件;与“联系人管理器”教程中的工作方式非常相似。
问题
在任务详细信息组件中,我在
<p>
元素,该元素使用字符串插值绑定到某些模型值。
<p>Date: | ${task.startDate} | ${task.dueDate}</p>
当我第一次单击任务列表中的任务时,任务详细信息视图将在
<router-view>
元素和插值字符串正确渲染,例如。
Dates: | 12/25/2017 | 1/25/2018
如果单击任务列表中的另一个任务,“任务详细信息”视图中的所有字段都会正确更改,但
<p>
要素它变成
Dates: | |
获取
<p>
元素,我必须清除选择,让路由器放入另一个视图,然后再次选择另一个任务。这将重新渲染视图,并再次显示插值。
为什么必须重新渲染任务详细信息视图才能将viewmodel中的值绑定到视图?
我将在下面发布代码和标记,但我还将一些示例代码推送到
public Github repo
以防有帮助。我试着把它写成要点。运行,但由于我使用的是Typescript,这被证明是有问题的。
任务列表组件
任务列表。html:
<template>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Priority</th>
</tr>
</thead>
<tbody>
<tr repeat.for="task of tasks" class="testClass ${task.id === $parent.SelectedTask.id ? 'active' : ''}" click.delegate="selectTask(task)">
<td>${task.id}</td>
<td>${task.title}</td>
<td>${task.priority}</td>
</tr>
</tbody>
</table>
</template>
任务列表。ts:
import {autoinject} from 'aurelia-framework';
import {TaskWebAPI} from './task-web-api';
import {Task} from './task-web-api';
import {Router} from 'aurelia-router';
//@inject(TaskWebAPI)
@autoinject
export class TaskList {
tasks;
SelectedTask: Task;
constructor(private api: TaskWebAPI, private router: Router) {
this.SelectedTask = new Task();
this.SelectedTask.id = 0;
}
created() {
this.api.getTaskList().then(tasks => this.tasks = tasks);
}
selectTask(task) {
this.router.navigateToRoute("tasks", { id: task.id });
this.SelectedTask = new Task();
Object.assign(this.SelectedTask, task);
}
}
TaskDetail组件
任务详细信息。html:
<template>
<form class="form-horizontal">
<div class="form-group">
<label for="taskTitle">Title</label>
<input type="text" placeholder="Task Title" id="taskTitle" class="form-control" value.bind="task.title" />
</div>
<div class="form-group">
<label for="taskPriority" class="control-label col-sm-2">Priority</label>
<div class="col-sm-3">
<input type="number" placeholder="Task Priority" id="taskPriority" class="form-control" value.bind="task.priority" />
</div>
<label for="taskStatus" class="control-label col-sm-2">Status</label>
<div class="col-sm-4">
<select class="form-control" value.bind="task.status">
<option repeat.for="status of taskStatuses">${status}</option>
</select>
</div>
</div>
<div class="form-group">
<label for="taskPctComplete" class="control-label col-sm-2">Percent Complete</label>
<div class="col-sm-3">
<input type="number" placeholder="Task % Complete" id="taskPctComplete" class="form-control" value.bind="task.percentComplete" />
</div>
</div>
<div class="form-group">
<label for="taskStartDate" class="control-label col-sm-2">Start Date</label>
<div class="col-sm-4">
<input type="date" placeholder="Start Date" id="taskStartDate" class="form-control" value.bind="task.startDate" />
</div>
<label for="taskDueDate" class="control-label col-sm-2">Due Date</label>
<div class="col-sm-4">
<input type="date" placeholder="Due Date" id="taskDueDate" class="form-control" value.bind="task.dueDate" />
</div>
</div>
<div class="form-group">
<label for="taskDescription" class="control-label col-sm-2">Description</label>
<div class="col-sm-10">
<textarea class="form-control" rows="4" id="taskDescription" value.bind="task.description"></textarea>
<!--This is the area place where the string interpolation is doing something that I don't understand. -->
<p>
Dates: | ${task.startDate} | ${task.dueDate}
</p>
</div>
</div>
<button type="button" class="btn btn-default" click.trigger="cancelClick()">Cancel</button>
</form>
</template>
任务详细信息。ts
import {autoinject} from 'aurelia-framework';
import {TaskWebAPI} from './task-web-api';
import {Router} from 'aurelia-router';
@autoinject
export class TaskDetail {
routeConfig;
task;
taskStatuses;
constructor(private api: TaskWebAPI, private router: Router) { }
activate(params, routeConfig) {
this.routeConfig = routeConfig;
return this.api.getTaskDetails(params.id).then(task => {
this.task = task;
this.routeConfig.navModel.setTitle(this.task.title);
}).then(() => this.api.getTaskStatuses())
.then((statuses) => this.taskStatuses = statuses);
//this.api.getTaskStatuses();
}
cancelClick() {
this.router.navigateToRoute('noselection');
}
}
任务Web Api
let latency = 200;
let id = 0;
function getId(){
return ++id;
}
export class Task {
id: number;
title: string;
priority: number;
status: string;
percentComplete: number;
description: string;
startDate: Date;
dueDate: Date;
}
let taskStatuses = ['Not Started', 'In Progress', 'Deferred', 'Completed'];
let tasks = [
{
id:getId(),
title:'TestTask1',
priority:'1',
status:'In Progress',
percentComplete:'22',
description:'This is the first test task.',
startDate:'12/25/2017',
dueDate:'1/25/2018'
},
{
id:getId(),
title:'TestTask2',
priority:'1',
status:'In Progress',
percentComplete:'45',
description:'This is the second test task.',
startDate:'1/25/2017',
dueDate:'11/25/2017'
},
{
id:getId(),
title:'TestTask3',
priority:'2',
status:'In Progress',
percentComplete:'89',
description:'This is the third test task.',
startDate:'4/25/2017',
dueDate:'9/25/2018'
},
{
id:getId(),
title:'TestTask4',
priority:'2',
status:'In Progress',
percentComplete:'10',
description:'This is the fourth test task.',
startDate:'5/25/2017',
dueDate:'7/16/2017'
},
{
id:getId(),
title:'TestTask5',
priority:'3',
status:'Not Started',
percentComplete:'0',
description:'This is the fifth test task.',
startDate:'',
dueDate:''
}
];
export class TaskWebAPI {
isRequesting = false;
getTaskList(){
this.isRequesting = true;
return new Promise(resolve => {
setTimeout(() => {
let results = tasks.map(x => { return {
id:x.id,
title:x.title,
priority:x.priority,
status:x.status,
percentComplete:x.percentComplete,
description:x.description,
startDate:x.startDate,
dueDate:x.dueDate
}});
resolve(results);
this.isRequesting = false;
}, latency);
});
}
getTaskStatuses() {
this.isRequesting = true;
return new Promise(resolve => {
setTimeout(() => {
let results = taskStatuses;
resolve(results);
this.isRequesting = false;
}, latency);
});
}
getTaskDetails(id){
this.isRequesting = true;
return new Promise(resolve => {
setTimeout(() => {
let found = tasks.filter(x => x.id == id)[0];
resolve(JSON.parse(JSON.stringify(found)));
this.isRequesting = false;
}, latency);
});
}
saveTask(task){
this.isRequesting = true;
return new Promise(resolve => {
setTimeout(() => {
let instance = JSON.parse(JSON.stringify(task));
let found = tasks.filter(x => x.id == task.id)[0];
if(found){
let index = tasks.indexOf(found);
tasks[index] = instance;
}else{
instance.id = getId();
tasks.push(instance);
}
this.isRequesting = false;
resolve(instance);
}, latency);
});
}
}
这可能是一个愚蠢的问题,但为什么每次都必须清除任务详细信息视图,以便在
<p>
要绑定的元素?所有其他元素似乎只需切换到新视图即可正确绑定。我知道这一切的运作方式可能有一些我不明白的地方,我正在寻找一个正确的方向。