如何使用Promise对象绑定Polymer模板的dom-repeat?
dom-repeat and Dropdowns Hey there! Let's work through how to bind Promise-based data (like what you get from Firestore) to Polymer's dom-repeat and dropdown elements. I've dealt with this exact scenario before, so here's a step-by-step breakdown with code examples.
First, a core concept to keep in mind: Polymer's template system doesn't natively resolve Promises directly in bindings. The fix? Resolve the Promise first, then assign the result to a reactive Polymer property—since Polymer automatically updates the UI when reactive properties change.
1. Binding Firestore Data to dom-repeat
Here's how to fetch data from Firestore (via a Promise) and bind it to dom-repeat:
Step 1: Define Reactive Properties
In your Polymer element, declare a property to hold the Firestore data. This property needs to be reactive so Polymer can track changes and update the UI.
Step 2: Fetch Data and Resolve the Promise
In the element's connectedCallback (or a custom method), call Firestore's API, resolve the Promise, and assign the parsed data to your reactive property.
Full Code Example (Element + Template)
JavaScript
class FirestoreListElement extends Polymer.Element { static get is() { return 'firestore-list-element'; } static get properties() { return { // Reactive property to hold Firestore items firestoreItems: { type: Array, value: () => [] // Default empty array to avoid null errors } }; } connectedCallback() { super.connectedCallback(); this.loadFirestoreData(); // Trigger data fetch when element connects to DOM } loadFirestoreData() { // Call Firestore collection (returns a Promise) firebase.firestore().collection('your-collection-name').get() .then(querySnapshot => { // Convert Firestore snapshot to an array of usable objects const items = querySnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() // Spread all document fields into the object })); // Assign to reactive property to trigger UI update this.firestoreItems = items; }) .catch(error => { console.error('Failed to load Firestore data:', error); // Add user-facing error handling here if needed }); } } customElements.define(FirestoreListElement.is, FirestoreListElement);
HTML Template
<dom-module id="firestore-list-element"> <template> <h2>My Firestore Items</h2> <!-- Bind dom-repeat to the reactive property --> <div class="item-list"> <dom-repeat items="[[firestoreItems]]"> <template> <div class="item-card"> <h3>[[item.title]]</h3> <p>[[item.description]]</p> </div> </template> </dom-repeat> </div> </template> </dom-module>
2. Binding Firestore Data to a Dropdown
For dropdowns (like paper-dropdown-menu or native <select>), the approach is nearly identical: resolve the Promise to get options, assign to a reactive property, then bind that property to the dropdown's items.
Example with paper-dropdown-menu
Update the Element's Properties and Methods
Add a reactive property for dropdown options, plus a method to fetch them:
static get properties() { return { firestoreItems: { /* ... existing property ... */ }, dropdownOptions: { type: Array, value: () => [] }, selectedOption: { type: String, notify: true, // Let parent elements track selection changes reflectToAttribute: true } }; } connectedCallback() { super.connectedCallback(); this.loadFirestoreData(); this.loadDropdownOptions(); // Fetch dropdown options on element load } loadDropdownOptions() { firebase.firestore().collection('dropdown-options').get() .then(querySnapshot => { this.dropdownOptions = querySnapshot.docs.map(doc => ({ label: doc.data().displayName, // Text users will see in the dropdown value: doc.id // The underlying value to track for selections })); }) .catch(error => { console.error('Failed to load dropdown options:', error); }); }
Update the Template
Add the dropdown, using dom-repeat to render options:
<template> <!-- ... existing dom-repeat section ... --> <h3>Select an Option</h3> <paper-dropdown-menu label="Choose an Item"> <paper-listbox slot="dropdown-content" selected="{{selectedOption}}"> <dom-repeat items="[[dropdownOptions]]"> <template> <paper-item value="[[item.value]]">[[item.label]]</paper-item> </template> </dom-repeat> </paper-listbox> </paper-dropdown-menu> </template>
Key Notes to Remember
- Never bind a Promise-returning function directly to
dom-repeator dropdown items (e.g.,<dom-repeat items="[[loadFirestoreData()]]">). This causes repeated, unnecessary API calls and won't resolve the Promise for the UI. - Stick to reactive properties: Polymer's reactivity system is what triggers UI updates when your data changes.
- Real-time updates: If you want the UI to auto-update when Firestore data changes, use
onSnapshot()instead ofget():
This sets up a listener that updates your property every time the collection changes.loadFirestoreData() { firebase.firestore().collection('your-collection-name') .onSnapshot(querySnapshot => { const items = querySnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); this.firestoreItems = items; }, error => { console.error('Snapshot error:', error); }); }
内容的提问来源于stack exchange,提问作者Raj T

