diff --git a/extensions/amp-bind/0.1/amp-state.js b/extensions/amp-bind/0.1/amp-state.js index 3c87e1527877..5b6f0ec12e87 100644 --- a/extensions/amp-bind/0.1/amp-state.js +++ b/extensions/amp-bind/0.1/amp-state.js @@ -14,7 +14,7 @@ * limitations under the License. */ -import {bindForDoc} from '../../../src/services'; +import {bindForDoc, viewerForDoc} from '../../../src/services'; import {fetchBatchedJsonFor} from '../../../src/batched-json'; import {isBindEnabledFor} from './bind-impl'; import {isJsonScriptTag} from '../../../src/dom'; @@ -52,11 +52,32 @@ export class AmpState extends AMP.BaseElement { user().assert(isBindEnabledFor(this.win), `Experiment "amp-bind" is disabled.`); - const TAG = this.getName_(); - toggle(this.element, /* opt_display */ false); this.element.setAttribute('aria-hidden', 'true'); + // Don't parse or fetch in prerender mode. + const viewer = viewerForDoc(this.getAmpDoc()); + viewer.whenFirstVisible().then(() => this.initialize_()); + } + + /** @override */ + mutatedAttributesCallback(mutations) { + const src = mutations['src']; + if (src !== undefined) { + this.fetchSrcAndUpdateState_(/* isInit */ false); + } + } + + /** @override */ + renderOutsideViewport() { + // We want the state data to be available wherever it is in the document. + return true; + } + + /** @private */ + initialize_() { + const TAG = this.getName_(); + // Fetch JSON from endpoint at `src` attribute if it exists, // otherwise parse child script tag. if (this.element.hasAttribute('src')) { @@ -83,20 +104,6 @@ export class AmpState extends AMP.BaseElement { } } - /** @override */ - mutatedAttributesCallback(mutations) { - const src = mutations['src']; - if (src !== undefined) { - this.fetchSrcAndUpdateState_(/* isInit */ false); - } - } - - /** @override */ - renderOutsideViewport() { - // We want the state data to be available wherever it is in the document. - return true; - } - /** * @param {boolean} isInit * @private diff --git a/extensions/amp-bind/0.1/bind-impl.js b/extensions/amp-bind/0.1/bind-impl.js index 0614f7f3036b..4a7ebd08f863 100644 --- a/extensions/amp-bind/0.1/bind-impl.js +++ b/extensions/amp-bind/0.1/bind-impl.js @@ -27,7 +27,11 @@ import {isExperimentOn} from '../../../src/experiments'; import {invokeWebWorker} from '../../../src/web-worker/amp-worker'; import {isFiniteNumber} from '../../../src/types'; import {reportError} from '../../../src/error'; -import {ampFormServiceForDoc, resourcesForDoc} from '../../../src/services'; +import { + ampFormServiceForDoc, + resourcesForDoc, + viewerForDoc, +} from '../../../src/services'; import {filterSplice} from '../../../src/utils/array'; import {rewriteAttributeValue} from '../../../src/sanitizer'; @@ -127,13 +131,17 @@ export class Bind { this.evaluator_ = new BindEvaluator(); } + /** @const @private {!../../../src/service/viewer-impl.Viewer} */ + this.viewer_ = viewerForDoc(this.ampdoc); + /** * Resolved when the service is fully initialized. * @const @private {Promise} */ - this.initializePromise_ = this.ampdoc.whenReady().then(() => { - return this.initialize_(); - }); + this.initializePromise_ = Promise.all([ + this.ampdoc.whenReady(), + this.viewer_.whenFirstVisible(), // Don't initialize in prerender mode. + ]).then(() => this.initialize_()); /** * Form implementations are not filled in until ampdoc is ready. diff --git a/extensions/amp-bind/0.1/test/test-amp-state.js b/extensions/amp-bind/0.1/test/test-amp-state.js index ac7bc9fb33b0..4aca5fde3843 100644 --- a/extensions/amp-bind/0.1/test/test-amp-state.js +++ b/extensions/amp-bind/0.1/test/test-amp-state.js @@ -48,17 +48,17 @@ describe('AmpState', () => { sandbox.restore(); }); - it('should parse its child script if `src` is not present at build', () => { + it('should parse its child script if `src` is not present at init', () => { ampState.innerHTML = ''; - ampState.implementation_.buildCallback(); + ampState.implementation_.initialize_(); expect(fetchStub).to.not.have.been.called; expect(updateStub).calledWithMatch({foo: 'bar'}); }); - it('should fetch json if `src` is present at build', () => { + it('should fetch json if `src` is present at init', () => { ampState.setAttribute('src', 'https://foo.com/bar?baz=1'); - ampState.implementation_.buildCallback(); + ampState.implementation_.initialize_(); expect(fetchStub).calledWith(/* opt_isInit */ true); expect(updateStub).to.not.have.been.called; });