Skip to content

Commit 70edf08

Browse files
Fix an error for v-bind in a v-for with different amount of props (#144)
* Fix an error for v-bind in a v-for with different amount of props/attributes * Bump version to 0.8.10
1 parent c6b7956 commit 70edf08

3 files changed

Lines changed: 62 additions & 21 deletions

File tree

collagraph/fragment.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -196,17 +196,20 @@ def _watch_bind_dict(self, name, expression):
196196
def update(self, new: set[str], old: set[str] | None):
197197
if old is None:
198198
old = set()
199-
for attr in new - old:
200-
self._watch_bind(
201-
attr,
202-
lambda attr=attr: expression()[attr],
203-
)
204-
205-
for attr in old - new:
206-
if f"bind:{attr}" in self._watchers:
207-
del self._watchers[f"bind:{attr}"]
208-
# Perform cleanup
209-
self._rem_attr(attr)
199+
if additional_attrs := new - old:
200+
for attr in additional_attrs:
201+
self._watch_bind(
202+
attr,
203+
lambda attr=attr: expression()[attr],
204+
)
205+
206+
if removed_attrs := old - new:
207+
for attr in removed_attrs:
208+
if f"bind:{attr}" in self._watchers:
209+
unwatch = self._watchers.pop(f"bind:{attr}")
210+
unwatch()
211+
# Perform cleanup
212+
self._rem_attr(attr)
210213

211214
self._watchers[f"bind_dict:{name}"] = watch(
212215
lambda: set(expression().keys()),
@@ -294,19 +297,17 @@ def unmount(self, destroy=True):
294297
self._events = {}
295298
# Disable the fn and callback of the watcher to disable
296299
# any 'false' triggers
297-
for watcher in self._watchers.values():
298-
watcher.fn = lambda: ()
299-
watcher.callback = None
300+
for unwatch in self._watchers.values():
301+
unwatch()
300302
self._watchers = {}
301303
self._condition = None
302304
self.tag = None
303305
else:
304306
self.element = None
305307
# Disable the fn and callback of the watcher to disable
306308
# any 'false' triggers
307-
for watcher in self._watchers.values():
308-
watcher.fn = lambda: ()
309-
watcher.callback = None
309+
for unwatch in self._watchers.values():
310+
unwatch()
310311
self._watchers = {}
311312

312313
# TODO: maybe control flow fragments needs another custom 'parenting'
@@ -871,8 +872,7 @@ def unmount(self, destroy=True):
871872
self._attributes = {}
872873
self._events = {}
873874
if self._type_watcher:
874-
self._type_watcher.fn = lambda: ()
875-
self._type_watcher.callback = None
875+
self._type_watcher()
876876
self._type_watcher = None
877877
self._condition = None
878878
self._expression = None

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "collagraph"
3-
version = "0.8.9"
3+
version = "0.8.10"
44
description = "Reactive user interfaces"
55
authors = [
66
{ name = "Berend Klein Haneveld", email = "berendkleinhaneveld@gmail.com" },
@@ -10,7 +10,7 @@ requires-python = ">=3.10"
1010
readme = "README.md"
1111
license = "MIT"
1212
dependencies = [
13-
"observ>=0.14.1",
13+
"observ>=0.17.1",
1414
]
1515

1616
[project.scripts]

tests/test_attributes_dynamic.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,3 +372,44 @@ def init(self):
372372
)
373373
with pytest.raises(NameError):
374374
gui.render(App, container, state=state)
375+
376+
377+
def test_dynamic_attribute_key_error(parse_source):
378+
App, _ = parse_source(
379+
"""
380+
<node
381+
v-for="node in nodes"
382+
v-bind="node"
383+
/>
384+
385+
<script>
386+
import collagraph as cg
387+
388+
class App(cg.Component):
389+
pass
390+
</script>
391+
"""
392+
)
393+
394+
state = reactive(
395+
{
396+
"nodes": [
397+
{"foo": "foo", "bar": "bar"},
398+
{"foo": "foo"},
399+
]
400+
}
401+
)
402+
container = {"type": "root"}
403+
gui = Collagraph(
404+
renderer=DictRenderer(),
405+
event_loop_type=EventLoopType.SYNC,
406+
)
407+
gui.render(App, container, state=state)
408+
409+
assert len(container["children"]) == 2
410+
411+
# The second item does not have the 'bar' attribute
412+
# which used to trigger a KeyError
413+
state["nodes"].pop(0)
414+
415+
assert len(container["children"]) == 1

0 commit comments

Comments
 (0)