1

I've got a vue web component with a numeric prop on it, and through some testing have found that doing something like this doesn't work in setting the prop value...

<script src="https://unpkg.com/vue@2"></script>
<script src="./mycomponents.js"></script>

<my-component myProp="40"></my-component>

But this will...

<script src="https://unpkg.com/vue@2"></script>
<script src="./mycomponents.js"></script>

<my-component id="mycmp"></my-component>

<script type="module">
const myComponent = document.getElementById("mycmp");
myComponent.myProp = 40;
</script>

Example component code:

<template>
    <p>{{myProp}}</p>
</template>

<script>
export default {
    name: 'MyComponent',
    props: {
        myProp: {
            type: Number,
            default: 0
        }
    }
}
</script>

I'm guessing maybe this is a timing thing, like when doing it through the html attributes the component hasn't finished being properly initialised yet? Though all the examples I saw of other people using vue web-components seemed to suggest that this should be a pretty basic use case. Hopefully it's just me doing something dumb.

Any help greatly appreciated!

5
  • 1
    HTML tag's attributes are by definition String values. Your component's prop should be defined as type: [String, Number] and then everywhere you access the prop - you should coerce it to Number. Commented May 6, 2022 at 12:28
  • I'm not that familiar with Vue.js, but could you try my-prop="40" instead of myProp="40". It might behave the same as data-* attributes, which are expected to be data-my-attr in HTML, but are accessed via elm.dataset.myAttr in JavaScript. Commented May 6, 2022 at 13:26
  • @3limin4t0r thank you! That's what it was. I'm so used to setting props on a component when already in the vue context, aka parent component setting child component prop. In that case the property name is fine to use within html as is. It looks like the same is not true when accessed as a web component from regular html. Thanks for your help Commented May 6, 2022 at 19:17
  • @IVOGELOV looks like vue is actually handling coercing the prop value to a number fine, I just didn't realise I needed to use kebab-case for the property name. Thanks though, I didn't realise we could allow a vue prop to accept an array of types. Commented May 6, 2022 at 19:19
  • The HTML that you refer to when using camelCase attribute names in your Vue components is pre-processed by Vue-template-compiler which forgives you. However, browsers convert to lowercase all attribute names (and do not forgive) - and do not convert from camelCase to kebab-case. Commented May 7, 2022 at 9:18

2 Answers 2

2

HTML attributes often do not match 1 to 1 with JavaScript properties. In this scenario the HTML attribute to Vue.js property translation is similar to that of data-* attributes.

Name conversion

dash-style to camelCase conversion

A custom data attribute name is transformed to a key for the DOMStringMap entry by the following:

  1. Lowercase all ASCII capital letters (A to Z);
  2. Remove the prefix data- (including the dash);
  3. For any dash (U+002D) followed by an ASCII lowercase letter a to z, remove the dash and uppercase the letter;
  4. Other characters (including other dashes) are left unchanged.

camelCase to dash-style conversion

The opposite transformation, which maps a key to an attribute name, uses the following:

  1. Restriction: Before transformation, a dash must not be immediately followed by an ASCII lowercase letter a to z;
  2. Add the data- prefix;
  3. Add a dash before any ASCII uppercase letter A to Z, then lowercase the letter;
  4. Other characters are left unchanged.

For example, a data-abc-def attribute corresponds to dataset.abcDef.

Applying this to your scenario we can skip step 2 (the data- part) and write the attribute like so:

<my-component my-prop="40"></my-component>
Sign up to request clarification or add additional context in comments.

Comments

0

You can try to setAttribute for prop converting it to string:

<my-component></my-component>

<script type="module">
  const myComp= document.querySelector("my-component");
  myComp.setAttribute("my-prop", JSON.stringify(40));
</script>

then in your component receive prop as string and convert it to number (or if you need object JSON.parse it):

<template>
  <p>{{ myPropNr }}</p>
</template>

props: {
  myProp: {
     type: String,
     default: 0
  }
},
computed: {
  myPropNr() {
    return Number(this.myProp)
  }
}

3 Comments

If I used javascript to fetch the element and then set the prop, that was already working in the example I gave with my question. I was more trying to find out why setting the property through html attribute wasn't working.
@JCoyle hey mate, I think because you can only pass string that way, so you can use JSON.stringify and JSON.parse to get something other then string
I did wonder if it would do that, so did add some guards in my code against it, but it looks like if you set the type of the property to number, then vue will actually automatically do the conversions for you. It turned out the problem was just I needed to use kebab-case for the property name. So doing something like <my-component my-prop="40"></my-component> seems to actually be working perfectly fine now

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.