Polymer 2.x:dom-if模板中querySelector返回null的问题求助
Hey there! I’ve run into this exact issue with Polymer 2.0’s <dom-if> before—total head-scratcher at first, but once you remember how <dom-if> works, it clicks right into place.
Why querySelector is returning null
The core problem here is that <dom-if> uses lazy conditional rendering. Since your uploaded property defaults to false, the template content (including your #upload element) isn’t inserted into the DOM when connectedCallback runs. That’s why this.shadowRoot.querySelector('#upload') comes back null—there’s no element to find yet.
Fixes that work
Here are the most reliable ways to hook into the moment when the <dom-if> content is actually rendered:
1. Listen for the dom-change event on <dom-if>
<dom-if> fires a dom-change event whenever its content is added to or removed from the DOM. You can use this to trigger your event listener setup:
First, add an ID to your <dom-if> element (and optionally restamp="true" if you need the content to fully re-render when uploaded changes):
<dom-if id="uploadDomIf" restamp="true" if="{{uploaded}}"> <template> <div id="upload"><!-- Your upload component --></div> </template> </dom-if>
Then in your element class:
connectedCallback() { super.connectedCallback(); // Save bound references to your handlers for clean removal later this._uploadResponseHandler = this.handleUploadResponse.bind(this); this._uploadSuccessHandler = this.handleUploadSuccess.bind(this); this.$.uploadDomIf.addEventListener('dom-change', () => { const uploadEl = this.shadowRoot.querySelector('#upload'); if (uploadEl) { uploadEl.addEventListener('upload-response', this._uploadResponseHandler); uploadEl.addEventListener('upload-success', this._uploadSuccessHandler); } else { // If the element was removed, clean up listeners to avoid leaks const oldUploadEl = this.shadowRoot.querySelector('#upload'); if (oldUploadEl) { oldUploadEl.removeEventListener('upload-response', this._uploadResponseHandler); oldUploadEl.removeEventListener('upload-success', this._uploadSuccessHandler); } } }); }
2. Use an observer for the uploaded property
You can watch for changes to the uploaded property, and when it switches to true, wait for the DOM to update before querying the element:
static get properties() { return { uploaded: { type: Boolean, value: false } }; } static get observers() { return ['_onUploadedChanged(uploaded)']; } _onUploadedChanged(newUploadedState) { if (newUploadedState) { // Use this.async() to wait for the <dom-if> content to render this.async(() => { const uploadEl = this.shadowRoot.querySelector('#upload'); if (uploadEl) { uploadEl.addEventListener('upload-response', this.handleUploadResponse.bind(this)); uploadEl.addEventListener('upload-success', this.handleUploadSuccess.bind(this)); } }); } else { // Clean up listeners when the element is removed const uploadEl = this.shadowRoot.querySelector('#upload'); if (uploadEl) { uploadEl.removeEventListener('upload-response', this.handleUploadResponse.bind(this)); uploadEl.removeEventListener('upload-success', this.handleUploadSuccess.bind(this)); } } }
Key note about memory leaks
Always remember to remove event listeners when the <dom-if> content is removed (when uploaded switches back to false). If you don’t, you’ll leave dangling references that can cause memory leaks over time. Using bound handler references (like this._uploadResponseHandler) makes clean removal much easier.
内容的提问来源于stack exchange,提问作者Sylia Baraka

