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

document an example of component composition #185

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

luk-f-a
Copy link

@luk-f-a luk-f-a commented Oct 9, 2021

Extending the template documentation to show how to compose components into each other, when all of them are created with ipyvuetify templates.

@mariobuikhuizen
Copy link
Collaborator

Thanks for your contribution. The chapter above (Embed ipywidgets) actually describes the recommended way of embedding/composing widgets. This works for all ipywidgets including ipyvuetify template widgets and is more flexible.

The feature you describe is the older way of doing this (which we want to deprecate). Maybe using MyComponent as name in the previous chapter is a bit confusing, since it's still an ipywidget.

@luk-f-a
Copy link
Author

luk-f-a commented Oct 21, 2021

thanks for the explanation, and warning for deprecation (I just built a lot of components using that approach). Does the widget approach allow for creating custom props? I was able to work with custom props with the component approach but I couldn't figure out how to do it with the widget approach.
Is there any way to work with custom events?

@mariobuikhuizen
Copy link
Collaborator

Ah, yes, you can also use a class instead of an instance. In that case components should still be used.
In the example this would then be:

'fruit-selector': FruitSelector

instead of:

python
'fruit-selector': FruitSelector()

And I think it would then be good to show props being set in the example.
(For reference: https://github.com/mariobuikhuizen/ipyvue/blob/master/class_components.ipynb)

It's also possible set full vue components in components (with which you can also use props), but for that it is better to use vue.register_component_from_string and vue.register_component_from_file.
(For reference: https://github.com/mariobuikhuizen/ipyvue/blob/master/examples/fullVueComponent.ipynb)

@luk-f-a
Copy link
Author

luk-f-a commented Nov 1, 2021

are you saying that those use cases (custom props and events) will remain possible only via components and won't be deprecated? Is it then worth documenting them here? ie, changing the PR to show an example of custom props and events? Maybe also document vue.register_component_from_string and vue.register_component_from_file?
I didn't know about these two functions, and they look very useful to avoid the overhead of a python class, for some cases.

On a related topic, any recommendations about how to manage state? props can flow from parent to child, but not the other way around. I've been using ipywidgets.link and dlink but the results have been unstable. Everyone now and then the link fails, and the GUI becomes corrupted (most of the times unusable after a JS error visible in the console).

@maartenbreddels
Copy link
Collaborator

Everyone now and then the link fails, and the GUI becomes corrupted (most of the times unusable after a JS error visible in the console).

Could you give an example of that, and possibly open a new issue for that?

@mariobuikhuizen
Copy link
Collaborator

are you saying that those use cases (custom props and events) will remain possible only via components and won't be deprecated? Is it then worth documenting them here? ie, changing the PR to show an example of custom props and events? Maybe also document vue.register_component_from_string and vue.register_component_from_file?
I didn't know about these two functions, and they look very useful to avoid the overhead of a python class, for some cases.

Yeah, that would be great.

On a related topic, any recommendations about how to manage state? props can flow from parent to child, but not the other way around. I've been using ipywidgets.link and dlink.

We depend on the way this is done in ipywidgets, so the way to "share" data between widgets is by linking them. However, traitles in ipyvuetify widgets are deep-watched on the vue side, so changes in a nested data structure are picked up. In a full vue component you could do something like this:

import ipyvuetify as v
import traitlets
import ipyvue

ipyvue.register_component_from_string("my-child", """
<template>
    <v-text-field :label="label" v-model="internalValue"></v-text-field>
</template>
<script>
module.exports = {
    props: ['label', 'value'],
    data() {
        return {
            internalValue: this.value,
        }
    },
    watch: {
        internalValue(v) {
            this.$emit('update:value', v)
        }
    }
}
</script>
""")

class Parent(v.VuetifyTemplate):
    
    @traitlets.default('template')
    def _template(self):
        return """
            <template>
                <div>
                    <div v-for="item in items">
                        <my-child :label="item.label" :value.sync="item.value"/>
                    </div>
                </div>
            </template>
        """
    items = traitlets.List().tag(sync=True) 
    
p = Parent(items=[{
    'label': 'label 1', 'value': 'x'},
    {'label': 'label 2', 'value': 'y'}
])
p.observe(lambda change: print(change['new']), names='items')
p

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants