I'm trying to create a custom input system for Editor X because we can't use inputs like slider, rich text box, address input, ratings and pagination and some others also not available on classic editor like data list.
I want to create a dynamic custom element which will generate a input with fully customizable options. And functionality will be like wix.
Example from Velo: $w('#myDropdown').options = options;
Example from my system: myInput.options = options;
So I have created a test version to test it with dropdown input which is <select> in html anyway that's not important.
I also created a object oriented system in JS to use all these things like in Velo BUT BUT BUT to use this object functions I need to use the HTML Element inside of my custom element. There is no problem with Native JS (I mean when u code it outside of Wix) but in Wix I can't pass the HTML Element to the class as a parameter in any way.
What I have tried already?
1. I have tried to pass the needed element (dropdown element) inside custom event:
let element = this.shadowRoot.getElementById(inputId);
this.dispatchEvent(new CustomEvent('load', {
detail: element
}))
But I'm getting this error: (I have searched for this error and it's probably not doable with Wix)
2. I have tried to get the element from iFrame using document.getElementById and pass the element to the postMessage parameter when I send message to the iFrame.
<script type="text/javascript">
window.onmessage = (event) => {
let element = document.getElementById('customElement');
window.parent.postMessage("Returned", element);
};
</script>
In this try no errors but I don't get any response also. So not worked. When I console log the element inside iFrame script what I see is it can't find the element it returns null (in this example I'm not trying to get dropdown element I was trying to get custom element itself because elements inside shadowRoot is not accessible)
3. I have tried to copy paste my object (at least I have tried :D)
let element = this.shadowRoot.getElementById(inputId);
const dropdown = new Input(element);
this.dispatchEvent(new CustomEvent('load', {
detail: dropdown
}))
Same logic with different element this time I tried to get object. But not worked same error:
What else I can try or do?
How can I achieve this with Wix is there any way to do this? All I want to do is use the element for my object here is the object code:
I need the html input element to get this work.
export function Input(element) {
this.element = element;
Object.defineProperty(this, 'value', {
get: function () {
return this.element.value;
},
set: function (value) {
if (value === 0) {
new Error('You cant set placeholder as a value! index 0 is placeholder')
}
this.element.value = value;
}
});
Object.defineProperty(this, 'selectedIndex', {
get: function () {
return this.element.selectedIndex;
},
set: function (value) {
if (value === 0) {
throw new Error('You can set placeholder as a value! index 0 is placeholder')
} else {
this.element.options.selectedIndex = value;
}
}
});
Object.defineProperty(this, 'required', {
get: function () {
if (this.element.required) {
return this.element.required;
} else {
return false;
}
},
set: function (value) {
if (typeof value != 'boolean') {
throw new Error(`Value must be boolean!`)
}
return this.element.required = value;
}
});
Object.defineProperty(this, 'enabled', {
get: function () {
if (this.element.disabled) {
return false;
} else {
return true;
}
}
});
Object.defineProperty(this, 'placeholder', {
get: function () {
return this.element.options[0].label;
},
set: function (value) {
this.element.options[0].label = value;
}
});
Object.defineProperty(this, 'options', {
get: function () {
return Array.apply(null, this.element.options).map((option, index) => {
if (index != 0) {
return {
label: option.label,
value: option.value
}
}
}).filter((element) => {
return element !== undefined;
})
},
set: async function (value) {
if (typeof value != 'object' || value.length <= 0) {
throw new Error(`It's not an array!`);
} else {
let errorCollector = 0;
value.forEach((item) => {
if (item.label) {
//
} else {
errorCollector++
}
if (item.value) {
//
} else {
errorCollector++
}
})
if (errorCollector > 0) {
throw new Error(`You must include label and value in every object! You had problems in ${parseInt(errorCollector / 2 + 0.5)} of your objects!`)
} else {
//remove all options
const optionsNode = element.shadowRoot.querySelectorAll('#testInput option');
optionsNode.forEach((option, index) => {
if (option.value) {
option.remove()
}
});
//add new options
value.forEach((option) => {
//@ts-ignore
this.element.add(new Option(option.label, option.value));
})
}
}
}
});
this.disable = function () {
this.element.setAttribute("disabled", "disabled")
}
this.enable = function () {
this.element.removeAttribute("disabled")
}
}
Thanks!