mirror of
https://github.com/Polymer/polymer.git
synced 2025-02-25 18:55:30 -06:00
Merge pull request #4056 from Polymer/4044-kschaaf-late-binding
Queue accessor value on instance. Fixes #4044.
This commit is contained in:
@@ -32,12 +32,19 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
if (!nativeProperties[property]) {
|
||||
let value = model[property];
|
||||
if (value !== undefined) {
|
||||
if (!model.__dataProto) {
|
||||
model.__dataProto = {};
|
||||
} else if (!model.hasOwnProperty('__dataProto')) {
|
||||
model.__dataProto = Object.create(model.__dataProto);
|
||||
if (model.__data) {
|
||||
// Adding accessor to instance; update the property
|
||||
// It is the user's responsibility to call _flushProperties
|
||||
model._setPendingProperty(property, value);
|
||||
} else {
|
||||
// Adding accessor to proto; save proto's value for instance-time use
|
||||
if (!model.__dataProto) {
|
||||
model.__dataProto = {};
|
||||
} else if (!model.hasOwnProperty('__dataProto')) {
|
||||
model.__dataProto = Object.create(model.__dataProto);
|
||||
}
|
||||
model.__dataProto[property] = value;
|
||||
}
|
||||
model.__dataProto[property] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
'unit/templatizer.html',
|
||||
'unit/dom-repeat.html',
|
||||
'unit/dom-if.html',
|
||||
'unit/dom-bind.html',
|
||||
'unit/polymer-dom.html',
|
||||
'unit/polymer-dom-observeNodes.html',
|
||||
'unit/importHref-element.html'
|
||||
|
||||
@@ -317,7 +317,23 @@ suite('single-element binding effects', function() {
|
||||
el.title = 'a title';
|
||||
assert.isTrue(el.titleChanged.calledOnce);
|
||||
assert.equal(el.titleChanged.firstCall.args[0], 'a title');
|
||||
})
|
||||
});
|
||||
|
||||
test('property effect added at instance time', function() {
|
||||
el.earlyBoundObserver = sinon.spy();
|
||||
el.lateBoundObserver = sinon.spy();
|
||||
el.earlyBound = 'early';
|
||||
el._createObservedProperty('earlyBound', 'earlyBoundObserver');
|
||||
el._createObservedProperty('lateBound', 'lateBoundObserver');
|
||||
el._flushProperties();
|
||||
el.lateBound = 'late';
|
||||
assert.equal(el.earlyBound, 'early');
|
||||
assert.equal(el.earlyBoundObserver.callCount, 1);
|
||||
assert.equal(el.earlyBoundObserver.firstCall.args[0], 'early');
|
||||
assert.equal(el.lateBound, 'late');
|
||||
assert.equal(el.lateBoundObserver.callCount, 1);
|
||||
assert.equal(el.lateBoundObserver.firstCall.args[0], 'late');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
73
test/unit/dom-bind-elements1.html
Normal file
73
test/unit/dom-bind-elements1.html
Normal file
@@ -0,0 +1,73 @@
|
||||
<!--
|
||||
@license
|
||||
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
|
||||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||||
Code distributed by Google as part of the polymer project is also
|
||||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||||
-->
|
||||
<script>
|
||||
Polymer({
|
||||
is: 'x-basic',
|
||||
properties: {
|
||||
notifyingvalue: {
|
||||
notify: true
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<dom-module id="x-content">
|
||||
<template><div id="container"><slot id="slot"></slot></div></template>
|
||||
<script>
|
||||
Polymer({
|
||||
is: 'x-content'
|
||||
});
|
||||
</script>
|
||||
</dom-module>
|
||||
|
||||
<dom-module id="x-attach-dom-bind">
|
||||
<template><x-content id="local"></x-content></template>
|
||||
<script>
|
||||
Polymer({
|
||||
is: 'x-attach-dom-bind',
|
||||
|
||||
attached: function() {
|
||||
var domBind = document.createElement('dom-bind');
|
||||
var template = document.createElement('template');
|
||||
|
||||
domBind.appendChild(template);
|
||||
|
||||
var span = document.createElement('span');
|
||||
span.innerHTML = '{{hello}}';
|
||||
|
||||
template.content.appendChild(span);
|
||||
domBind.hello = 'hey';
|
||||
|
||||
this.$.local.appendChild(domBind);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</dom-module>
|
||||
|
||||
<dom-module id="x-compose">
|
||||
<template><x-content id="local"></x-content></template>
|
||||
<script>
|
||||
Polymer({
|
||||
is: 'x-compose'
|
||||
});
|
||||
</script>
|
||||
</dom-module>
|
||||
|
||||
<script>
|
||||
Polymer({
|
||||
is: 'x-produce-a',
|
||||
properties: {
|
||||
bindToText: {
|
||||
notify: true,
|
||||
value: 'this text is bound'
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
20
test/unit/dom-bind-elements2.html
Normal file
20
test/unit/dom-bind-elements2.html
Normal file
@@ -0,0 +1,20 @@
|
||||
<!--
|
||||
@license
|
||||
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
|
||||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||||
Code distributed by Google as part of the polymer project is also
|
||||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||||
-->
|
||||
<script>
|
||||
Polymer({
|
||||
is: 'x-needs-host',
|
||||
attached: function() {
|
||||
if (!this.__dataHost) {
|
||||
throw "No dataHost at ready time";
|
||||
}
|
||||
this.config = this.__dataHost.getAttribute('config');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
249
test/unit/dom-bind.html
Normal file
249
test/unit/dom-bind.html
Normal file
@@ -0,0 +1,249 @@
|
||||
<!doctype html>
|
||||
<!--
|
||||
@license
|
||||
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
|
||||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||||
Code distributed by Google as part of the polymer project is also
|
||||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
|
||||
<script src="../../../web-component-tester/browser.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<dom-bind id="earlyDomBind">
|
||||
<template>
|
||||
<div id="earlyBoundChild">{{value}}</div>
|
||||
</template>
|
||||
</dom-bind>
|
||||
|
||||
<script>
|
||||
/* global earlyDomBind earlyBoundChild declaredXBasic1 declaredXBasic2 declarativeDomBind boundTextDiv container needsHost*/
|
||||
earlyDomBind.value = 'hi!';
|
||||
</script>
|
||||
|
||||
<link rel="import" href="../../polymer.html">
|
||||
<link rel="import" href="dom-bind-elements1.html">
|
||||
|
||||
<dom-bind id="declarativeDomBind">
|
||||
<template>
|
||||
<x-basic id="declaredXBasic1" value="{{value}}" notifyingvalue="{{nvalue}}" on-custom="handleEvent" computed="{{compute(dep)}}"></x-basic>
|
||||
<x-basic id="declaredXBasic2" value="{{value}}" notifyingvalue="{{nvalue}}"></x-basic>
|
||||
<x-produce-a bind-to-text={{boundText}}></x-produce-a>
|
||||
<div id="boundTextDiv">{{boundText}}</div>
|
||||
</template>
|
||||
</dom-bind>
|
||||
|
||||
<div id="container">
|
||||
</div>
|
||||
|
||||
<dom-bind id="timingDomBind" config="config">
|
||||
<template>
|
||||
<x-needs-host id="needsHost"></x-needs-host>
|
||||
</template>
|
||||
</dom-bind>
|
||||
|
||||
<script>
|
||||
|
||||
suite('dom-bind touched before upgrade', function() {
|
||||
test('value binds top-down', function() {
|
||||
assert.equal(earlyBoundChild.textContent, 'hi!');
|
||||
});
|
||||
});
|
||||
|
||||
suite('declarative dom-bind', function() {
|
||||
|
||||
var domBind;
|
||||
var el1;
|
||||
var el2;
|
||||
|
||||
setup(function() {
|
||||
domBind = declarativeDomBind;
|
||||
el1 = declaredXBasic1;
|
||||
el2 = declaredXBasic2;
|
||||
});
|
||||
|
||||
test('value binds top-down', function() {
|
||||
domBind.value = 'foo';
|
||||
assert.equal(el1.value, 'foo');
|
||||
assert.equal(el2.value, 'foo');
|
||||
});
|
||||
|
||||
test('notifyingvalue binds from child to child', function() {
|
||||
el1.notifyingvalue = 'bar';
|
||||
assert.equal(domBind.nvalue, 'bar');
|
||||
assert.equal(el2.notifyingvalue, 'bar');
|
||||
});
|
||||
|
||||
test('event listener fires', function() {
|
||||
var count = 0;
|
||||
domBind.handleEvent = function() {
|
||||
count++;
|
||||
};
|
||||
el1.fire('custom');
|
||||
assert.equal(count, 1);
|
||||
});
|
||||
|
||||
test('inline function runs', function() {
|
||||
domBind.compute = function(val) {
|
||||
return val * 10;
|
||||
};
|
||||
domBind.dep = 5;
|
||||
assert.equal(el1.computed, 50);
|
||||
});
|
||||
|
||||
test('initial value notifies to dom-bind', function() {
|
||||
assert.equal(domBind.boundText, 'this text is bound');
|
||||
assert.equal(boundTextDiv.textContent, 'this text is bound');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
suite('imperative dom-bind', function() {
|
||||
var domBind;
|
||||
var el1;
|
||||
var el2;
|
||||
|
||||
setup(function() {
|
||||
domBind = document.createElement('dom-bind');
|
||||
var template = document.createElement('template');
|
||||
|
||||
domBind.appendChild(template);
|
||||
|
||||
var doc = template.content.ownerDocument;
|
||||
el1 = doc.createElement('x-basic');
|
||||
|
||||
el1.setAttribute('id', 'impEl1');
|
||||
el1.setAttribute('value', '{{value}}');
|
||||
el1.setAttribute('notifyingvalue', '{{nvalue}}');
|
||||
el1.setAttribute('on-custom', 'handleEvent');
|
||||
el1.setAttribute('computed', '{{compute(dep)}}');
|
||||
|
||||
el2 = doc.createElement('x-basic');
|
||||
el2.setAttribute('id', 'impEl2');
|
||||
el2.setAttribute('value', '{{value}}');
|
||||
el2.setAttribute('notifyingvalue', '{{nvalue}}');
|
||||
|
||||
template.content.appendChild(el1);
|
||||
template.content.appendChild(el2);
|
||||
document.body.appendChild(domBind);
|
||||
|
||||
CustomElements.takeRecords();
|
||||
|
||||
el1 = domBind.$.impEl1;
|
||||
el2 = domBind.$.impEl2;
|
||||
});
|
||||
|
||||
teardown(function() {
|
||||
if (domBind.parentElement) {
|
||||
domBind.parentElement.removeChild(domBind);
|
||||
}
|
||||
});
|
||||
|
||||
test('value binds top-down', function() {
|
||||
domBind.value = 'foo';
|
||||
assert.equal(el1.value, 'foo');
|
||||
assert.equal(el2.value, 'foo');
|
||||
});
|
||||
|
||||
test('notifyingvalue binds from child to child', function() {
|
||||
el1.notifyingvalue = 'bar';
|
||||
assert.equal(domBind.nvalue, 'bar');
|
||||
assert.equal(el2.notifyingvalue, 'bar');
|
||||
});
|
||||
|
||||
test('event listener fires', function() {
|
||||
var count = 0;
|
||||
domBind.handleEvent = function() {
|
||||
count++;
|
||||
};
|
||||
el1.fire('custom');
|
||||
assert.equal(count, 1);
|
||||
});
|
||||
|
||||
test('inline function runs', function() {
|
||||
domBind.compute = function(val) {
|
||||
return val * 10;
|
||||
};
|
||||
domBind.dep = 5;
|
||||
assert.equal(el1.computed, 50);
|
||||
});
|
||||
|
||||
test('move dom-bind', function( ) {
|
||||
container.appendChild(domBind);
|
||||
CustomElements.takeRecords();
|
||||
|
||||
assert.equal(container.firstElementChild, el1);
|
||||
assert.equal(container.firstElementChild.nextElementSibling, el2);
|
||||
});
|
||||
|
||||
test('remove dom-bind', function() {
|
||||
assert(document.body.contains(el1));
|
||||
assert(document.body.contains(el2));
|
||||
|
||||
domBind.parentElement.removeChild(domBind);
|
||||
CustomElements.takeRecords();
|
||||
|
||||
assert(!document.body.contains(el1));
|
||||
assert(!document.body.contains(el2));
|
||||
});
|
||||
|
||||
test('dom-bind distributed when inserted in element attached',
|
||||
function() {
|
||||
var el = document.createElement('x-attach-dom-bind');
|
||||
document.body.appendChild(el);
|
||||
|
||||
// Flush CE & distribution
|
||||
Polymer.dom.flush();
|
||||
|
||||
assert.equal(el.$.local.$.slot.assignedNodes()[0].textContent, 'hey',
|
||||
'dom-bind did not distribute');
|
||||
document.body.removeChild(el);
|
||||
});
|
||||
|
||||
test('dom-bind distributed when inserted dynamically', function() {
|
||||
var composeEl = document.createElement('x-compose');
|
||||
document.body.appendChild(composeEl);
|
||||
CustomElements.takeRecords();
|
||||
|
||||
var dynamicDomBind = document.createElement('dom-bind');
|
||||
var dynamicTemplate = document.createElement('template');
|
||||
|
||||
dynamicDomBind.appendChild(dynamicTemplate);
|
||||
|
||||
var span = document.createElement('span');
|
||||
span.innerHTML = '{{hello}}';
|
||||
|
||||
dynamicTemplate.content.appendChild(span);
|
||||
dynamicDomBind.hello = 'hey';
|
||||
composeEl.$.local.appendChild(dynamicDomBind);
|
||||
|
||||
// Flush CE & distribution
|
||||
Polymer.dom.flush();
|
||||
|
||||
assert.equal(composeEl.$.local.$.slot.assignedNodes()[0].textContent, 'hey',
|
||||
'dom-bind did not distribute');
|
||||
document.body.removeChild(composeEl);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
suite('timing', function() {
|
||||
|
||||
test('late-loaded import should block stamping', function() {
|
||||
assert.equal(needsHost.config, 'config');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<link rel="import" href="dom-bind-elements2.html">
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user