I'm following the step-by-step introduction from A-FRAME framework and currently learning how to write a component and get issue updating a component. I've already looked at that thread to make sure i was doing it right.
Here's the case. A box component is created. Here's a draft to illustrate that. When no oldData means we are in init phase. if component props changes (oldData not empty), component props are updated with new values. Init and update functions both fire once.
The thing is that when setting new values to component attributes,
el.setAttribute("box", { width: 2, height: 2, depth: 2, color: "#33FF60" });
el.setAttribute("box", { width: 2, height: 4, depth: 3, color: "#F533FF" });
the box is rendered accordingly, but the logs i've putted as warning in the update function, to inform about the update phases, the conditions, does not fire, like if each time setAttribute() is used, i stay in the init phase, not going through the update phase, with "no oldData - init phase" logged as result (oldData's empty object).
if (Object.keys(oldData).length === 0) {
console.log("no oldData - init phase");
return;
}
Also, i've placed a listener into the init phase to get details when component changes but it never fires when component "update".
el.addEventListener("componentChanged", function (e) {
console.log(e);
console.log("listener init");
if (e.detail.name === "width") {
console.log(e.detail.newData);
}
});
Asking the community in the hope to get some feedbacks from other viewpoints. There's probably something i don't see here.
PS: component written in separate .js file, called into index.html head with defer attribute for JS to be executed after page parsed.
With two calls like this:
el.setAttribute("box", { width: 2, height: 2, depth: 2, color: "#33FF60" });
el.setAttribute("box", { width: 2, height: 4, depth: 3, color: "#F533FF" });
the second setAttribute
won't wait for the first one. They both happen within the same renderloop with only the last one being registered.
If you wait a bit:
let el = document.querySelector("a-entity");
setTimeout(() => {
el.setAttribute("box", { color: "#FF00AA" });
}, 1500)
setTimeout(() => {
el.setAttribute("box", { color: "#AA00FF" });
}, 3000)
<script src="https://aframe.io/releases/1.4.0/aframe.min.js"></script>
<script>
console.log("🔥");
AFRAME.registerComponent("box", {
schema: {
color: { type: "color", default: "#DAF7A6" },
},
init: function() {
console.log("init 🔵");
var data = this.data;
var el = this.el;
// create mesh
this.geometry = new THREE.BoxGeometry(data.width, data.height, data.depth);
this.material = new THREE.MeshStandardMaterial({ color: data.color });
this.mesh = new THREE.Mesh(this.geometry, this.material);
// set mesh on entity
el.setObject3D("mesh", this.mesh);
},
update: function(oldData) {
console.log("update 🟢");
console.log("current color:", this.data.color)
console.log("old color:", oldData.color)
var data = this.data;
var el = this.el;
// if oldData empty, then means we're in init process
if (Object.keys(oldData).length === 0) {
console.log("no oldData - init phase");
return;
}
// material related props changed. update material
if (data.color !== oldData.color) {
console.log("material changed");
el.getObject3D("mesh").material.color = new THREE.Color(data.color);
}
}
});
</script>
<a-scene>
<a-entity box position="0 2 -5" scale="10 10 0.5"></a-entity>
</a-scene>
You'll get three sets of logs:
setAttribute
changing the random color to #33FF60setAttribute
changing #33FF60 to #F533FFAlso You should register your component before using it in the scene (here it doesn't matter so much since you add it with setAttribute
, but if it gets registered after the scene initializes, it won't work [source]
We must register components before we use them anywhere in . Meaning from an HTML file, components should come in order before