require 'volt/page/bindings/base_binding' class EachBinding < BaseBinding def initialize(target, context, binding_name, getter, variable_name, template_name) # puts "New EACH Binding" super(target, context, binding_name) @item_name = variable_name @template_name = template_name # Find the source for the content binding @value = value_from_getter(getter) @templates = [] # Run the initial render update @added_listener = @value.on('added') { |_, position, item| puts "ADDED" ; item_added(position) } @changed_listener = @value.on('changed') { puts "CHANGED" ; reload } @removed_listener = @value.on('removed') { |_, position| item_removed(position) } end # When a change event comes through, its most likely upstream, so the whole # array might have changed. In this case, just reload the whole thing # TODO: Track to make sure the changed event isn't being called too often (it is currently) def reload # ObjectTracker.enable_cache # Remove all of the current templates if @templates @templates.each do |template| template.remove_anchors # TODO: Make sure this is being removed since we already removed the anchors template.remove end end @templates = [] # Run update again to rebuild update # ObjectTracker.disable_cache end def item_removed(position) position = position.cur @templates[position].remove_anchors @templates[position].remove @templates.delete_at(position) value_obj = @value.cur if value_obj size = value_obj.size - 1 else size = 0 end # puts "Position: #{position} to #{size}" # Removed at the position, update context for every item after this position position.upto(size) do |index| @templates[index].context.locals[:index].cur = index end end def item_added(position) # ObjectTracker.enable_cache # puts "ADDED 1" binding_name = @@binding_number @@binding_number += 1 # Setup new bindings in the spot we want to insert the item section.insert_anchor_before_end(binding_name) index = ReactiveValue.new(position) value = @value[index] item_context = SubContext.new({@item_name => value, :index => index, :parent => @value}, @context) # ObjectTracker.enable_cache @templates << TemplateRenderer.new(@target, item_context, binding_name, @template_name) # puts "ADDED 2" # ObjectTracker.disable_cache end def update(item=nil) if item values = [item] else values = @value.cur return if values.is_a?(Model) || values.is_a?(Exception) values = values.attributes end # TODO: Switch to #each? values.each_with_index do |value,index| item_added(index) end end # When this each_binding is removed, cleanup. def remove # puts "Remove Each" @added_listener.remove @added_listener = nil @changed_listener.remove @changed_listener = nil @removed_listener.remove @removed_listener = nil @templates.each(&:remove) @templates = nil super end end