ractivejs / ractive

Next-generation DOM manipulation
http://ractive.js.org
MIT License
5.94k stars 396 forks source link

How to declare additional attribute for a partial? #3419

Open ceremcem opened 1 year ago

ceremcem commented 1 year ago

Is there a known way to declare additional attributes for a partial? For example:

{{#partial mybutton}}
  <mycomponent foo="{{value}}" bar="{{size}}"  color="green" hello="there" /> 
  <!-- mycomponent also supports width= attribute -->
{{/partial}}

{{#with myvar1}}
  {{> mybutton}}
{{/with}}

{{#with myvar2}}
  {{> mybutton width="300"}} <- this syntax would be pretty handy
{{/with}}

I simply want to use mycomponent with some default configuration and then I want to extend it with a new attribute only for the next instance.

marcalexiei commented 1 year ago

You can explicit provide context to the partial instead of wrapping it in a with:

{{>mybutton myvar1}}

and after you can use object spread to pass additional attributes:

{{>mybutton { ...myvar2, width: 300 } }}

I made a working example on Ractive playground.

Adding code below for reference:

const App = Ractive.extend({
    template: `
  <h1>Hello</h1>

  {{#partial mybutton}}
    Partial context:
    <pre>{{JSON.stringify(.)}}</pre>

    <div>size: {{.size}}</div>
    <div>value: {{.value}}</div>
    <div>width: {{.width || 'defaultWidthValue'}}</div>
  {{/partial}}

  {{>mybutton myvar1}}

  <hr>

  {{>mybutton { ...myvar2, width: 300 } }}

  `,
    css: `h1 { color: #00818a; }`,
    cssId: 'app',
    data: () => ({
        myvar1: {
            size: 10,
            value: 't'
        },
        myvar2: {
            size: 15,
            value: 't2'
        },
    }),
});

const app = window.app = new App({
    target: 'body'
});
ceremcem commented 1 year ago

@marcalexiei Please show me how you could set the width attribute in this example.

Please do not change this part:

  {{#partial mybutton}}
    <mycomponent size="{{size}}" value="{{value}}"/> <!-- do not add `width="{{width}}"` attribute here -->
  {{/partial}}
marcalexiei commented 1 year ago

mycomponent declares width: null inside its data, so there is no way that Ractive reads ancestors width properties and overrides mycomponent width default value without explicating a value when creating the component instance.


To made your example working you have to set mycomponent isolated flag to false and remove width: null declarartion as seen in this example

Ractive.components["mycomponent"] = Ractive.extend({
  isolated: false,
  template: `
    mycomponent context:
    <pre>{{JSON.stringify(.)}}</pre>

    <div>size: {{size}}</div>
    <div>value: {{value}}</div>
    <div>width: {{width}}</div>
    `, 
  data: () => {
    return {
      size: 5, 
      value: 3, 
    }
  }
});

I don't like this approach because when debugging it might be not straightforward understand where width value arrives.

ceremcem commented 1 year ago

I don't like this approach because when debugging it might be not straightforward understand where width value arrives.

Exactly. I may simply prefer adding width="{{width}}" into the partial declaration in order to be able to easily reason about a problem when I need to.