I currently have 2 components. One of them, creates a series of dodecahedrons and the other one sets them invisible. Both of them are generated at runtime.
The problem is with the invisible one. I can't get the dynamically generated children by using:
el.querySelector('*')
in the init method of the invisible component.
I have even tried:
- Listening for the "loaded" event and then registering the component.
- Using promises and listening to a loaded event.
- Using a window.setTimeout() function of 3 seconds after the component has been registered.
This is my full code, so far:
export class InvisibleComponent {
constructor() {
/**
* Sets the current element and all of its children as invisible
* by using its materials property.
*
*/
const _this = this;
AFRAME.registerComponent('invisible', {
init: function () {
_this.setTransparent(this.el);
console.log(this.el);
let children = this.el.querySelector('*');
if (!children) return;
Array.from(children).forEach(child => {
_this.setTransparent(this.el);
})
},
remove: function () {
if (!this.el) return;
_this.setOpaque(this.el);
let children = this.el.querySelector('*');
if (!children) return;
Array.from(children).forEach(child => {
_this.setOpaque(this.el);
})
}
})
}
setTransparent(el: AFrame.Entity) {
this.getMaterial(el).then((material :any) => {
this.setAttributes(el,material.opacity);
})
.catch(resolve => {
console.log("Material couldn't be gathered. Using 100% of opacity instead", resolve);
this.setAttributes(el, 1);
});
}
setAttributes(el : AFrame.Entity, opacity){
el.setAttribute('data-previous-opacity',opacity);
el.setAttribute('material', 'opacity:0; transparent: true; visible:false;');
}
/**
* This is a solution if the element which is trying to load
* hasn't been loaded yet. All elements must have a material
* in order to be inserted in a scene.
* @param el
*/
getMaterial(el: AFrame.Entity): Promise<number> {
return new Promise<number>((resolve, reject) => {
let material = el.getAttribute('material');
if (material) resolve(material);
el.sceneEl.addEventListener('loaded', function () {
let material = el.getAttribute('material');
!material ? reject(undefined) : resolve(material);
})
});
}
// If you had previous property, this will not remove them.
setOpaque(el: AFrame.Entity) {
let dataPreviousOpacity = el.getAttribute('data-previous-opacity');
if (!dataPreviousOpacity) dataPreviousOpacity = 1;
el.setAttribute('material', 'transparent', dataPreviousOpacity === 1 ? false : true);
el.setAttribute('material', 'opacity', dataPreviousOpacity);
el.setAttribute('material', 'visible', true);
}
}