如何将Firestore查询结果嵌入Polymer 3模板?
Hey there, let's work through this problem step by step—async logic with web components can definitely feel tricky at first, but we'll get this sorted out for you!
First: Fix the this Context Issue
The biggest roadblock in your current code is that inside the .then() callback, this doesn't point to your MyPage component instance. That's why you can't set this.users directly. The simple fix here is to use an arrow function instead of a regular function—arrow functions preserve the outer context's this:
class MyPage extends PolymerElement { constructor() { super(); this.users = ''; // Initialize the property with a default value } static get properties() { return { users: { type: String, value: '' // Ensures the template has something to render initially } } } static get template() { return html`<div>[[users]]</div>`; } connectedCallback() { super.connectedCallback(); // Always call the parent method first! // Fetch users once the component is attached to the DOM const setsRef = firestore.collection("users"); setsRef.get().then((querySnapshot) => { // Arrow function preserves `this` const users = []; querySnapshot.forEach((doc) => { users.push(doc.data().verb); }); this.users = users.join(", "); // Now `this` refers to your MyPage component! }).catch((error) => { console.log("Error getting documents: ", error); }); } }
I moved the Firestore call to connectedCallback() instead of the constructor because Polymer components are more fully initialized when they're attached to the DOM—this avoids potential issues with early property access.
Second: Extract Firestore Logic to an External File
To keep your component clean and reusable, let's move the Firestore query into a separate service file (e.g., firestore-services.js):
// firestore-services.js export async function getAllUsers() { try { const setsRef = firestore.collection("users"); const querySnapshot = await setsRef.get(); const users = []; querySnapshot.forEach((doc) => { users.push(doc.data().verb); }); return users.join(", "); // Return the formatted string of users } catch (error) { console.error("Error fetching users: ", error); throw error; // Let the component handle the error if needed } }
Now import this function into your component and use async/await for cleaner, more readable async code:
import { getAllUsers } from './firestore-services.js'; class MyPage extends PolymerElement { constructor() { super(); this.users = ''; } static get properties() { return { users: { type: String, value: '' } } } static get template() { return html`<div>[[users]]</div>`; } async connectedCallback() { super.connectedCallback(); try { this.users = await getAllUsers(); // Wait for the async result to resolve } catch (error) { // Handle error here (e.g., show a user-friendly message) console.log("Failed to load users: ", error); } } }
Bonus: Use an Array Property for More Flexibility
If you might want to render individual users later (instead of just a comma-separated string), adjust the users property to be an Array:
static get properties() { return { users: { type: Array, value: () => [] // Default to an empty array } } } // Update the template to iterate over users with dom-repeat static get template() { return html` <div> <h3>User List:</h3> <ul> <template is="dom-repeat" items="[[users]]"> <li>[[item]]</li> </template> </ul> </div> `; } // Adjust the service to return an array instead of a string export async function getAllUsers() { try { const setsRef = firestore.collection("users"); const querySnapshot = await setsRef.get(); return querySnapshot.docs.map(doc => doc.data().verb); // Directly map docs to an array } catch (error) { console.error("Error fetching users: ", error); throw error; } }
This gives you more control over how you display user data in your template down the line.
内容的提问来源于stack exchange,提问作者Jonathan

