ipyvuetify icon indicating copy to clipboard operation
ipyvuetify copied to clipboard

document an example of component composition

Open luk-f-a opened this issue 4 years ago • 6 comments

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

luk-f-a avatar Oct 09 '21 16:10 luk-f-a

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.

mariobuikhuizen avatar Oct 21 '21 12:10 mariobuikhuizen

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?

luk-f-a avatar Oct 21 '21 15:10 luk-f-a

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)

mariobuikhuizen avatar Oct 25 '21 11:10 mariobuikhuizen

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).

luk-f-a avatar Nov 01 '21 07:11 luk-f-a

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?

maartenbreddels avatar Nov 01 '21 09:11 maartenbreddels

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

mariobuikhuizen avatar Nov 01 '21 10:11 mariobuikhuizen