diff --git a/src/checked-observer.js b/src/checked-observer.js
index 00ad5cb9..64ad0155 100644
--- a/src/checked-observer.js
+++ b/src/checked-observer.js
@@ -1,6 +1,7 @@
import {subscriberCollection} from './subscriber-collection';
const checkedArrayContext = 'CheckedObserver:array';
+const checkedValueContext = 'CheckedObserver:value';
@subscriberCollection()
export class CheckedObserver {
@@ -42,8 +43,14 @@ export class CheckedObserver {
}
call(context, splices) {
- // called by task queue and array observer.
+ // called by task queue, array observer, and model/value observer.
this.synchronizeElement();
+ // if the input's model or value property is data-bound, subscribe to it's
+ // changes to enable synchronizing the element's checked status when a change occurs.
+ if (!this.valueObserver
+ && (this.valueObserver = this.element.__observers__.model || this.element.__observers__.value)) {
+ this.valueObserver.subscribe(checkedValueContext, this);
+ }
}
synchronizeElement() {
@@ -117,5 +124,8 @@ export class CheckedObserver {
this.arrayObserver.unsubscribe(checkedArrayContext, this);
this.arrayObserver = null;
}
+ if (this.valueObserver) {
+ this.valueObserver.unsubscribe(checkedValueContext, this);
+ }
}
}
diff --git a/src/observer-locator.js b/src/observer-locator.js
index 695f21ef..7c1942e2 100644
--- a/src/observer-locator.js
+++ b/src/observer-locator.js
@@ -179,6 +179,7 @@ export class ObserverLocator {
|| propertyName === 'style' || propertyName === 'css'
|| propertyName === 'value' && (obj.tagName.toLowerCase() === 'input' || obj.tagName.toLowerCase() === 'select')
|| propertyName === 'checked' && obj.tagName.toLowerCase() === 'input'
+ || propertyName === 'model' && obj.tagName.toLowerCase() === 'input'
|| /^xlink:.+$/.exec(propertyName)) {
return this.getObserver(obj, propertyName);
}
diff --git a/test/checked-observer.spec.js b/test/checked-observer.spec.js
index c1fa2bb7..df121670 100644
--- a/test/checked-observer.spec.js
+++ b/test/checked-observer.spec.js
@@ -22,6 +22,7 @@ describe('CheckedObserver', () => {
beforeAll(() => {
obj = { selectedItems: [] };
el = createElement('');
+ observerLocator.getObserver(el, 'value');
document.body.appendChild(el);
binding = getBinding(observerLocator, obj, 'selectedItems', el, 'checked', bindingMode.twoWay).binding;
});
@@ -39,6 +40,19 @@ describe('CheckedObserver', () => {
}, 0);
});
+ it('responds to element value change', done => {
+ expect(el.checked).toBe(true);
+ el.__observers__.value.setValue('ZZZZ');
+ setTimeout(() => {
+ expect(el.checked).toBe(false);
+ el.__observers__.value.setValue('A');
+ setTimeout(() => {
+ expect(el.checked).toBe(true);
+ done();
+ });
+ }, 0);
+ });
+
it('responds to element change', done => {
el.checked = false;
el.dispatchEvent(DOM.createCustomEvent('change'));
@@ -77,6 +91,7 @@ describe('CheckedObserver', () => {
obj = { selectedItems: [], itemA: {} };
el = createElement('');
el.model = obj.itemA;
+ observerLocator.getObserver(el, 'model');
document.body.appendChild(el);
binding = getBinding(observerLocator, obj, 'selectedItems', el, 'checked', bindingMode.twoWay).binding;
});
@@ -94,6 +109,19 @@ describe('CheckedObserver', () => {
}, 0);
});
+ it('responds to element value change', done => {
+ expect(el.checked).toBe(true);
+ el.__observers__.model.setValue({});
+ setTimeout(() => {
+ expect(el.checked).toBe(false);
+ el.__observers__.model.setValue(obj.itemA);
+ setTimeout(() => {
+ expect(el.checked).toBe(true);
+ done();
+ });
+ }, 0);
+ });
+
it('responds to element change', done => {
el.checked = false;
el.dispatchEvent(DOM.createCustomEvent('change'));
diff --git a/test/observer-locator.spec.js b/test/observer-locator.spec.js
index a22b1478..3d1162a1 100644
--- a/test/observer-locator.spec.js
+++ b/test/observer-locator.spec.js
@@ -165,4 +165,8 @@ describe('ObserverLocator', () => {
it('getAccessor returns ValueAttributeObserver for input.value', () => {
expect(locator.getAccessor(document.createElement('input'), 'value') instanceof ValueAttributeObserver).toBe(true);
});
+
+ it('getAccessor returns SetterObserver for input.model', () => {
+ expect(locator.getAccessor(document.createElement('input'), 'model') instanceof SetterObserver).toBe(true);
+ });
});