canjs / can-stache

Live binding handlebars templates
https://canjs.com/doc/can-stache.html
MIT License
10 stars 13 forks source link

"named partials" should accept their context values as arguments #665

Open mjstahl opened 5 years ago

mjstahl commented 5 years ago

When I read through the example below (pulled from https://canjs.com/doc/can-stache.tags.named-partial.html) the first thing that came to mind was this means two different things in the same stache file. It took a moment (more than a glance in this small example) to figure out which one does what.

  {{< addressView}}
      <address>{{this.street}}, {{this.city}}</address>
  {{/ addressView}}

  <article>
      {{addressView(this.address1)}}
      {{addressView(this.address2)}}
  </article>

So I propose a change to extend its semantics. This will make things more explicit and continue to discourage the use of stache constructs that create contexts.

  {{< addressView(address) }}
      <address>{{address.street}}, {{address.city}}</address>
  {{/ addressView}}

  <article>
      {{addressView(this.address1)}}
      {{addressView(this.address2)}}
  </article>

In order to keep this from being a breaking change, the first example would continue to work. And this and address would be equal.

phillipskevin commented 5 years ago

Can you do this using Hash Expressions?

 <article>
      {{addressView(address = this.address1)}}
      {{addressView(address = this.address2)}}
 </article>
justinbmeyer commented 5 years ago

@phillipskevin I think has expressions would still set this right? I don't think it would create a let context.

You could create a let context like:

{{ addressView( scope.addLetContext( address = this.address1 ) ) }}

I think this would keep this in {{< addressView}} what you might expect.

==================================

This is an age old problem with stache and other (non-JSX) templates ... what to do with the data argument passed to a renderer/view.

It's odd that data becomes this here:

data = {foo: "bar"};
view = stache("{{this.foo}}");
view(data);

One thing I've thought about is forcing call down folks throat:

data = {foo: "bar"};
view = stache("{{this.foo}}");
view.call(data);

If renderers expected this in stache, everything could make a lot more sense. If you want to call a partial or renderer function in stache and set this then do:

{{ addressView.call(this.address1) }}

If you want to pass an argument, do:

{{ addressView(this.address1) }}

It would be cool if somehow these arguments could be defined in stache:

{{#(address, user)}}

{{/}}

But now I've jumped the shark.