我有3个模型: type
, restriction
和 item
。
type
很简单,只有一个id
:
app/models/type.js
:
import Model from 'ember-data/model';
export default Model.extend({});
restriction
可以有多个 type
描述具有此限制的项目的允许类型:
app/models/restriction.js
:
import Model from 'ember-data/model';
import { hasMany } from 'ember-data/relationships';
export default Model.extend({
allowedTypes: hasMany( "type" )
});
item
可以包含多个 type
,但也可以包含多个 restriction
type
必须只是所有限制的允许类型的交集的子集(如果至少有一个限制,那么它必须至少有一种类型)。
我已使用计算属性对此进行了验证:
app/models/item.js
:
import Model from 'ember-data/model';
import { computed } from '@ember/object';
import { hasMany } from 'ember-data/relationships';
import { isEmpty } from '@ember/utils';
const peekHasMany = attr => ( item => item.hasMany( attr ).ids() );
const hasItems = array => !isEmpty( array );
const includedIn = array => ( item => array.indexOf( item ) >= 0 );
const intersectionOf = ( array1, array2, index ) => index >= 0 ? array1.filter( includedIn( array2 ) ) : array2;
export default Model.extend({
types: hasMany( "type" ),
restrictions: hasMany( "restriction" ),
isValidTypes: computed(
"types.[]",
"restrictions.@each.allowedTypes",
function(){
let restrictions = this.hasMany( "restrictions" ).value();
if ( isEmpty( restrictions ) )
{
return true;
}
let allowed = restrictions
.map( peekHasMany( "allowedTypes" ) )
.filter( hasItems );
if ( isEmpty( allowed ) )
{
return true;
}
let types = this.hasMany( "types" ).ids();
if ( isEmpty( types ) )
{
return false;
}
let allowedTypes = allowed.reduce( intersectionOf );
return types.every( includedIn( allowedTypes ) );
}
)
});
这使用DS.Model.hasMany( attributeName )
同步获取依赖于所加载的引用模型的关系的HasManyReference
。
如何更改计算属性以使用this.get()
异步获取两个属性(和子属性)而不是同步使用this.hasMany()
?
答案 0 :(得分:1)
let value = this.hasMany( attributeName ).value();
/* following code */
可以替换为
this.get( attributeName ).then( value => { /* following code */ } );
复杂性来自以下几行:
const peekHasMany = attr => ( item => item.hasMany( attr ).ids() );
let allowed = restrictions.map( peekHasMany( "allowedTypes" ) )
/* following code */
其中,更改时会产生一系列承诺。这可以使用Promise.all( arrayOfPromises )
const getAll = attr => ( item => item.get( attr ) );
Promise.all( restrictions.map( getAll( "allowedTypes" ) ) )
.then( allowed => {
/* following code */
} );
然后代码变为:
import Model from 'ember-data/model';
import { computed } from '@ember/object';
import { hasMany } from 'ember-data/relationships';
import { isEmpty } from '@ember/utils';
const getAll = attr => ( item => item.get( attr ) );
const hasItems = array => !isEmpty( array );
const includedIn = array => ( item => array.indexOf( item ) >= 0 );
const intersectionOf = ( array1, array2, index ) => index >= 0 ? array1.filter( includedIn( array2 ) ) : array2;
export default Model.extend({
types: hasMany( "type" ),
restrictions: hasMany( "restriction" ),
isValidTypes: computed(
"types.[]",
"restrictions.@each.allowedTypes",
function(){
return this.get( "restrictions" )
.then( restrictions => {
if ( isEmpty( restrictions ) )
{
return true;
}
return Promise.all( restrictions.map( getAll( "allowedTypes" ) ) )
.then( allowed => {
allowed = allowed.filter( hasItems );
if ( isEmpty( allowed ) )
{
return true;
}
return this.get( "types" )
.then( types => {
if ( isEmpty( types ) )
{
return false;
}
let allowedTypes = allowed.reduce( intersectionOf );
return types.every( includedIn( allowedTypes ) );
} );
} );
} );
}
)
});
或使用async
和await
语法:
import Model from 'ember-data/model';
import { computed } from '@ember/object';
import { hasMany } from 'ember-data/relationships';
import { isEmpty } from '@ember/utils';
const getAll = attr => ( item => item.get( attr ) );
const hasItems = array => !isEmpty( array );
const includedIn = array => ( item => array.indexOf( item ) >= 0 );
const intersectionOf = ( array1, array2, index ) => index >= 0 ? array1.filter( includedIn( array2 ) ) : array2;
export default Model.extend({
types: hasMany( "type" ),
restrictions: hasMany( "restriction" ),
isValidTypes: computed(
"types.[]",
"restrictions.@each.allowedTypes",
async function(){
let restrictions = await this.get( "restrictions" );
if ( isEmpty( restrictions ) )
{
return true;
}
let allowed = ( await Promise.all( restrictions.map( getAll( "allowedTypes" ) ) ) )
.filter( hasItems );
if ( isEmpty( allowed ) )
{
return true;
}
let types = await this.get( "types" );
if ( isEmpty( types ) )
{
return false;
}
let allowedTypes = allowed.reduce( intersectionOf );
return types.every( includedIn( allowedTypes ) );
}
)
});