Skip to content
This repository was archived by the owner on Mar 13, 2018. It is now read-only.

Commit b9266f7

Browse files
committed
NodeBind: oneTime.
This patch changes the call signature of bind(), which now takes: name, value, oneTime. oneTime is expected to be true if the caller wishes the bound value updated but doesn't require it to track an observable. if oneTime is true, it is expected that value will NOT be an observable, otherwise it will be. R=arv BUG= Review URL: https://codereview.appspot.com/43700043
1 parent 5c904e7 commit b9266f7

2 files changed

Lines changed: 109 additions & 34 deletions

File tree

src/NodeBind.js

Lines changed: 51 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,16 @@
103103
};
104104
}
105105

106-
Text.prototype.bind = function(name, observable) {
106+
Text.prototype.bind = function(name, value, oneTime) {
107107
if (name !== 'textContent')
108-
return Node.prototype.bind.call(this, name, observable);
108+
return Node.prototype.bind.call(this, name, value, oneTime);
109+
110+
if (oneTime)
111+
return updateText(this, value);
109112

110113
unbind(this, 'textContent');
111-
updateText(this, observable.open(textBinding(this)));
112-
return this.bindings.textContent = observable;
114+
updateText(this, value.open(textBinding(this)));
115+
return this.bindings.textContent = value;
113116
}
114117

115118
function updateAttribute(el, name, conditional, value) {
@@ -130,19 +133,21 @@
130133
};
131134
}
132135

133-
Element.prototype.bind = function(name, observable) {
136+
Element.prototype.bind = function(name, value, oneTime) {
134137
var conditional = name[name.length - 1] == '?';
135138
if (conditional) {
136139
this.removeAttribute(name);
137140
name = name.slice(0, -1);
138141
}
139142

140-
unbind(this, name);
143+
if (oneTime)
144+
return updateAttribute(this, name, conditional, value);
141145

146+
unbind(this, name);
142147
updateAttribute(this, name, conditional,
143-
observable.open(attributeBinding(this, name, conditional)));
148+
value.open(attributeBinding(this, name, conditional)));
144149

145-
return this.bindings[name] = observable;
150+
return this.bindings[name] = value;
146151
};
147152

148153
var checkboxEventType;
@@ -269,35 +274,42 @@
269274
}
270275
}
271276

272-
HTMLInputElement.prototype.bind = function(name, observable) {
277+
HTMLInputElement.prototype.bind = function(name, value, oneTime) {
273278
if (name !== 'value' && name !== 'checked')
274-
return HTMLElement.prototype.bind.call(this, name, observable);
279+
return HTMLElement.prototype.bind.call(this, name, value, oneTime);
275280

276-
unbind(this, name);
277-
this.removeAttribute(name);
278281

282+
this.removeAttribute(name);
279283
var sanitizeFn = name == 'checked' ? booleanSanitize : sanitizeValue;
280284
var postEventFn = name == 'checked' ? checkedPostEvent : noop;
281-
bindInputEvent(this, name, observable, postEventFn);
285+
286+
if (oneTime)
287+
return updateInput(this, name, value, sanitizeFn);
288+
289+
unbind(this, name);
290+
bindInputEvent(this, name, value, postEventFn);
282291
updateInput(this, name,
283-
observable.open(inputBinding(this, name, sanitizeFn)),
292+
value.open(inputBinding(this, name, sanitizeFn)),
284293
sanitizeFn);
285294

286-
return this.bindings[name] = observable;
295+
return this.bindings[name] = value;
287296
}
288297

289-
HTMLTextAreaElement.prototype.bind = function(name, observable) {
298+
HTMLTextAreaElement.prototype.bind = function(name, value, oneTime) {
290299
if (name !== 'value')
291-
return HTMLElement.prototype.bind.call(this, name, observable);
300+
return HTMLElement.prototype.bind.call(this, name, value, oneTime);
292301

293-
unbind(this, 'value');
294302
this.removeAttribute('value');
295303

296-
bindInputEvent(this, 'value', observable);
304+
if (oneTime)
305+
return updateInput(this, 'value', value);
306+
307+
unbind(this, 'value');
308+
bindInputEvent(this, 'value', value);
297309
updateInput(this, 'value',
298-
observable.open(inputBinding(this, 'value', sanitizeValue)));
310+
value.open(inputBinding(this, 'value', sanitizeValue)));
299311

300-
return this.bindings.value = observable;
312+
return this.bindings.value = value;
301313
}
302314

303315
function updateOption(option, value) {
@@ -326,16 +338,19 @@
326338
}
327339
}
328340

329-
HTMLOptionElement.prototype.bind = function(name, observable) {
341+
HTMLOptionElement.prototype.bind = function(name, value, oneTime) {
330342
if (name !== 'value')
331-
return HTMLElement.prototype.bind.call(this, name, observable);
343+
return HTMLElement.prototype.bind.call(this, name, value, oneTime);
332344

333-
unbind(this, 'value');
334345
this.removeAttribute('value');
335346

336-
bindInputEvent(this, 'value', observable);
337-
updateOption(this, observable.open(optionBinding(this)));
338-
return this.bindings.value = observable;
347+
if (oneTime)
348+
return updateOption(this, value);
349+
350+
unbind(this, 'value');
351+
bindInputEvent(this, 'value', value);
352+
updateOption(this, value.open(optionBinding(this)));
353+
return this.bindings.value = value;
339354
}
340355

341356
function updateSelect(select, property, value, retries) {
@@ -356,20 +371,22 @@
356371
}
357372
}
358373

359-
HTMLSelectElement.prototype.bind = function(name, observable) {
374+
HTMLSelectElement.prototype.bind = function(name, value, oneTime) {
360375
if (name === 'selectedindex')
361376
name = 'selectedIndex';
362377

363378
if (name !== 'selectedIndex' && name !== 'value')
364-
return HTMLElement.prototype.bind.call(this, name, observable);
379+
return HTMLElement.prototype.bind.call(this, name, value, oneTime);
365380

366-
367-
unbind(this, name);
368381
this.removeAttribute(name);
369382

370-
bindInputEvent(this, name, observable);
371-
updateSelect(this, name, observable.open(selectBinding(this, name)), 2);
372-
return this.bindings[name] = observable;
383+
if (oneTime)
384+
return updateSelect(this, name, value);
385+
386+
unbind(this, name);
387+
bindInputEvent(this, name, value);
388+
updateSelect(this, name, value.open(selectBinding(this, name)), 2);
389+
return this.bindings[name] = value;
373390
}
374391

375392
// TODO(rafaelw): We should polyfill a Microtask Promise and define it if it isn't.

tests/tests.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ suite('Text bindings', function() {
6565
// TODO(rafaelw): Throw on binding to unavailable property?
6666
});
6767

68+
test('oneTime', function() {
69+
var text = document.createTextNode('hi');
70+
text.bind('textContent', 1, true);
71+
assert.strictEqual('1', text.data);
72+
});
73+
6874
test('No Path', function() {
6975
var text = testDiv.appendChild(document.createTextNode('hi'));
7076
var model = 1;
@@ -127,6 +133,13 @@ suite('Element attribute bindings', function() {
127133
assert.strictEqual('', el.getAttribute('foo'));
128134
});
129135

136+
test('oneTime', function() {
137+
var el = testDiv.appendChild(document.createElement('div'));
138+
var model = {a: '1'};
139+
el.bind('foo', 1, true);
140+
assert.strictEqual('1', el.getAttribute('foo'));
141+
});
142+
130143
test('No path', function() {
131144
var el = testDiv.appendChild(document.createElement('div'));
132145
var model = 1;
@@ -235,6 +248,12 @@ suite('Form Element Bindings', function() {
235248
inputTextAreaValueTest('input');
236249
});
237250

251+
test('Input.value - oneTime', function() {
252+
var el = testDiv.appendChild(document.createElement('input'));
253+
el.bind('value', 42, true);
254+
assert.strictEqual('42', el.value);
255+
});
256+
238257
test('Input.value - no path', function() {
239258
inputTextAreaNoPath('input');
240259
});
@@ -247,6 +266,12 @@ suite('Form Element Bindings', function() {
247266
inputTextAreaValueTest('textarea');
248267
});
249268

269+
test('TextArea.value - oneTime', function() {
270+
var el = testDiv.appendChild(document.createElement('textarea'));
271+
el.bind('value', 42, true);
272+
assert.strictEqual('42', el.value);
273+
});
274+
250275
test('TextArea.value - no path', function() {
251276
inputTextAreaNoPath('textarea');
252277
});
@@ -325,6 +350,14 @@ suite('Form Element Bindings', function() {
325350
assert.isFalse(model.x);
326351
});
327352

353+
test('(Checkbox)Input.checked - oneTime', function() {
354+
var input = testDiv.appendChild(document.createElement('input'));
355+
testDiv.appendChild(input);
356+
input.type = 'checkbox';
357+
input.bind('checked', true, true);
358+
assert.isTrue(input.checked);
359+
});
360+
328361
test('(Checkbox)Input.checked - path unreachable', function() {
329362
var input = testDiv.appendChild(document.createElement('input'));
330363
testDiv.appendChild(input);
@@ -430,6 +463,13 @@ suite('Form Element Bindings', function() {
430463
assert.isTrue(model.x);
431464
});
432465

466+
test('(Radio)Input.checked - oneTime', function() {
467+
var input = testDiv.appendChild(document.createElement('input'));
468+
input.type = 'radio';
469+
input.bind('checked', true, true);
470+
assert.isTrue(input.checked);
471+
});
472+
433473
test('(Radio)Input.checked - path unreachable', function() {
434474
var input = testDiv.appendChild(document.createElement('input'));
435475
input.type = 'radio';
@@ -594,6 +634,18 @@ test('(Radio)Input.checked - multiple forms - ShadowRoot', function() {
594634
assert.strictEqual(1, model.val);
595635
});
596636

637+
test('Select.selectedIndex - oneTime', function() {
638+
var select = testDiv.appendChild(document.createElement('select'));
639+
testDiv.appendChild(select);
640+
var option0 = select.appendChild(document.createElement('option'));
641+
var option1 = select.appendChild(document.createElement('option'));
642+
var option2 = select.appendChild(document.createElement('option'));
643+
644+
select.bind('selectedIndex', 2, true);
645+
Platform.performMicrotaskCheckpoint();
646+
assert.strictEqual(2, select.selectedIndex);
647+
});
648+
597649
test('Select.selectedIndex - path NaN', function() {
598650
var select = testDiv.appendChild(document.createElement('select'));
599651
testDiv.appendChild(select);
@@ -623,6 +675,12 @@ test('(Radio)Input.checked - multiple forms - ShadowRoot', function() {
623675
assert.strictEqual('Hi', option.value);
624676
});
625677

678+
test('Option.value - oneTime', function() {
679+
var option = testDiv.appendChild(document.createElement('option'));
680+
option.bind('value', 42, true);
681+
assert.strictEqual('42', option.value);
682+
});
683+
626684
test('Select.selectedIndex - path unreachable', function() {
627685
var select = testDiv.appendChild(document.createElement('select'));
628686
testDiv.appendChild(select);

0 commit comments

Comments
 (0)