How can I turn doc.id into clickable item?
Right now I can get data from my database, I can list all the doc.id's, but I want to make those into hyperlinks, when pressed it gets the data from the database and shows it's data as a drawing on the canvas. If that makes sense?
doc.id is that unique id for stuff that is saved in my firestore db.
const allDrawings = document.querySelector('#allDrawings');
function renderDrawings(doc){
let li = document.createElement('li');
let key = document.createElement('doc.id');
li.setAttribute('data-id', doc.id);
key.textContent = doc.id;
li.appendChild(key);
allDrawings.appendChild(li);
}
db.collection('joonistused').get().then((snapshot) => {
snapshot.docs.forEach(doc => {
renderDrawings(doc);
console.log(doc.id);
})
})
If you're just trying to create an anchor in the DOM then try something like this:
const anchor = document.createElement('a');
anchor.href = `/some/path/to/${doc.id}`;
anchor.innerText = `Document ID ${doc.id}`;
// Document ID 123
I believe what you are looking for is a design/logic to list documents in a firestore collection in your browser and make them list items. You then want to click on an item and have the content for that document displayed to the user. This will require programming logic on your end. You will want to write browser/client side JavaScript that is called when a link is clicked (onclick). When the JavaScript code is reached you will then want to make a web client call to the Firestore database to retrieve the corresponding document.
See: https://firebase.google.com/docs/reference/js/firebase.firestore.DocumentReference.html#get
This looks very useful too:
Firebase Firestore Tutorial #3 - Getting Documents
Related
I am doing one of my first projects using the Ball Don't lie API, trying to build my version of an ESPN landing page. I am using https://www.balldontlie.io/api/v1/players. I am using Javascript, I have been stuck for days trying to understand how to display the first and last name of all of the players on the landing page in HTML. I only know how to display one name if I use data.data[0]. I've tried .map, loops, it's just not clicking. I want to be able to display other stats in the array as well. Can anyone help?
This my Javascript code:
async function getPlayers() {
const response = await fetch ('https://www.balldontlie.io/api/v1/players');
const data = await response.json();
const players = data.data;
console.log(players);
displayPlayer(players);
}
function displayPlayer(players) {
const scores = document.getElementById('scores');
scores.innerHTML = `
${players.first_name} ${players.last_name}`;
}
getPlayers()```
I had tried .map, I've tried loops, I am just not understanding what function is going to show the players. Maybe my orignal code doesn't make sense. I've tried watching Youtube and can't find anyone doing it in simple Javascript.
You can try this in your script and edit points 2. and 4. for better display of what you need to show
// 1. GET request using fetch()
fetch("https://www.balldontlie.io/api/v1/players")
// Converting received data to JSON
.then((response) => response.json())
.then((json) => {
// 2. Create a variable to store HTML table headers
let li = `<tr><th>ID</th><th>first_name</th><th>height_feet</th><th>height_inches</th> <th>last_name</th><th>position</th><th>im lazy...</th></tr>`;
// 3. Loop through each data and add a table row
console-console.log(json.data);
json.data.forEach((user) => {
li += `<tr>
<td>${user.id}</td>
<td>${user.first_name} </td>
<td>${user.height_feet}</td>
<td>${user.height_inches}</td>
<td>${user.last_name}</td>
<td>${user.position}</td>
<td>${user.team.id}</td>
<td>${user.team.abbreviation}</td>
<td>${user.team.city}</td>
<td>${user.team.conference}</td>
<td>${user.team.division}</td>
<td>${user.team.full_name}</td>
<td>${user.team.name}</td>
</tr>`;
});
// 4. DOM Display result
document.getElementById("users").innerHTML = li;
});
And your html body part look like this
<div>
<!-- Table to display fetched user data -->
<table id="users"></table>
</div>
Your constant players is an array. In order to access a player's information within that array, you would need to index each player to then access their object of key:value pairs.
That is why you can get the first player's name to show when you save players as data.data[0]. This is indicating that you want to access the object in position 0 in the array. If you wanted the second player's information you would reference data.data[1], and so forth.
With trying to keep as much of your original code as possible (and adding some comments), I believe this is what you were trying to achieve.
async function getPlayers() {
// Fetch the API and convert it to json.
const response = await fetch ('https://www.balldontlie.io/api/v1/players');
const data = await response.json();
// Save the returned data as an array.
const players = data.data;
console.log(players);
// Create an element to display each individual player's information.
players.array.forEach(player => {
displayPlayer(player);
});
}
function displayPlayer(player) {
// Grab the element encasing all players.
const scores = document.getElementById('scores');
// Create a new element for the individual player.
const playerContent = document.createElement('div');
// Add the player's name.
playerContent.innerHTML = `
${player.first_name} ${player.last_name}`;
// Add the player content into the encasing division.
scores.appendChild(playerContent);
}
getPlayers()
We will use the forEach() function to index each player's object in the array of data for us, grab your "scores" element you created on your HTML page, then we will "append" (add to the end) each player's information into your "scores" element.
The website link below has some useful information to read that can help you build on your existing code when you want to start adding styling.
https://www.thesitewizard.com/javascripts/insert-div-block-javascript.shtml
This site has some useful information on using "promises" when dealing with async functions that will come in handy as you progress in coding.
https://www.geeksforgeeks.org/why-we-use-then-method-in-javascript/
These website links were added as of 02/04/2023 (just to add as a disclaimer to the links because who knows what they will do in 2030 O.o).
Hope this helps!
I am trying to impelement a delete function in Firestore database and the problem is that when I click delete, it deletes the last document created, not the one that I want to delete.
This is how I get the data from the database:
db.collection("flights").get().then((snapshot) =>{
snapshot.docs.forEach(doc => {
var data = doc.data();
var docID = doc.id;
And this is how I am trying to delete it:
function deleteFlight(docID){
firebase.firestore()
.collection("flights")
.doc(docID)
.delete()
.then(() => console.log("Document deleted")) // Document deleted
.catch((error) => console.error("Error deleting document", error));
}
I want to specify that after I create a new document, the website is refreshed, so I think it loses somehow the document id.
In the comment section you have specified that you are calling the deleteFlight() function from a html button. As you are using forEach() loop after getting the collection of documents and within that populating docID, by the time the html button is clicked the forEach() loop would have been completed and then docID will have the document id of the document which comes last in ascending order because by default the documents are sorted in ascending order of document id as mentioned in this document. In your case I suspect the document id for the recently added document comes last when sorted in ascending order. This is the reason the recently added document is getting deleted.
I am not sure of your use case. But I would suggest you to declare a variable outside of the db.collection() method and implement some logic according to your use case to populate it with the document id which you want to delete. Then use that variable in the deleteFlight() function.
Any suggestions on how to get a snapshot to only return certain
documents in a collection?
db.collection('locations-data').get().then(snapshot => {
setupLocations(snapshot.docs);
The JS setupLocations function loops through and adds data to an ul/li on the UI.It Works but it loads every document and I only want a specific document based on a users access listed in a user collection.
In my "locations-data" collection I have documents named by location (e.g. ca1001, ca1002, etc.)
And a user collection > userID > locations array to set which locations a user can view.
As mentioned above, The Setup works great on the front-end but loads all documents and I only want certain users to get certain locations (documents) to show in the UI.
I get the locations array from the users collection into a var, and have tried using map and other things on the code side, also tried a few things via security rules, etc. Just not having much luck.
Here's the code on the UI side that loads the display for the user.
// show locations
const setupLocations = (data) => {
if (data.length) {
let html = '';
data.forEach((doc) => {
const location = doc.data();
const li = `
<li>
<div class="collapsible-header grey lighten-4">
${location.shortName}, Total Income: ${location.todayIncome}
</div>
<div class="collapsible-body white">${location.totalIncome}</div>
</li>
`;
html += li;
});
locationList.innerHTML = html;
} else {
locationList.innerHTML = '<h5 class="center-align">Login to view data</h5>';
}
};
I ended up using "array-contains" and just added a users field to each document I want to include. .where('_users', 'array-contains', user.email). Will just have to create a simple admin to manage users this way to avoid having to add all users to each document manually. Thanks all for suggestions.
Any suggestions on how to get a snapshot to only return certain documents in a collection?
Since your first option is to get all document based on the users location you can use what #pepe said, the where in query filter to get a specific or certain documents inside your collection. The other option is store all the data of location from user collection to a array variable then display it directly to your UI. With that you don't need to query for location-data collection because you already got all the specific location data based on the user's data.
I have the following code to retrieve some user information from Cloud Firestore - it grabs the list of challenges a user is part of from a subcollection on their user document and then uses those ids to collect the full challenge information from the top level challenge document.
When I delete a challenge I remove it from the main challenges document and then remove the id reference in each users challenges subcollection. The UI updates nicely for each delete as snapshotchanges is an active subscription, until I delete the final one. The final one deletes from the database but stays in the UI until I refresh or make a new challenge.
My theory is that becuase deleting the last document in the challenges subcollection also deletes the subcollection this means snapshotChanges doesn't run as there is no longer a collection in the database to monitor the changes on.
Any thoughts on how to workaround this would be great.
getChallenges() {
return this.getCurrentUserId().pipe(switchMap(userId => {
return this.db.collection(`users/${userId}/challenges`).snapshotChanges().pipe(
map(actions => actions.map(a => {
const data = a.payload.doc.data();
console.log('in get challenges: ', data);
const user_challenge_key = a.payload.doc.id;
return this.getOneChallenge(data['id'], user_challenge_key);
}))
);
}));
}
getOneChallenge(id, user_challenge_key = null): Observable<Challenge> {
return this.db.doc(`challenges/${id}`).snapshotChanges().pipe(
take(1),
map(changes => {
const data = new Challenge(changes.payload.data());
const challengeId = changes.payload.id;
data.user_challenge_key = user_challenge_key;
data.id = id;
console.log('in get One challenge: ', data);
return data;
})
);
}
Maybe maintain a dummy document in order to keep the sub-collection
For example, validate if you going to delete the last element of that sub-collection add the dummy and later delete the last element
for the first insertion check if the dummy object is the only document, after that add your first entry and delete the dummy
I found a similar question with similar approach on the Firestore's Google Group
I am trying to get a way to delete firestore document by a click event.
here is what i have so far. x is the document id i get from firestore. But how to get the ID change dynamically based on the content show in the page? SO that user can delete the content they wanted.
var deleteContent = document.getElementById('delete');
deleteContent.addEventListener('click', function(e) {
// get current document ID
x = 'poOjcQce2iiKzp2FaFVA'
var getId = db.collection("checkin").doc(x);
getId.delete().then(function() {
console.log(" successfully deleted!");
}).catch(function(error) {
console.error("Error removing document: ", error);
});
});
Thanks
Firebase Cloud Firestore allows you to perform simple and compounded queries. Essentially, you can provide a condition in the db.collection(<COLLECTION>).where() clause which will filter all documents that match that certain condition.
For illustrative purposes, suppose documents in the a collection follow the following structure: { id, '123', name: 'test', color: 'red' }. If you want to get all documents with the color red, you can simply call db.collection('a').where('color', '==', 'red'), which you can then iterate into to process each document that matches that condition.
Moreover, in your specific case, suppose your document structure is { id, content }you can try something like this:
var deleteContent = document.getElementById('delete');
deleteContent.addEventListener('click', function(e) {
// get current document ID
let docToDelete = db.collection("checkin").where('content', '==', 'CONTENT_GOES_HERE')
x = docToDelete.id;
var getId = db.collection("checkin").doc(x);
getId.delete().then(function() {
console.log(" successfully deleted!");
}).catch(function(error) {
console.error("Error removing document: ", error);
});
});
However, a much simpler way would be to store the document id somewhere within your application whenever a specific document is read, local storage or session storage for instance. As such, you can refer to the document id whenever you need. For example, suppose that you fetch all of a user's documents in an onLoad event handler --- suppose that you have HTML elements with the id 'content1', 'content2', 'content3', etc. and that it is where the contents of your documents are shown. You can try something like this:
let userId = 123;
[...].onload = () => {
// Get all of the documents belonging to this user
let i = 0;
let docs = [];
let documents = db.collection('posts').where('userId', '==', userId);
documents.forEach(doc => {
document.getElementById(`content${i}`).innerHTML = JSON.stringify(doc.data()); // Just stringifying to be certain
/**
* Extra step to add the document id in the sessionStorage so that we can refer to it later
*/
htmlId = 'content' + i;
sessionStorage.setItem(htmlID, doc.id );
})
}
In doing so, you can simply refer to the document id like such sessionStorage.getItem('content2').
Note that in any of the examples I listed, there is heavy preparation that needs to be done in order for this to be as smooth sailing as possible. However, wouldn't you agree that a programmer merely is a person that spends hours on things that takes minutes for the sake of making it easier in subsequent uses? :)