我有一个在我的代码库中使用的对象,我想扩展它以便它可以像一个数组一样工作。我尝试过使用Ember的MutableArray mixin取得了一些成功,但我还是需要手动回复对象的变化(即调用foo.arrayContentWillChange
和foo.arrayContentDidChange
)。我已经解除了ArrayProxy
的大部分代码,所以看起来应该很熟悉。
任何帮助将不胜感激。谢谢!
我必须公布对数组的所有更改,如下所示:
index = model.indexOf(@get('element'))
model.arrayContentWillChange(index, 1, 0)
model.removeAt(index)
model.arrayContentDidChange(index, 1, 0)
我想像Ember数组一样使用我的对象:
model.removeObject(@get('element'))
module.exports = DraftCampaign = ArrayModel.extend({
item : null
page_options : null
needs_loader : null
embeds : {CampaignEntity : 'item'} # The HAL API defines the name 'item'
#
# Alias the embeds array to content. This is used by ArrayModel to
# expose a MutableArry interface.
#
content: Ember.computed.alias('item')
init: ->
@_super()
@set('item', Ember.A([]))
populate_fields: (data) -> # "item" is initialized here.
@setAllProperties(@, data)
})
module.exports = ArrayModel = MyModel.extend(Ember.MutableArray, {
content : null
arrangedContent : Ember.computed.alias('content')
contentArrayWillChange : Ember.K
contentArrayDidChange : Ember.K
arrangedContentWillChange : Ember.K
arrangedContentDidChange : Ember.K
init: ->
@_super()
@_setupContent()
@_setupArrangedContent()
objectAt: (index) ->
if Ember.get(@, 'content')
@objectAtContent(index)
else
throw new Ember.Error 'content is undefined'
length: ( ->
arrangedContent = Ember.get(@, 'arrangedContent')
if arrangedContent then Ember.get(arrangedContent, 'length') else 0
).property('arrangedContent.@each')
replace: ->
if (Ember.get(@, 'arrangedContent') is Ember.get(@, 'content'))
@_replace.apply(@, arguments)
else
throw new Ember.Error 'Using replace on an arranged ArrayProxy is not allowed.'
removeAt: (start, length = 1) ->
if typeof start is 'number'
content = Ember.get(@, 'content')
arrangedContent = Ember.get(@, 'arrangedContent')
indicies = []
if ((start < 0) or (start >= Ember.get(@, 'length')))
throw new Ember.Error('index out of range')
[start...start + length].map (index) ->
indicies.push(content.indexOf(arrangedContent.objectAt(index)))
indicies.sort((a,b) -> b - a)
Ember.beginPropertyChanges()
[0...indicies.length].map (index) =>
@_replace(indicies[index], 1, [])
Ember.endPropertyChanges()
pushObject: (obj) ->
content = Ember.get(@, 'content')
@_insertAt(Ember.get(content, 'length'), obj)
return obj
pushObjects: (objects) ->
if (not(Ember.Enumerable.detect(objects) or Ember.isArray(objects)))
throw new TypeError(
'Must pass Ember.Enumerable to Ember.MutableArry#pushObjects'
)
@_replace(Ember.get(@, 'length'), 0, objects)
return @
setObjects: (objects) ->
return @clear() unless objects.length
length = Ember.get(@, 'length')
@_replace(0, length, objects)
return @
unshiftObject: (obj) ->
@_insertAt(0, obj)
return obj
slice: ->
arr = @toArray()
return arr.slice.apply(arr, arguments)
arrangedContentArrayWillChange: (item, index, removedCnt, addedCnt) ->
@arrayContentWillChange(index, removedCnt, addedCnt)
arrangedContentArrayDidChange: (item, index, removedCnt, addedCnt) ->
@arrayContentDidChange(index, removedCnt, addedCnt)
arrayWillChange: ->
@arrayContentWillChange(arguments[1], arguments[2], arguments[3])
arrayDidChange: ->
@arrayContentDidChange(arguments[1], arguments[2], arguments[3])
willDestroy: ->
@_teardownArrangedContent()
@_teardownContent()
})
#
# Private Methods
#
AdStageArrayModel.reopen({
objectAtContent: (index) ->
Ember.get(@, 'arrangedContent').objectAt(index)
replaceContent: (index, amt, objects) ->
content = Ember.get(@, 'content')
@_contentWillChagne()
@arrayContentWillChange(index, amt, objects.length)
content.replace(index, amt, objects)
@arrayContentDidChange(index, amt, objects.length)
@_contentDidChange()
_contentWillChange: Ember.beforeObserver('content', ->
@_teardownContent()
)
_teardownContent: ->
content = Ember.get(@, 'content')
if content
content.removeArrayObserver(@, {
willChange : 'contentArrayWillChange'
didChange : 'contentArrayDidChange'
})
_insertAt: (index, object) ->
throw new Ember.Error('out of range') if (index > Ember.get(@, 'content.length'))
@_replace(index, 0, [object])
return @
_replace: (index, amt, objects) ->
content = Ember.get(@, 'content')
Ember.assert('The content property of ' + @.constructor + ' should be set' +
' before modifying if', content)
@replaceContent(index, amt, objects) if content
return @
_contentDidChange: Ember.observer('content', ->
content = Ember.get(@, 'content')
Ember.assert('Can\'t set ArrayProxy\'s content to itself', content is not @)
@_setupContent()
)
_setupContent: ->
content = Ember.get(@, 'content')
if content
Ember.assert(
Ember.String.fmt('ArrayProxy expects an Array or ' +
'Ember.ArrayProxy, but you passed %@', [typeof content]),
Ember.isArray(content) || content.isDestroyed
)
content.addArrayObserver(@, ->
willChange : 'contentArrayWillChange'
didChange : 'contentArrayDidChange'
)
_arrangedContentWillChange: Ember.beforeObserver('arrangedContent', ->
arrangedContent = Ember.get(@, 'arrangedContent')
len = if arrangedContent then Ember.get(arrangedContent, 'length') else 0
@arrangedContentArrayWillChange(@, 0, len, undefined)
@arrangedContentWillChange(@)
@_teardownArrangedContent(arrangedContent)
)
_arrangedContentDidChange: Ember.observer('arrangedContent', ->
arrangedContent = Ember.get(@, 'arrangedContent')
len = if arrangedContent then Ember.get(arrangedContent, 'length') else 0
Ember.assert(
'Can\'t set ArrayProxy\'s content to itself',
arrangedContent is not @
)
@_setupArrangedContent()
@arrangedContentDidChange(@)
@arrangedContentArrayDidChange(@, 0, undefined, len)
)
_setupArrangedContent: ->
arrangedContent = Ember.get(@, 'arrangedContent')
if arrangedContent
Ember.assert(Ember.String.fmt('ArrayProxy expects an Array or ' +
'Ember.ArrayProxy, but you passed %@', [typeof arrangedContent]),
Ember.isArray(arrangedContent) || arrangedContent.isDestroyed)
arrangedContent.addArrayObserver(@, {
willChange : 'arrangedContentArrayWillChange'
didChange : 'arrangedContentArrayDidChange'
})
_teardownArrangedContent: ->
arrangedContent = Ember.get(@, 'arrangedContent')
if arrangedContent
arrangedContent.removeArrayObserver(@, {
willChange : 'arrangedContentArrayWillChange'
didChange : 'arrangedContentArrayDidChange'
})
})
答案 0 :(得分:1)
我认为这可能有助于简化一下。请参阅TestMutableArray了解最简单的实现(尽管我认为slice
是严格要求的,除了性能之外 - 如果objectAt
不是slice
,它将使用replace
可用)。 MutableArray将通过arrayContentWillChange
管理所有更改,因此您只需为所有方法在该位置调用arrayContentDidChange
和length
。
作为参考,这里是我发现实现MutableArray的所有类。其中许多实现了额外的方法,但我认为它们主要是为那些特定的实现需要进行额外的簿记:
注意:Ember文档未按要求提及replace
,但没有它{{1}}会传递一些奇怪的值,而某些方法似乎不起作用。