Class: Volt::AttributeBinding

Inherits:
BaseBinding show all
Defined in:
lib/volt/page/bindings/attribute_binding.rb

Instance Attribute Summary

Attributes inherited from BaseBinding

#binding_name, #context, #target

Instance Method Summary collapse

Methods inherited from BaseBinding

#dom_section

Constructor Details

#initialize(page, target, context, binding_name, attribute_name, getter, setter) ⇒ AttributeBinding

Returns a new instance of AttributeBinding.



6
7
8
9
10
11
12
13
14
# File 'lib/volt/page/bindings/attribute_binding.rb', line 6

def initialize(page, target, context, binding_name, attribute_name, getter, setter)
  super(page, target, context, binding_name)

  @attribute_name = attribute_name
  @getter         = getter
  @setter         = setter

  setup
end

Instance Method Details

#changed(event = nil) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/volt/page/bindings/attribute_binding.rb', line 45

def changed(event = nil)
  case @attribute_name
    when 'value'
      current_value = `#{element}.val() || ''`
    else
      current_value = `#{element}.is(':checked')`
  end

  if @is_radio
    if current_value
      # if it is a radio button and its checked
      @context.instance_exec(@selected_value, &@setter)
    end
  else
    @context.instance_exec(current_value, &@setter)
  end
end

#elementObject



63
64
65
# File 'lib/volt/page/bindings/attribute_binding.rb', line 63

def element
  @element ||= `$('#' + #{binding_name})`
end

#removeObject



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/volt/page/bindings/attribute_binding.rb', line 128

def remove
  # Unbind events, leave the element there since attribute bindings
  # aren't responsible for it being there.
  case @attribute_name
    when 'value'
      `#{element}.off('input.attrbind', #{nil})`
    when 'checked'
      `#{element}.off('change.attrbind', #{nil})`
  end

  if @computation
    @computation.stop
    @computation = nil
  end

  @string_template_renderer.remove if @string_template_renderer
  @string_template_renderer_computation.stop if @string_template_renderer_computation

  # Clear any references
  @target  = nil
  @context = nil
  @getter  = nil
end

#remove_anchorsObject



152
153
154
# File 'lib/volt/page/bindings/attribute_binding.rb', line 152

def remove_anchors
  fail 'attribute bindings do not have anchors, can not remove them'
end

#setupObject



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/volt/page/bindings/attribute_binding.rb', line 16

def setup
  # Listen for changes
  @computation = -> do
    begin
      @context.instance_eval(&@getter)
    rescue => e
      Volt.logger.error("AttributeBinding Error: #{e.inspect}")
      ''
    end
  end.watch_and_resolve! do |result|
    update(result)
  end

  @is_radio = `#{element}.is('[type=radio]')`
  if @is_radio
    @selected_value = `#{element}.attr('value') || ''`
  end

  # Bind so when this value updates, we update
  case @attribute_name
    when 'value'
      changed_event = Proc.new { changed }
      `#{element}.on('input.attrbind', #{changed_event})`
    when 'checked'
      changed_event = Proc.new { |event| changed(event) }
      `#{element}.on('change.attrbind', #{changed_event})`
  end
end

#update(new_value) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/volt/page/bindings/attribute_binding.rb', line 67

def update(new_value)
  if @attribute_name == 'checked'
    update_checked(new_value)
    return
  end

  # Stop any previous reactive template computations
  @string_template_renderer_computation.stop if @string_template_renderer_computation
  @string_template_renderer.remove if @string_template_renderer

  if new_value.is_a?(StringTemplateRenderer)
    # We don't need to refetch the whole reactive template to
    # update, we can just depend on it and update directly.
    @string_template_renderer = new_value

    @string_template_renderer_computation = -> do
      self.value = @string_template_renderer.html
    end.watch!
  else
    if new_value.is_a?(NilMethodCall) || new_value.nil?
      new_value = ''
    end

    self.value = new_value
  end
end

#update_checked(value) ⇒ Object



116
117
118
119
120
121
122
123
124
125
126
# File 'lib/volt/page/bindings/attribute_binding.rb', line 116

def update_checked(value)
  if value.is_a?(NilMethodCall) || value.nil?
    value = false
  end

  if @is_radio
    value = (@selected_value == value)
  end

  `#{element}.prop('checked', #{value})`
end

#value=(val) ⇒ Object



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/volt/page/bindings/attribute_binding.rb', line 94

def value=(val)
  case @attribute_name
    when 'value'
      # TODO: only update if its not the same, this keeps it from moving the
      # cursor in text fields.
      if val != `(#{element}.val() || '')`
        `#{element}.val(#{val})`
      end
    when 'disabled'
      # Disabled is handled specially, you can either return a boolean:
      # (true being disabled, false not disabled), or you can optionally
      # include the "disabled" string. (or any string)
      if val != false && val.present?
        `#{element}.attr('disabled', 'disabled')`
      else
        `#{element}.removeAttr('disabled')`
      end
    else
      `#{element}.attr(#{@attribute_name}, #{val})`
  end
end