justin-schroeder / arrow-js

Reactivity without the framework

Home Page:https://arrow-js.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

fails to render with multiple expressions in an attribute

jukart opened this issue · comments

Here is a test which shows the problem:

import { html } from '..'

describe('extressions in attribute', () => {
  it('should render correctly with a single expression in an attribute', () => {
    const parent = document.createElement('div')
    html`<div class="${() => 'class'}" @click="${() => 'click'}">
      ${() => 'body'}
    </div>`(parent)
    expect(parent.innerHTML).toStrictEqual(`<div class="class">
      body
    </div>`)
  })

  it('should render correctly with multiple expressions in an attribute', () => {
    const parent = document.createElement('div')
    html`<div class="${() => 'class1'} ${() => 'class2'}">
      ${() => 'body'}
    </div>`(parent)
    expect(parent.innerHTML).toStrictEqual(
      `<div class="<!--➳❍--> <!--➳❍-->">
      class1
    </div>`
    )
  })
})

This is intentional. You can only provide 1 expression for your attribute. This allows arrow to be small, fast and efficient, and still gives you plenty of ability to do what you’re asking.

html`<div class="${() => 'class1'} ${() => 'class2'}"></div>

should be written:

html`<div class="${() => `${d.class1} ${d.class2}`"></div>

Ok thanks for the quick reply. I was bringing this up because it worked before.
It broke some things in my app :)
But that`s why it's alpha :)

@justin-schroeder
Another note:
This also fails:
width="${width}px"
It has to be this:
width="${`${width}px`}"

I'd say this should be mentioned somewhere in the documentation because strange things are happening if you do it wrong.

Sure, we can mention this in the docs! FWIW, this is how most many frameworks work. If you bind to an attribute you need to provide the full value of that attribute:

React:

<div data-foo={width + 'px}></div> 

Vue:

<div :data-foo="`${width}px`"></div>

Fair enough, it just feels a bit different here because it looks like a "normal" template literal.

One more thing I am just struggling with:
I have a checkbox input with checked="${false}" which is not removing the attribute.
With checked="${() => false}" it works.

Btw.
I love this library. It shows how bloated the existing Libraries are especially React (I don't know much about Vue).

Is there another place to discuss such things or is this Ok?

I think making it more clear in the docs, and eventually via more dev toolings will be helpful.

As for the ${false} vs ${() = >false} — in the first example you are directly interpolating "false" into your template just like you would with a normal template literal, there is no attribute binding at all there. Only expressions with functions are actually "bound" to the attribute 👍