Skip to content

Commit 70eea24

Browse files
ngokevindmarcos
authored andcommitted
have setAttribute wait for existing DOM data to init component (#2727)
1 parent 5038dd0 commit 70eea24

File tree

2 files changed

+73
-17
lines changed

2 files changed

+73
-17
lines changed

‎src/core/a-entity.js‎

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -510,14 +510,15 @@ var proto = Object.create(ANode.prototype, {
510510
* When initializing, we set the component on `this.components`.
511511
*
512512
* @param {string} attr - Component name.
513-
* @param {object} attrValue - The value of the DOM attribute.
514-
* @param {bollean} clobber - if the new attrValue will ccompletely replace the previous properties
513+
* @param {object} attrValue - Value of the DOM attribute.
514+
* @param {boolean} clobber - If new attrValue completely replaces previous properties.
515515
*/
516516
updateComponent: {
517517
value: function (attr, attrValue, clobber) {
518518
var component = this.components[attr];
519519
var isDefault = attr in this.defaultComponents;
520520
if (component) {
521+
// Remove component.
521522
if (attrValue === null && !isDefault) {
522523
this.removeComponent(attr);
523524
return;
@@ -526,6 +527,7 @@ var proto = Object.create(ANode.prototype, {
526527
component.updateProperties(attrValue, clobber);
527528
return;
528529
}
530+
529531
// Component not yet initialized. Initialize component.
530532
this.initComponent(attr, attrValue, false);
531533
}
@@ -686,28 +688,37 @@ var proto = Object.create(ANode.prototype, {
686688
var arg1Type = typeof arg1;
687689
var clobber;
688690
var componentName;
691+
var delimiterIndex;
689692
var isDebugMode;
690693

691-
var pos = attrName.indexOf(MULTIPLE_COMPONENT_DELIMITER);
692-
componentName = pos > 0 ? attrName.substring(0, pos) : attrName;
693-
694-
// Determine which type of setAttribute to call based on the types of the arguments.
695-
if (COMPONENTS[componentName]) {
696-
if (arg1Type === 'string' && typeof arg2 !== 'undefined') {
697-
singlePropertyUpdate(this, attrName, arg1, arg2);
698-
} else {
699-
clobber = arg1Type !== 'object' || (arg1Type === 'object' && arg2 === true);
700-
this.updateComponent(attrName, arg1, clobber);
701-
}
694+
delimiterIndex = attrName.indexOf(MULTIPLE_COMPONENT_DELIMITER);
695+
componentName = delimiterIndex > 0 ? attrName.substring(0, delimiterIndex) : attrName;
702696

703-
// In debug mode, write component data up to the DOM.
704-
isDebugMode = this.sceneEl && this.sceneEl.getAttribute('debug');
705-
if (isDebugMode) { this.components[attrName].flushToDOM(); }
697+
// Not a component.
698+
if (!COMPONENTS[componentName]) {
699+
normalSetAttribute(this, attrName, arg1);
706700
return;
701+
}
702+
703+
// Initialize component first if not yet initialized.
704+
if (!this.components[attrName] && this.hasAttribute(attrName)) {
705+
this.updateComponent(attrName,
706+
HTMLElement.prototype.getAttribute.call(this, attrName));
707+
}
708+
709+
// Determine which type of setAttribute to call based on the types of the arguments.
710+
if (arg1Type === 'string' && typeof arg2 !== 'undefined') {
711+
singlePropertyUpdate(this, attrName, arg1, arg2);
707712
} else {
708-
normalSetAttribute(this, attrName, arg1);
713+
// Object update.
714+
clobber = arg1Type !== 'object' || (arg1Type === 'object' && arg2 === true);
715+
this.updateComponent(attrName, arg1, clobber);
709716
}
710717

718+
// In debug mode, write component data up to the DOM.
719+
isDebugMode = this.sceneEl && this.sceneEl.getAttribute('debug');
720+
if (isDebugMode) { this.components[attrName].flushToDOM(); }
721+
711722
/**
712723
* Just update one of the component properties.
713724
* >> setAttribute('foo', 'bar', 'baz')

‎tests/core/a-entity.test.js‎

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,6 +1048,51 @@ suite('a-entity', function () {
10481048
assert.ok(el.components.sound__1 instanceof components.sound.Component);
10491049
assert.ok(el.components.sound__2 instanceof components.sound.Component);
10501050
});
1051+
1052+
test('waits for DOM data to init before setAttribute data', function (done) {
1053+
// Test component.
1054+
AFRAME.registerComponent('test', {
1055+
schema: {
1056+
foo: {default: 5},
1057+
bar: {default: 'red'},
1058+
qux: {default: true}
1059+
},
1060+
1061+
init: function () {
1062+
var data = this.data;
1063+
assert.equal(data.foo, 10);
1064+
assert.equal(data.bar, 'red');
1065+
assert.equal(data.qux, true);
1066+
},
1067+
1068+
update: function (oldData) {
1069+
var data = this.data;
1070+
if (Object.keys(oldData).length) {
1071+
// Second update via setAttribute.
1072+
assert.equal(data.foo, 10);
1073+
assert.equal(data.bar, 'orange');
1074+
assert.equal(data.qux, true);
1075+
delete AFRAME.components['test-setter'];
1076+
done();
1077+
} else {
1078+
// First update via initialization.
1079+
assert.equal(data.foo, 10);
1080+
assert.equal(data.bar, 'red');
1081+
assert.equal(data.qux, true);
1082+
}
1083+
}
1084+
});
1085+
1086+
// Component that will do the setAttribute, without dependency.
1087+
AFRAME.registerComponent('test-setter', {
1088+
init: function () {
1089+
this.el.setAttribute('test', {bar: 'orange'});
1090+
}
1091+
});
1092+
1093+
// Create the entity.
1094+
this.el.innerHTML = '<a-entity test-setter test="foo: 10">';
1095+
});
10511096
});
10521097

10531098
suite('removeComponent', function () {

0 commit comments

Comments
 (0)