Aurelia-帮助理解我看到的一些绑定行为
在完成ContactManager教程后,我想通过将ContactManager站点修改为任务列表站点来进行一些练习。我已将联系人列表组件和联系人详细信息组件更改为使用任务而不是联系人。基本上,当我点击任务列表中的任务时,路由器会打开一个任务细节组件;与“联系人管理器”教程中的工作方式非常相似 问题 在TaskDetail组件中,我在元素中有一些文本,该元素使用字符串插值绑定到一些模型值。 日期:|${task.startDate}|${task.dueDate}当我第一次单击任务列表中的任务时,任务细节视图在元素中打开,插入的字符串正确呈现,例如:日期:| 12/25/2017 | 1/25/2018如果我单击任务列表中的另一个任务,“任务详细信息”视图中的所有字段都正确更改,元素中的文本除外。它变成了日期:| |要在元素中显示文本,我必须让路由器放入另一个视图,然后再次选择另一个任务,从而清除选择。这将重新渲染视图,并再次显示插值 为什么我必须重新渲染task detail视图才能将viewmodel中的值绑定到视图 我将在下面发布代码和标记,但我还将一些示例代码推送到了一个案例中,以防有所帮助。我试着把它写进Gist.Run中,但由于我使用的是Typescript,这证明是有问题的 任务列表组件 task-list.html:Aurelia-帮助理解我看到的一些绑定行为,aurelia,Aurelia,在完成ContactManager教程后,我想通过将ContactManager站点修改为任务列表站点来进行一些练习。我已将联系人列表组件和联系人详细信息组件更改为使用任务而不是联系人。基本上,当我点击任务列表中的任务时,路由器会打开一个任务细节组件;与“联系人管理器”教程中的工作方式非常相似 问题 在TaskDetail组件中,我在元素中有一些文本,该元素使用字符串插值绑定到一些模型值。 日期:|${task.startDate}|${task.dueDate}当我第一次单击任务列表中的任务时
<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>
TaskDetail组件
task-detail.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>
任务Web Api
这可能是一个愚蠢的问题,但为什么每次都必须清除TaskDetail视图,才能绑定元素中的插值字符串?所有其他元素似乎只要切换到新视图就可以正确绑定。我知道这一切是如何运作的,可能有一些我不明白的地方,我正在寻找一个正确的方向。你的绑定没有问题。是输入类型=日期把事情搞砸了。您可以通过执行以下操作来验证这一点:
getTaskDetails(id) {
this.isRequesting = true;
return new Promise(resolve => {
setTimeout(() => {
let found = tasks.filter(x => x.id == id)[0];
let res = JSON.parse(JSON.stringify(found));
// Note these
console.log('Found: ', found);
console.log('Result: ', res);
resolve(res);
this.isRequesting = false;
}, latency);
});
}
在task-web-api.ts中,将getTaskDetails更改为以下内容:
getTaskDetails(id) {
this.isRequesting = true;
return new Promise(resolve => {
setTimeout(() => {
let found = tasks.filter(x => x.id == id)[0];
let res = JSON.parse(JSON.stringify(found));
// Note these
console.log('Found: ', found);
console.log('Result: ', res);
resolve(res);
this.isRequesting = false;
}, latency);
});
}
在task-detail.ts中,将激活更改为:
总之,导致这种行为的不是绑定。相反,发生这种情况是因为格式无效,因此该值被拒绝。根据,没有标准的方法来更改输入类型=日期所使用的格式,因此您应该使用标准的yyyy-MM-dd格式。如果您在task-web-api.ts中更改了虚拟数据,那么输入类型=date也会起作用
同时,令人奇怪的是,这种情况在第一次绑定之后不会发生,但在以后会发生。然而,我不认为是奥雷莉亚造成了这个问题,可能是浏览器造成的。尽管如此,还是有必要就此提出一个问题。如何清除任务详细信息视图?本教程有一个无选择组件。我所做的只是在任务详细信息页面上添加一个取消按钮和一条到路由器的路由。单击按钮时,它会调用此.router.navigatetoRoute'noselection'来加载元素中的无选择组件。您不必这样做。只需将一个新对象分配给任务属性。但它有点让人困惑,你想做什么,所以你可能想在gist run创建一个演示?@bigopon谢谢你,顺便说一句,谢谢你看了我的问题。我以前从未使用过gist运行,所以可能我遗漏了一些东西,但由于我使用的是Typescript,所以我似乎无法使它与我的项目一起工作。我将代码上传到了一个公共Github repo。希望这能帮助你或其他任何人看看这个问题。这是链接:我还在README.md文件中包含了关于如何重现该问题的说明。哇,这真的很有趣。谢谢你的帮助。我不认为我会找到它否则。特别是因为我一直在使用Firefox进行测试,它没有显示日期值格式不正确的警告。它显示其他日志消息,但不显示这些日志消息。谢谢
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);
});
}
}
getTaskDetails(id) {
this.isRequesting = true;
return new Promise(resolve => {
setTimeout(() => {
let found = tasks.filter(x => x.id == id)[0];
let res = JSON.parse(JSON.stringify(found));
// Note these
console.log('Found: ', found);
console.log('Result: ', res);
resolve(res);
this.isRequesting = false;
}, latency);
});
}
activate(params, routeConfig) {
this.routeConfig = routeConfig;
return this.api.getTaskDetails(params.id).then(task => {
// Note this:
console.log('Task: ', task);
this.task = <iTask>task;
this.routeConfig.navModel.setTitle(this.task.title);
}).then(() => this.api.getTaskStatuses())
.then((statuses) => this.taskStatuses = statuses);
}
<div class="form-group">
<label for="taskStartDate" class="control-label col-sm-2">Start Date</label>
<div class="col-sm-4">
<input type="text" 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="text" placeholder="Due Date" id="taskDueDate" class="form-control" value.bind="task.dueDate" />
</div>
</div>