vuejs/vue-web-component-wrapper

Passing properties other than strings don't seem to work??

mheere2 opened this issue · 18 comments

I am trying to pass a list of items to a web-component but internally it seems to have converted it to a String... ??
So for example in the code below I wish to pass two properties: a 'msg' (String) and an 'items' (Array).

// wrap my VueWebComponent into a web-component
const CustomElement = wrap(Vue, VueWebComponent);

// and register this with the window...
window.customElements.define('my-custom-element', CustomElement);

// get an element from the index.html that I wish to inject the following Vue instance into
let elName = document.getElementsByClassName("v1")[0];

let vm = new Vue({
	el: elName,
	template: `
	<div>
		<my-custom-element :msg="this.d1" :items="this.items" @pause="paused"></my-custom-element>
	</div>
	`,
	data() {
		return {
			d1: "Hello",
			items: [
				{ name: 'Marcel', age: 51 },
				{ name: 'Deniz', age: 46 }
			]
		};
	},
	methods: {
		paused() {
			this.d1 = "Paused";
		}
	}
});

Unfortunately when I try to access the props inside the VueWebComponent code I find:
msg = "Hello"
items = "[object Object],[object Object]"

Any help much appreciated!

This is the code for the VueWebComponent.vue

<template>
  <div class="mywc">
    <h4>My Vue Web Component</h4>
    <button @click="doPause">Pause</button>
    <div>{{ msg }} {{ counter }}</div>
  </div>
</template>

<script>
export default {
  props: ["msg", "items"],
  data() {
    return {
      counter: 0,
      name: "marcel"
    };
  },
  methods: {
    doPause() {
      this.counter++;

      // this works beautifully with Vue but with React we have to attach
      // custom listeners....
      this.$emit("pause", { name: this.name });
     
    }
  }
};
</script>

Hi, yes I did try that but also didn't work. How would I go about setting this myself using JS?

I didn't try it with this library but in Vue Custom Element You do it like that - https://karol-f.github.io/vue-custom-element/#/demos/binding (Plain JavaScript binding usage)

Thanks - yes I have seen that lib as well - it's a different one than this one - it's yours I believe? :)
So should I simply not using this one? With this one we have Evan You @yyx990803 contributing..
In the source code there is a function syncAttribute that tries to obtain the value through this statement:
const value = el.hasAttribute(key) ? el.getAttribute(key) : undefined;
It is at this point it is already converted to '[object Object],[object Object]'
But I will give yours a go now...

Use this lib as long as You can. It's more strict and opinionated and IMHO switch only if You feel you need something more complex.

Maybe just try to avoid using object/arrays as custom element attributes? It will solve your problems .

  • I don't consider passing in an Array as complex though? I am trying to convert my Vue Dropdown control into a web component and it requires passing in an Array of dropdown items... so it's pretty essential..

@karol-f Hi, sorry I must be doing something daft - it also isn't working using your 'vue-custom-element' control
This is what I have now:

main.js

import Vue from 'vue/dist/vue';
import VueWebComponent from './components/VueWebComponent';
import App from './components/App';

import vueCustomElement from 'vue-custom-element';
Vue.use(vueCustomElement);

Vue.customElement('my-custom-element', VueWebComponent);

// get an element from the index.html that I wish to inject the following Vue instance into
let elName = document.getElementsByClassName("v1")[0];

// start a standard Vue App component 
new Vue({
	el: elName,
	render: h => h(App)
});

App.vue

<template>
  <div>
    <my-custom-element :msg="d1" :items="items" @pause="paused"></my-custom-element>
  </div>
</template>

<script>
export default {
  data() {
    return {
      d1: "Hello",
      items: [{ name: "Marcel", age: 51 }, { name: "Deniz", age: 46 }]
    };
  },
  methods: {
    paused() {
      this.d1 = "Paused";
    }
  }
};
</script>

VueWebComponent.vue

<template>
  <div class="mywc">
    <h4>My Vue Web Component</h4>
    <div>msg = {{ msg }}</div>
    <div>items = {{ items }}</div>
  </div>
</template>

<script>
export default {
  props: {
    msg: String,
    items: Array
  },
  methods: {
    doPause() {
      console.log("doPause - emitting 'pause'", this.items);
      this.$emit("pause", { name: this.name });
    }
  }
};
</script>

And this is what is shows:
msg = Hello
items = [object Object],[object Object]

Note - since I am now using props validation I also get an error in the console..
[Vue warn]: Invalid prop: type check failed for prop "items". Expected Array, got String with value "[object Object],[object Object]".

Can you please just prepare Codesandbox.io/vue and I will fix it?

@karol-f
Thanks - here is the codesandbox sample:
https://codesandbox.io/s/karol-f-query-124ch

Thanks for your help @karol-f - it certainly works for your library but unfortunately still doesn't seem to work for this lib (vue-web-component-wrapper) -
I'll put together another codesandbox..

Here is the other codesandbox -
https://codesandbox.io/s/web-component-wrapper-query-iix8s
actually, I am also getting an error message regarding "Unknown custom element: ...." that I am not getting in my local project code...
Regardless, the hint provided by karol-f above doesn't seem to work for this lib?

@mheere-iress about error in console - read "Caveats" - https://github.com/karol-f/vue-custom-element/blob/master/README.md#caveats

I read that - but the problem lies deeper I believe. The codesandbox is complaining about:
Unknown custom element: - did you register the component correctly ...blah blah
This is an error I am not getting in my local vs-code environment
Thing is - besides that - that your suggestion does work in your lib but not in this one...?

@karol-f Hi!, if you have one more minute I would really appreciate it if you could have a quick look at my codesandbox samples
The first one using your lib works well (both local dev code and the sandbox) but switching to the 'official' lib I have:
a) it still doesn't work in my local test code and
b) the sandbox example doesn't seem to play ball! (it complains about the custom element not being registered... (I would be quite happy for just (a) to be resolved! :) )
https://codesandbox.io/s/karol-f-query-124ch
https://codesandbox.io/s/web-component-wrapper-query-iix8s
Thanks!

i'm also experiencing this issue, I think it's pretty fundamental that passing complex types as properties works. Any ideas on when this will be fixed?

I also have the same issue. If I pass object/array to any prop:Object, it seems it's always turned into a string...

It works if I use these components in an Angular app though (code below) 🤔
<my-dropdown [options]="['Preselected Angular option','Angular option 2']"></my-dropdown>

so yeah...
I ended up with

    <template v-for="(widget, index) in widgets">
        <component :key="`component-${index}`" :is="widget.component" :payload="pack(widget.payload)" />
    </template>
    ---
    methods: {
        pack(payload) {
            return JSON.stringify(payload)
        }
    }
<!-- npx vue-cli-service build --target wc --name my-custom-element ./src/components/VueWebComponent.vue -->  
<template>
    <div style="color: grey">
        <h1>My Vue Web Component</h1>
        <div>{{ data }}</div>
    </div>
</template>
<script>
    export default {
        props: {
            payload: String
        },
        data() {
            return {
                data: JSON.parse(this.payload)
            }
        },
    }
</script>

Unknown custom element: - did you register the component correctly ...blah blah

Vue.config.ignoredElements = [
  'my-custom-element',
  /^my-/
]

So yeah... You still need to tell Vue or the Lint what elements you are going to use...
Very annoying if/when you want to make dynamic stuff... ie: have a DB decide how your page is going to look.
Solution seems to be to use a wildcard in your ignoredElements.
In my case I'm going to prefix all my widgets with the name of the app.

I built a Web components wrapper of Apache ECharts: ECharts-JSX, which is based on Proxy object to transform uncountable official options to Custom Element properties, Vue uses setAttribute for { } or [ ] making charts crashed: https://idea2app.github.io/Vue-MobX-Prime-ts/#/chart

But Preact, WebCell (my Web components framework) & some other view engines assign Object values to properties directly instead of setting attributes: