I want to delete an item from the Firebase real-time database by clicking the button in JavaScript. I get data from the database directly in the frontend. When I click the Delete button, the corresponding object should be removed from the database and the front end. I tried some logic functions and deleted a certain element from the database, but my HTML page did not update.
I have to refresh the page every time. How can I delete it in real-time?
Here is my complete code https://jsfiddle.net/waqasumer/x1ugL5yr/
function deleteTodo(e) {
const key = e.parentElement.parentElement.getAttribute('data-key');
firebase.database().ref('tasks').child(key).remove();
}
var main = document.getElementById("main-section");
function saveData() {
var todo = document.getElementById("todo-item");
if (todo.value === "") {
alert("Please enter task");
} else {
var key = firebase.database().ref('tasks').push().key;
var tasks = {
todo: todo.value,
key: key
}
firebase.database().ref('tasks/' + key).set(tasks);
document.getElementById("todo-item").value = "";
}
}
function getData() {
firebase.database().ref('tasks').on('child_added', function (data) {
var item = data.val().todo;
var key = data.val().key;
console.log(data.val());
var row = document.createElement("div");
row.setAttribute("class", "row");
row.setAttribute("data-key", key);
var col1 = document.createElement("div");
col1.setAttribute("class", "col text");
var task = document.createTextNode(item);
col1.appendChild(task);
row.appendChild(col1);
var col2 = document.createElement("div");
col2.setAttribute("class", "col");
var editBtn = document.createElement("button");
editBtn.setAttribute("class", "btn btn-success btn-circle btn-sm fa fa-pencil-square-o");
editBtn.setAttribute("onclick", "editTodo(this)");
col2.appendChild(editBtn);
row.appendChild(col2);
var col3 = document.createElement("div");
col3.setAttribute("class", "col");
var deleteBtn = document.createElement("button");
deleteBtn.setAttribute("class", "btn btn-primary btn-circle btn-sm btn-danger fa fa-remove");
deleteBtn.setAttribute("onclick", "deleteTodo(this)");
col3.appendChild(deleteBtn);
row.appendChild(col3);
main.appendChild(row);
})
}
getData();
function deleteAll() {
firebase.database().ref('tasks').remove();
main.innerHTML = "";
}
function deleteTodo(e) {
const key = e.parentElement.parentElement.getAttribute('data-key');
firebase.database().ref('tasks').child(key).remove();
}
Yes! As far as I saw, you have to refresh the page to get updated data. This is because you are using 'child_added' in your event listener which gets triggered only when a new child is added.
firebase.database().ref('tasks').on('child_added', function (data){})
You can just refer this and add value listeners to your function such that it retrieves data every time when the child gets changed.
https://firebase.google.com/docs/database/web/read-and-write#listen_for_value_events
EDIT
You can also delete a value using set() or update() method by passing null.
In this case, you can have a callback function. You can use this callback function to update your DOM.
Related
I am facing some issues while trying to pass JSON object as a parameter to function!
but on that function, while consoling log the data I am getting [object:object].
Here is my code:
function buildTable(data) {
var table = document.getElementById("myTable");
table.innerHTML = "";
for (var i = 0; i < data.length; i++) {
var row = `<tr class="item-id-${data[i].id}"> <td>${data[i].name}</td> <td>${data[i].audio_muted}</td> <td>${data[i].video_muted}</td> <td><button id="audio_handle" class="btn btn-primary" onclick="handleMembers('${data[i]}')">Video</button></td>`;
table.innerHTML += row;
}
}
function handleMembers(data) {
console.log("data = >", data); //= [object:object]
}
The issue is when I am calling handle function from the button inside template literal string I m getting [object:object] as output
Where I am going wrong?
I fixed a few points in the following snippet and added some HTML and some sample data:
// some sample data for illustration:
const data=[{id:1,name:"Harry",audio_muted:1,video_muted:1},{id:2,name:"Ron",audio_muted:1,video_muted:0},{id:3,name:"Hermiony",audio_muted:0,video_muted:1},{id:4,name:"Ginny",audio_muted:0,video_muted:1}];
const tbl=document.getElementById("myTable");
tbl.innerHTML = data.map((itm,i)=>`<tr class="item-id-${itm.id}"> <td>${itm.name}</td> <td>${itm.audio_muted}</td> <td>${itm.video_muted}</td> <td><button data-id="${i}" class="btn btn-primary">Video</button></td>`).join("\n")
tbl.addEventListener("click",ev=>{
if (ev.target.tagName==="BUTTON")
console.log("data = >", data[ev.target.dataset.id]) ; //= [object:object]
})
<table id="myTable"></table>
As #Quentin already mentioned you should not include JavaScript code within a template string. This gets too complicated to read and to maintain. Instead I used a delegated event-handler on the table itself to listen for the click on the button elements. By doing all this there was no need anymore for the two named functions.
Another thing that comes to my mind is: Never use element.innerHTML += ... inside a for loop as this will potentially become really slow. It is generally better to assemble the whole HTML string in one go and then assign it to the innerHTML property.
I think it's the wrong approach to do that. You should try to create the element using the DOM api and add the eventListener to the selected element, something like:
function buildTable(data) {
const table = document.getElementById("myTable");
for(let d of data) {
const tr = document.createElement("tr");
const td1 = document.createElement("td");
td1.textContent = d.name;
const td2 = document.createElement("td");
td2.textContext = d.audio_muted;
const td3 = document.createElement("td");
td3.textContent = d.video_muted;
const tdButton = document.createElement("button");
tdButton.classList.add("btn", "btn-primary");
tdButton.addEventListener("click", () => handleMembers(d));
tr.appendChild(td1)
tr.appendChild(td2)
tr.appendChild(td3)
tr.appendChild(tdButton);
table.appendChild(tr)
}
}
I'm trying to use javascript to retrieve the data from row.insertCell(0) unfortunately I don't believe I am setting up my this statement correctly so I am getting nothing back. I would appreciate some advice on this.
var cardTable = document.getElementById("cardBody");
card.forEach(item => {
let row = cardTable.insertRow();
let refNum = row.insertCell(0);
refNum.innerHTML = item.G1_Card_Ref;
let select = row.insertCell(1);
var sBtn = document.createElement('input');
sBtn.type = "button";
sBtn.className = "btn";
sBtn.style.color = "blue";
sBtn.setAttribute('onclick', 'editCard('this')');
sBtn.value = "Select";
select.appendChild(sBtn);
This is a temporary function I created to look at the data coming back from the table.
function editCard(CardRefNo) {
document.getElementById("ecForm").style.display = "block";
}
Try setting the onclick listener like this
sBtn.onclick = function() {
// do stuff with sBtn here, this is the new editCard function
console.log(sBtn)
document.getElementById("ecForm").style.display = "block";
}
I've created a website using google app script. In my website, I have a table but the values came from my spreadsheet.
Now, I have an editable table unfortunately, once I change the values in the row and the auto refresh triggered it will come back to normal and get the original values from the spreadsheet. Is there a way that once I've made some changes it will also change in the spreadsheet so when autorefresh triggered it will just be the same? Is it even possible?
<script>
document.addEventListener("DOMContentLoaded",function(){
google.script.run.withSuccessHandler(generateTable).getOnline();
google.script.run.withSuccessHandler(generateTable1).getStatus();
setInterval(() => {
document.getElementById("tablebody").innerHTML = "";
document.getElementById("tablebody1").innerHTML = "";
google.script.run.withSuccessHandler(generateTable).getOnline();
google.script.run.withSuccessHandler(generateTable1).getStatus();
google.script.run.withSuccessHandler(getOnline).generateTable();
google.script.run.withSuccessHandler(getStatus).generateTable1();
}, 20000); // run the function every 5 seconds
});
function generateTable(dataArray){
var tbody = document.getElementById("tablebody");
var tbody1 = document.getElementById("tablebody").innerHTML;
dataArray.forEach(function(r){
var row = document.createElement("tr");
var col1 = document.createElement("td");
col1.textContent = r[0];
var col2 = document.createElement("td");
col2.textContent = r[1];
var col3 = document.createElement("td");
col3.textContent = r[2];
row.appendChild(col1);
row.appendChild(col2);
row.appendChild(col3);
tbody.appendChild(row);
$(function(){
$("td").click(function(event){
if($(this).children("input").length > 0)
return false;
var tdObj = $(this);
var preText = tdObj.html();
var inputObj = $("<input type='text' />");
tdObj.html("");
inputObj.width(tdObj.width())
.height(tdObj.height())
.css({border:"0px",fontSize:"17px"})
.val(preText)
.appendTo(tdObj)
.trigger("focus")
.trigger("select");
inputObj.keyup(function(event){
if(13 == event.which) { // press ENTER-key
var text = $(this).val();
tdObj.html(text);
}
else if(27 == event.which) { // press ESC-key
tdObj.html(preText);
}
});
inputObj.click(function(){
return false;
});
});
});
});
}
</script>
<table>
<tr>
<th>Timestamp & Current TimeZone</th>
<th>Name</th>
<th>EID</th>
</tr>
<tbody id="tablebody">
</table>
Here's my code on .gs
function getOnline(){
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("UserLogins");
var data = ws.getRange(3, 1, ws.getLastRow()-1,3).getValues();
Logger.log(data);
return data;
}
I’m not sure of your use case, but it’s possible to embed an editable spreadsheet (see how here).
If you really want to do this with HTML + JavaScript for yourself, my approach would be:
Keep a version of what you know is in the backend. And another of the local changes, in different data structures.
Use functional paradigms to generate the table. Specially reactive frameworks (React, Vue.js, etc) will simplify your job a lot.
When “applying” changes, do not manually modify the backend data representation.
It should be kept as the data that the server sends you. Simply send the request and it will be updated automatically.
When the server sends a change that you had locally, remove it from the local changes. This consolidates the changes.
Also, you need to decide what happens when a cell gets updated while you are editing it.
Here is an example with vanilla JS on a single text input which can give you an idea (a lot of this could be handled by a reactive framework):
const elements = {
input: null,
stateView: null
}
const backend = {
input: 'value'
}
const local = {
}
function update() {
// Update backend with the backend information. Usually means a fetch
/* backend = ... */
if (local.input === backend.input) {
delete local.input
}
render()
}
function save() {
// Send a request updating the backend
// simulation
backend.input = local.input
update()
}
function localChange() {
local.input = elements.input.value
if (local.input === backend.input) {
delete local.input
}
render()
}
function render() {
input.value = 'input' in local ? local.input : backend.input
let state = ''
if ('input' in local) {
state += `Local: "${local.input}"<br/>`
}
state += `Backend: "${backend.input}"<br/>`
elements.stateView.innerHTML = state
}
// Setup events
document.addEventListener('DOMContentLoaded', function() {
elements.input = document.getElementById('input')
elements.input.addEventListener('keyup', localChange)
elements.input.addEventListener('change', save)
elements.stateView = document.getElementById('stateView')
update()
})
<input id="input" type="text" placeholder="Add you data here">
<p id="stateView"></p>
Notice that in this case if the user is editing and it’s the same I just ignore the local state. Also, because I’m not really making requests, everything is instantaneous.
I'm building an application in which there is a sign-up form. When I click submit, a new table row is dynamically created and the table is saved in local storage. Edit and Delete buttons are appended with the table row. When I click on Edit, data in td having classes name, mail, mob, add should populate name, email, mobile no. and address fields in the sign up form respectively. Furthermore when I submit, the changes should be updated in the same table row whose edit button I had clicked.
But instead of that, a new record is created. I'm attempting to pass the row id to the add function in my code and this is what I have done so far.
function save(){
var taskList = [];
$("#saveTable tbody").find("tr").each(function(){
var task = {};
var currentRow = $(this).closest("tr");
task.name = currentRow.find('.name').text();
task.mail = currentRow.find(".mail").text();
task.mob = currentRow.find(".mob").text();
task.add = currentRow.find(".add").text();
task.Country = currentRow.find(".country").text();
task.State = currentRow.find(".state").text();
taskList.push(task);
});
saveObject("tasks",taskList);
}
function saveObject(recordKey,jsObject){
var objectAsString = JSON.stringify(jsObject);
localStorage.setItem(recordKey,objectAsString);
}
function load(){
var taskList = loadObject("tasks");
for(var index=0; taskList && index<taskList.length; ++index){
this.add(taskList[index]);
}
}
function loadObject(recordKey){
var objectAsString = localStorage.getItem(recordKey);
return JSON.parse(objectAsString);
}
function add(taskObject,index){
if(index){
console.log(index);
var update = $('#saveTable tbody').find('tr').eq(index);
}
var newTR = $("<tr class='child'></tr>");
var newName = $("<td class='name'></td>");
var newMail = $("<td class='mail'></td>");
var newMob = $("<td class='mob'></td>");
var newAdd = $("<td class='add'></td>");
var newCountry = $("<td class='country'></td>");
var newState = $("<td class='state'></td>");
var edit = $("<input class='button_ed' type='submit' value='Edit'/>");
var del = $("<input class='button_del' type='submit' value='Delete'/>");
$(newTR).append($(newName).text(taskObject.name));
$(newTR).append($(newMail).text(taskObject.mail));
$(newTR).append($(newMob).text(taskObject.mob));
$(newTR).append($(newAdd).text(taskObject.add));
$(newTR).append($(newCountry).text(taskObject.Country));
$(newTR).append($(newState).text(taskObject.State));
$(newTR).append($(edit)).append($(del));
$("#saveTable tbody").append($(newTR));
$(edit).on("click",function myEdit(){
event.preventDefault();
if (this.value=="Edit") {
this.value="Save";
var ed = this.closest("tr");
$('#contact_name').val($(ed).children("td.name").text());
$('#contact_email').val($(ed).children("td.mail").text());
$('#contact_mob').val($(ed).children("td.mob").text());
$('#contact_address').val($(ed).children("td.add").text());
$('#contact_name').addClass("valid");
$('#contact_email').addClass("valid");
$('#contact_mob').addClass("valid");
$('#contact_address').addClass("valid");
//collect table row id in variable and pass it to add function
index = ed.rowIndex;
//console.log(index);
save();
}
});
$(del).on("click",function myDel(){
$(this).closest("tr").remove();
save();
});
}
I have a a table that has four columns ID,NAME,SURNAME and RECIPIENT
Each button has a different value that is equal to the number of the ID that is in the same line as the button. For example the value of the first button is 2, second button 3 last button 123 all the buttons have id=contact. Each time i press a button i store the value of that button in a variable with the name input. My source code for that is:
var input; //prepare var to save contact name/ PLACE outside document ready
$(function() {
// contact form animations
$('button[id="contact"]').click(function() {
input = $(this).val(); //set var contactName to value of the pressed button
$('#contactForm').fadeToggle();
})
$(document).mouseup(function (e) {
var container = $("#contactForm");
if (!container.is(e.target) // if the target of the click isn't the container...
&& container.has(e.target).length === 0) // ... nor a descendant of the container
{
container.fadeOut();
}
});
});
Then i want to user this variable to fetch some files that are corresponded with the current varibale from firebase database. In my firebase database i have a folder with the name files that has three supfolders that coresponds to the values of the three buttons that i have
In general lines I click one of the three buttons (let's say the button in the first column), I store the value of the button(so now the input value will be equal to 2). Then i drug all the information that is stored in firebase database from files/2/. I have implemented the source code for that but I am not getting any results and when i run inspect console i am not getting any errors. The source code is the following :
var databaseRef = firebase.database().ref().child(`files/${input}/`);
var tblUsers = document.getElementById('tbl_users_list');
var rowIndex = 1;
databaseRef.once('value',function(snapshot){
snapshot.forEach(function(childsnapshot) {
var childKey = childsnapshot.key;
var childData = childsnapshot.val();
//var urls = childData.url;
var row = tblUsers.insertRow(rowIndex);
var cellId = row.insertCell(0);
var cellName = row.insertCell(1);
var button = row.insertCell(2);
var itd = document.createElement('input');
itd.setAttribute("type","button");
itd.setAttribute("value","View");
itd.onclick=function () {
window.open(childData.url);
};
cellId.appendChild(document.createTextNode(childData.filename));
cellName.appendChild(document.createTextNode(childData.created));
button.appendChild(itd);
rowIndex = rowIndex+1;
//document.write(username);
})
});
If in the above source code change the line var databaseRef = firebase.database().ref().child(`files/${input}/`); replacing the variable i stored the value of the button in the first function with 2 , 3 or 123 i am getting results so it seems the the problem is there but i dont know what else to do.
Can someone please help me ?
Thanks in Regards
This appears to be a perfect use case for the .dataset or data- attribute. MDN has a great page showing how to use this. Basically, store the uid as <data-uid = "ach782bckhbc23whatever"> in your HTML on the <tr> or the <button> element an on click, use evt.target.dataset.uid or evt.target.parentElement.dataset.uid to get the row's uid to make your .get() firebase call.
<div id="user" data-id="1234567890" data-user="johndoe" data-date-of-birth>John Doe</div>
let el = document.querySelector('#user');
// el.id == 'user'
// el.dataset.id === '1234567890'
// el.dataset.user === 'johndoe'
// el.dataset.dateOfBirth === ''
el.dataset.dateOfBirth = '1960-10-03'; // set the DOB.
// 'someDataAttr' in el.dataset === false
el.dataset.someDataAttr = 'mydata';
// 'someDataAttr' in el.dataset === true