Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: watch didn't work for Vue-only vars #86

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 22 additions & 19 deletions js/src/VueTemplateRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,27 +163,30 @@ function addModelListeners(model, vueModel) {
}

function createWatches(model, parentView, templateWatchers) {
return model.keys()
.filter(prop => !prop.startsWith('_')
&& !['events', 'template', 'components', 'layout', 'css', 'data', 'methods'].includes(prop))
.reduce((result, prop) => ({
...result,
[prop]: {
handler(value) {
if (templateWatchers && templateWatchers[prop]) {
templateWatchers[prop].bind(this)(value);
}
/* Don't send changes received from backend back */
if (_.isEqual(value, model.get(prop))) {
return;
}
const modelWatchers = model.keys().filter(prop => !prop.startsWith('_')
&& !['events', 'template', 'components', 'layout', 'css', 'data', 'methods'].includes(prop))
.reduce((result, prop) => ({
...result,
[prop]: {
handler(value) {
if (templateWatchers && templateWatchers[prop]) {
templateWatchers[prop].bind(this)(value);
}
/* Don't send changes received from backend back */
if (_.isEqual(value, model.get(prop))) {
return;
}

model.set(prop, value === undefined ? null : _.cloneDeep(value));
model.save_changes(model.callbacks(parentView));
},
deep: true,
model.set(prop, value === undefined ? null : _.cloneDeep(value));
model.save_changes(model.callbacks(parentView));
},
}), {});
deep: true,
},
}), {})
/* Overwritten keys from templateWatchers are handled in modelWatchers
so that we eventually call all handlers from templateWatchers.
*/
return {...templateWatchers, ...modelWatchers};
maartenbreddels marked this conversation as resolved.
Show resolved Hide resolved
}

function createMethods(model, parentView) {
Expand Down
94 changes: 94 additions & 0 deletions tests/ui/test_watchers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import pytest
import sys
from playwright.sync_api import Page
from traitlets import Callable, Int, Unicode, default
from IPython.display import display

if sys.version_info < (3, 7):
pytest.skip("requires python3.7 or higher", allow_module_level=True)

import ipyvue as vue


class WatcherTemplateTraitlet(vue.VueTemplate):
number = Int(0).tag(sync=True)
callback = Callable()
text = Unicode("Click Me ").tag(sync=True)

@default("template")
def _default_vue_template(self):
return """
<template>
<div @click="number += 1">{{text + number}}</div>
</template>
<script>
export default {
watch: {
number: function(value) {
callback();
}
}
}
</script>
"""

def vue_callback(self):
self.callback()


# We test that the watcher is activated when a var from python is changed
def test_watcher_traitlet(solara_test, page_session: Page):
def callback():
widget.text = "Clicked "

widget = WatcherTemplateTraitlet(callback=callback)

display(widget)

widget = page_session.locator("text=Click Me 0")
widget.click()
widget = page_session.locator("text=Clicked 1")


class WatcherTemplateVue(vue.VueTemplate):
callback = Callable()
text = Unicode("Click Me ").tag(sync=True)

@default("template")
def _default_vue_template(self):
return """
<template>
<div @click="number += 1">{{text + number}}</div>
</template>
<script>
export default {
watch: {
number: function(value) {
callback();
}
},
data(){
return {
number: 0
}
}
}
</script>
"""

def vue_callback(self):
self.callback()


# We test that watch works for a purely Vue variable
def test_watcher_vue(solara_test, page_session: Page):
def callback():
widget.text = "Clicked "

widget = WatcherTemplateVue(callback=callback)

display(widget)

widget = page_session.locator("text=Click Me 0")
widget.click()
widget = page_session.locator("text=Clicked 1")
Loading