Почему мой Ember MutableArray не объявляет об изменениях?
У меня есть объект, который используется во всей нашей кодовой базе, и я хочу расширить его, чтобы он мог действовать как массив. Я попытался использовать мибин MutableArray от Ember с некоторым успехом, но мне все еще нужно объявить изменения объекта вручную (т.е. вызвать foo.arrayContentWillChange
а также foo.arrayContentDidChange
). Я снял большую часть кода с ArrayProxy
так что это должно выглядеть довольно знакомо.
Любая помощь будет оценена. Спасибо!
проблема
Я должен объявить все свои изменения в массиве так:
index = model.indexOf(@get('element'))
model.arrayContentWillChange(index, 1, 0)
model.removeAt(index)
model.arrayContentDidChange(index, 1, 0)
Я хотел бы использовать мой объект как Ember Array:
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'
})
})
1 ответ
Я думаю, что это может помочь немного упростить. См. TestMutableArray для того, что, вероятно, является самой простой реализацией (хотя я не думаю, slice
строго требуется, кроме того, для выполнения - он будет использовать objectAt
если slice
не доступен). MutableArray направит все изменения через replace
так что вам нужно только позвонить arrayContentWillChange
а также arrayContentDidChange
в этом одном месте для всех методов.
Для справки, вот все классы, которые я обнаружил, которые реализуют MutableArray. Многие из них реализуют дополнительные методы, но я думаю, что в основном они предназначены для дополнительной бухгалтерии, которую необходимо было сделать для этих конкретных реализаций:
Примечание: в документации Ember не упоминается length
по мере необходимости, но без него replace
получает некоторые странные значения, а некоторые методы не работают.