我试图在多选表单的上下文中使用和理解Aurelia ValueConverter。我认为直截了当,对我来说是一个挑战。
我有一个表单来创建一个新的交易,它通过多选输入字段分配了多个类别。我已将表单中的输出绑定到new_deal.categorizations(在数据库中,交易通过分类具有类别)。
现在通过“蛮力”来创造。方法,我在发布到API之前将每个类别ID转换为{category_id:id}对象。
仅记录POST输出的示例:
create(){
var categorizations = this.new_deal.categorizations;
this.new_deal.categorizations = categorizations.map(function (e) {
return {category_id: e}
});
logger.debug ('POST: ', JSON.stringify(this.new_deal));
}
示例输出:
POST: {"name":"new deal","categorizations":[{"category_id":"1"},{"category_id":"2"}]}
但我认为最好通过ValueConverter来实现。
Plunker here包含完整代码,但基本上是:
app.js:
export class App {
constructor(){
this.categories = [{id: 1, name: 'test1'}, {id: 2, name: 'test2'}];
this.new_deal = {
name: 'new deal',
categorizations: null,
};
}
create(){
var categorizations = this.new_deal.categorizations;
this.new_deal.categorizations = categorizations.map(function (e) {return {category_id: e}});
logger.debug ('POST: ', JSON.stringify(this.new_deal));
}
create2(){
logger.debug ('POST: ', JSON.stringify(this.new_deal));
}
}
export class CategoryToIDValueConverter {
fromView(id) {
return id ? id: null;
}
}
和app.html:
<template>
<h1>Testing ValueConverter</h1>
<h3 >New Brute Force Deal</h3>
<form role="form">
<label>Name</label>
<input type="text" placeholder="Ex. Buy One Get One Free" value.bind="new_deal.name">
<label>Categories</label>
<select value.bind="new_deal.categorizations" multiple size="2">
<option repeat.for="category of categories" value.bind="category.id">${category.name}</option>
</select>
</form>
<button type="submit" click.delegate="create()">Save</button>
<h3>New ValueConverter Deal</h3>
<form role="form">
<label>Name</label>
<input type="text" placeholder="Ex. Buy One Get One Free" value.bind="new_deal.name">
<label>Categories</label>
<select class="form-control" value.bind="new_deal.categorizations | categoryToID" multiple size="2">
<option repeat.for="category of categories" value.bind="category.id">${category.name}</option>
</select>
</form>
<button class="btn btn-success" type="submit" click.delegate="create2()">Save</button>
</template>
有了这个,我得到了
的输出POST: {"name":"new deal","categorizations":["1","2"]}
在app.js中的fromView中,我认为我可以改变:
return id ? id: null;
要返回对象而不是单个值:
return id ? {category_id: id} : null
但是这导致了这个错误:
Uncaught Error: Only null or Array instances can be bound to a multi-select.
进一步检查后,看起来id作为一个数组来自View ...
所以我从View修改为:
fromView(id) {
if(id){
var categorizations = [];
id.forEach(function(cat_id){
categorizations.push({category_id: cat_id})
});
logger.debug(categorizations);
logger.debug(Object.prototype.toString.call(categorizations));
return categorizations;
} else { return null; }
}
}
尝试期望一个数组,然后构建一个要返回的分类对象数组,但正如您在this Plunker中看到的那样,它会在您单击时丢失选择(尽管调试日志显示正在创建的对象)
答案 0 :(得分:0)
您有一个类别对象数组,每个对象都有name
(字符串)和id
(数字)。这些将用于填充允许多选的选择元素:
export class App {
categories = [
{ id: 1, name: 'test1'},
{ id: 2, name: 'test2'}
];
}
<select multiple size="2">
<option repeat.for="category of categories">${category.name}</option>
</select>
交易对象由name
(字符串)和categorizations
组成。分类对象如下所示:{ category_id: 1 }
export class App {
categories = [
{ id: 1, name: 'test1'},
{ id: 2, name: 'test2'}];
deal = {
name: 'new deal',
categorizations: [],
}
}
我们希望将select元素的值绑定到交易对象的分类,这是一个对象数组。这意味着每个select元素的选项都需要有一个对象&#34; value&#34;。 HTMLOptionElement的value属性只接受字符串。我们分配给它的任何东西都将被强制转换为字符串。我们可以将分类对象存储在可以处理任何类型的特殊model
属性中。有关这方面的更多信息,请参阅aurelia docs。
<select multiple size="2">
<option repeat.for="category of categories" model.bind="{ category_id: category.id }">${category.name}</option>
</select>
最后,我们需要将select元素的值绑定到交易对象的分类:
<select value.bind="deal.categorizations" multiple size="2">
<option repeat.for="category of categories" model.bind="{ category_id: category.id }">${category.name}</option>
</select>
总之,视图和视图模型看起来像这样:
export class App {
categories = [
{ id: 1, name: 'test1'},
{ id: 2, name: 'test2'}];
deal = {
name: 'new deal',
categorizations: [],
}
createDeal() {
alert(JSON.stringify(this.deal, null, 2));
}
}
<template>
<form submit.delegate="createDeal()">
<label>Name</label>
<input type="text" placeholder="Ex. Buy One Get One Free" value.bind="deal.name">
<label>Categories</label>
<select value.bind="deal.categorizations" multiple size="2">
<option repeat.for="category of categories" model.bind="{ category_id: category.id }">${category.name}</option>
</select>
<button type="submit">Save</button>
</form>
</template>
这是一个工作的掠夺者:http://plnkr.co/edit/KO3iFBostdThrHUA0QHY?p=preview
答案 1 :(得分:0)
在Aurelia Gitter频道的whayes帮助下找出它。所以我在正确的轨道上期望在fromView方法中有一个数组,但我还需要在ValueConverter中使用toView方法。
export class CategoryToIDValueConverter {
toView(cats){
if (cats){
var ids = [];
cats.forEach(function(categorization){
ids.push(categorization.category_id);
});
return ids;
} else { return null; }
}
fromView(id) {
if(id){
var categorizations = [];
id.forEach(function(cat_id){
categorizations.push({category_id: cat_id})
});
return categorizations;
} else { return null; }
}
}
我也试过了,但我最初假设我需要将转换器添加到表单的选择行和选项行中,如下所示:
<select class="form-control" value.bind="new_deal.categorizations | categoryToID" multiple size="2">
<option repeat.for="category of categories" value.bind="category.id">${category.name}</option>
</select>
但那确实不对。我只需要将categoryToID ValueConverter应用于选择行,它们都按预期工作。
工作Plunker显示蛮力方法在您单击保存之前不会更改模型,并且ValueConverter会在您更改选择时更改它。
最终的app.js
import {LogManager} from 'aurelia-framework';
let logger = LogManager.getLogger('testItems');
export class App {
constructor(){
this.categories = [{id: 1, name: 'test1'}, {id: 2, name: 'test2'}];
this.new_deal = {
name: 'new deal',
categorizations: [],
};
setInterval(() => this.debug = JSON.stringify(this.new_deal, null, 2), 100);
}
create(){
var categorizations = this.new_deal.categorizations;
this.new_deal.categorizations = categorizations.map(function (e) {return {category_id: e}});
alert(JSON.stringify(this.new_deal, null, 2));
}
create2(){
alert(JSON.stringify(this.new_deal, null, 2));
}
}
export class CategoryToIDValueConverter {
toView(cats){
if (cats){
var ids = [];
cats.forEach(function(categorization){
ids.push(categorization.category_id);
});
return ids;
} else { return null; }
}
fromView(id) {
if(id){
var categorizations = [];
id.forEach(function(cat_id){
categorizations.push({category_id: cat_id})
});
return categorizations;
} else { return null; }
}
}
最终app.html
<template>
<h1>Testing ValueConverter</h1>
<h3 >New Brute Force Deal</h3>
<form role="form">
<label>Name</label>
<input type="text" placeholder="Ex. Buy One Get One Free" value.bind="new_deal.name">
<label>Categories</label>
<select value.bind="new_deal.categorizations" multiple size="2">
<option repeat.for="category of categories" value.bind="category.id">${category.name}</option>
</select>
</form>
<button type="submit" click.delegate="create()">Save</button>
<h3>New ValueConverter Deal</h3>
<form role="form">
<label>Name</label>
<input type="text" placeholder="Ex. Buy One Get One Free" value.bind="new_deal.name">
<label>Categories</label>
<select class="form-control" value.bind="new_deal.categorizations | categoryToID" multiple size="2">
<option repeat.for="category of categories" value.bind="category.id">${category.name}</option>
</select>
</form>
<button type="submit" click.delegate="create2()">Save</button>
<!-- debug -->
<pre><code>${debug}</code></pre>
</template>