Add a new child in Firebase - javascript

So my situation is a bit different to issues found online.
I want the node Societies to be updated with a new child node Foot19 when the button is pressed. The context is that it is a list of school groups that when the user presses on the button to 'follow' them, the ID to that group is added to their personal data section.
So when they click addFootballSoc button Foot19 is added as a new child node to their specific Societies node.
The key values in the at the start of each sUsers node is equivalent to their authentication uid which is why I'm calling it using firebase.auth()
document.getElementById('addFootballSoc').onclick = function() {addFootball()};
function addFootball(){
var runUid = firebase.auth().currentUser.uid;
var searchRef = firebase.database().ref('sUsers');
var newSearchRef = searchRef.child(runUid);
var mm = newSearchRef.child('Societies')
mm.child.set('Foot19'){}
}
I want it to add a new child for each group they join so they can't overwrite either, for example if I were to add a 'Arts' group button
EDIT:
changed the function so the onclick works and it does now write to where I want,
however, if I were to add another child node alongside Foot19 it will delete Foot19 and replace it, I would use push but I don't want to have the unique key added to my nodes. How can I change this to ensure more nodes can be added?
document.getElementById('addFootballSoc').onclick = function() {addFootball()};
function addFootball(){
var runUid = firebase.auth().currentUser.uid;
var searchRef = firebase.database().ref('sUsers');
var newSearchRef = searchRef.child(runUid);
var mm = newSearchRef.child('Societies')
mm.child.set('Foot19'){}
}

You may be calling the function immediately addFootball() on page load before you have the uid back/resolved from Firebase or looks like you are handing .set the wrong type of data. Try this.
document.getElementById('addFootballSoc').addEventListener("click", function(evt) {
var runUid = firebase.auth().currentUser.uid;
if(runUid){
var searchRef = firebase.database().ref('sUsers');
var newSearchRef = searchRef.child(runUid);
var mm = newSearchRef.child('Societies')
mm.child.set({'Foot19':true});
} else {
console.log("no uid");
}
});

Solved it.
screengrab
The screen grab shows the entries being placed in the child node societies within the users ùid node. The extra entires ALT5 & ASN11 are where I changed the value on line 6 to test that new nodes would not be overwritten.
function addFootball(){
var runUid = firebase.auth().currentUser.uid;
var searchRef = firebase.database().ref('sUsers');
var newSearchRef = searchRef.child(runUid);
newSearchRef.child('Societies').update({
Foot19 : true
})
}

Related

How to create multiple todolists using a save button?

Below is a snippet of some of my code. Think a todo list on steriods. I am trying to create multiple Div elements that save to a page that contain a different list every time my "Save button is pressed. whats actually happening is that multiple divs are showing but the original div saved is the only one that gets updated with the list information(so like in a todo list when you click submit a new list item appears ive added a save button and an input field that the user can use to name their list and saves that list to a container but only one div gets updated). I know i'm almost there but ive been looking at this for a couple of hours now and cant quite figure it out. https://github.com/W33K5Y/TODO-PIRPLE
const saveButton = document.getElementById("submit-save");
const myLists = document.getElementById("my-lists");
const startNote = document.getElementById("start-note");
const listName = document.getElementById("new-list-name");
const myUl = document.getElementById("my-ul-lists");
// ! savebutton listener
saveButton.addEventListener("click", addNewTodo);
// ! make new html elements
const newTodoOl = document.createElement("ol");
const newTodoLi = document.createElement("li");
const listH1 = document.createElement("h4");
// ! =============== function for creating new todo ================================
function addNewTodo() {
const todoDiv = document.querySelector(".todo-container");
const todos = document.querySelectorAll(".todo-item");
todos.forEach(function(todo) {
createLi(todo);
});
listName.value ? listH1.innerText = listName.value : listH1.innerText = "My List";
newTodoDivWrap.classList.add("new-todo-div");
newTodoDivWrap.appendChild(listH1);
newTodoDivWrap.appendChild(newTodoOl);
myLists.appendChild(newTodoDivWrap);
todoReset(todoDiv, startNote);
startLoginSignUpNoneLobbyFlex();
}
// todo function to go in above that removes all of whats in the tido-container
function todoReset(div, lobbyDiv) {
lobbyDiv.remove();
div.firstElementChild.innerHTML = "";
}
function createLi(todo) {
// ! Create LI
const newTodo = document.createElement('li');
newTodo.innerText = todo.innerText;
newTodo.classList.add("todo-saved-item");
newTodoOl.appendChild(newTodo);
}
I think the following is why it's not working as you intended:
const newTodoOl = document.createElement("ol");
const newTodoLi = document.createElement("li");
const listH1 = document.createElement("h4");
Remember that javascript creates references, so when you do something like this—newTodoDivWrap.appendChild(listH1)—you don't add a new element, you only add a reference to said element.
It's the same as if you had two objects.
var a = {'name': 'Anette'}
var bbbb = a // creates a reference, not a new object.
bbbb.name = 'Bjorn'
console.log(a.name) // Bjorn
So create new elements inside the method, instead of creating and calling public ones.
Also, comments like this are so unnecessary:
function createLi(todo) {
// ! Create LI
You had a method name that perfectly explains what it does. You don't need to comment that. Start making it a habit of naming variables or method to explain what's going on—you're already doing that (ex. startLoginSignUpNoneLobbyFlex)—so you don't have to use comments. Comments are useless, unless it's for documentation.
You have to move
const newTodoOl = document.createElement("ol");
const newTodoLi = document.createElement("li");
const listH1 = document.createElement("h4");
into the addNewTodo function. That way each iteration produces a brand new List
Rickard pointed me in the right direction :)

How to document merge a parent record and all of its child records

I'm creating a document merge (mail merge) from Google App Maker to a Google Document template. I can do so successfully when merging one single record, but how do you merge several records into the one document?
I have an purchase_orders parent record which has several purchase_order_line_items child records but I can't seem to get all of these records into a single document merge.
A similar question (Document Merge with Google App Maker) was asked by by Johan W with a comprehensive answer by Markus Malessa and Pavel Shkleinik (thank you!). However, it only caters for cases when you are merging one single record.
I have tried to build on their answer by using a second for loop to get the data of all associated child records. The script runs but only seems to merge the first child record; not all of them.
Here is an example of the server-side code I've tried to use:
function Export(key, key2) {
// Get the parent record by its key, which was passed by the first parameter above
var record = app.models.Purchase_Orders.getRecord(key);
// Get the first child record by its key, which was passed by the second parameter above
var childRecord = app.models.Purchase_Order_Line_Items.getRecord(key2);
// Get the Google Document which will be used as a template for this merge
var templateId = '1Xbt8camqHJYrhBnx0a6G2-RvTvybqU0PclHifcdiLLA';
//Set the filename of the new merge document to be created
var filename = 'Document for Customer ' + new Date();
//Make a copy of the template to use as the merge document
var copyFile = DriveApp.getFileById(templateId).makeCopy(filename);
//Get the Google Docs ID of the newly created merge document
var copyDoc = DocumentApp.openById(copyFile.getId());
var copyBody = copyDoc.getBody();
// Replace the field names in the template with the field data from the parent record
var fields = app.metadata.models.Purchase_Orders.fields;
for (var i in fields) {
console.log(i);
var text = '<<' + fields[i].name + '>>';
var data = record[fields[i].name];
if (data !== null) {
copyBody.replaceText(text, data);
} else {
// do nothing
}
}
// Replace the field names in the template with the field data from the child records
childFields = app.metadata.models.Purchase_Order_Line_Items.fields;
for (i in childFields) {
console.log(i);
var childtext = '<<' + childFields[i].name + '>>';
var childdata = childRecord[childFields[i].name];
if (childdata !== null) {
copyBody.replaceText(childtext, childdata);
} else {
// do nothing
}
}
}
How can I improve my code so that all associated child records are merged into a single document?
How can I set up my Google Document template to cater for any number of child records?
Rather than passing in the child record key via a second parameter, I would suggest just passing in the parent key and then changing your function as follows:
function Export(key) {
// Get the parent record by its key, which was passed by the first parameter above
var record = app.models.Purchase_Orders.getRecord(key);
// Get the first child record by its key, which was passed by the second parameter above
var childRecords = record.Purchase_Order_Line_Items;
// Get the Google Document which will be used as a template for this merge
var templateId = '1Xbt8camqHJYrhBnx0a6G2-RvTvybqU0PclHifcdiLLA';
//Set the filename of the new merge document to be created
var filename = 'Document for Customer ' + new Date();
//Make a copy of the template to use as the merge document
var copyFile = DriveApp.getFileById(templateId).makeCopy(filename);
//Get the Google Docs ID of the newly created merge document
var copyDoc = DocumentApp.openById(copyFile.getId());
var copyBody = copyDoc.getBody();
// Replace the field names in the template with the field data from the parent record
var fields = app.metadata.models.Purchase_Orders.fields;
for (var i in fields) {
console.log(i);
var text = '<<' + fields[i].name + '>>';
var data = record[fields[i].name];
if (data !== null) {
copyBody.replaceText(text, data);
} else {
// do nothing
}
}
// Replace the field names in the template with the field data from the child records
var childFields = app.metadata.models.Purchase_Order_Line_Items.fields;
var table = [];
var tableheader = [];
for (i in childFields) {
console.log(i);
tableheader.push(childFields[i].displayName);
}
table.push(tableheader);
for (i in childRecords) {
var data = [];
for (var j in childFields) {
data.push(childRecords[i][childFields[j].name]);
}
table.push(data);
}
copyBody.appendTable(table);
The table building is based on a 2D array and the documentation is here https://developers.google.com/apps-script/reference/document/table. But you will also need to remove your prebuilt table in favor of just appending a table instead. This way you are not dependent on the quantity of child records being fixed like they currently are in your document template. Also, the variable for childRecords may or may not work, I have not tested this since I am unsure if prefetch works in conjunction with .getRecord(key). This may require some additional testing but hopefully this will provide enough guidance.
Thought I would add this as an alternative. Lets say you keep your table but remove all the rows with exception for the header row then you could still use DocumentApp service to add your rows to the table like so:
var tableheaderfieldnames = ['Quantity_for_PO', 'Inventory_Item.id', 'Unit_Price']; //set a fixed table header with the field names, uncertain if the table header for the related inventory item will work or not
var table = copyBody.getTables()[0];
for (i in childRecords) {
var row = table.appendRow();
for (var j in tableheaderfieldnames) {
row.appendTableCell(childRecords[i][tableheaderfieldnames[j]]);
}
}
Keep in mind that AM does not allow you to use FK references, so for your inventory item that appears to use a fk field you may need to tinker around with setting the proper name reference for when you are trying to fill in the item in your table.

Firebase checking if child exists, pull and update data if exists javascript

I am trying to count the number of times a certain key word (city) is searched. I have stored the data so for each new input I want to see if the child exists and if so pull the numSearched child and add 1. I can see if it exists but I can add on.
My database is a simple
file:///Users/paulamactavish/Downloads/practicaltravel-63ff1-export.json
var cityToCheck = city;
var cityRef = firebase.database().ref('travelPlans');
cityRef.once('child_added', function(snapshot) {
snapshot.forEach(function(child) {
if (snapshot.val().city==cityToCheck) {
var myJSON = JSON.stringify(snapshot);
var citySearch = JSON.parse(myJSON)
numSearchCounter = (citySearch.numSearched);
numSearchCounter++
child.ref().update({
numSearched = numSearchCounter
});
};
});
});
I have looked over lots of other responses but I cant seem to make it work as a whole. Thanks in advance!

Updating only some of object

I have a table in my database that I would like to be able to change some of the sections and keep the other functions as they were however it is updating the table so that the two are changed but the other 3 become empty. is there any way to change this?
$(function Tuesday(){
// CREATE A REFERENCE TO FIREBASE
var dateTuesdayRef = new Firebase('https://shiftsapp.firebaseio.com/roster');
// REGISTER DOM ELEMENTS
var date2Field = $('#date2Input');
var emp1put2Field = $('#emp1Input2');
var emp2put2Field = $('#emp2Input2');
var emp3put2Field = $('#emp3Input2');
var emp4put2Field = $('#emp4Input2');
var emp5put2Field = $('#emp5Input2');
var enter2Field = $('#enter2');
// LISTEN FOR KEYPRESS EVENT
enter2Field.keypress(function (e) {
if (e.keyCode == 13) {
//FIELD VALUES
var dateTuesday = date2Field.val();
var emp1put2 = emp1put2Field.val();
var emp2put2 = emp2put2Field.val();
var emp3put2 = emp3put2Field.val();
var emp4put2 = emp4put2Field.val();
var emp5put2 = emp5put2Field.val();
var enter2 = enter2Field.val();
//SAVE DATA TO FIREBASE AND EMPTY FIELD
var obj2 = {};
obj2[dateTuesday] = {
emp1:emp1put2,
emp2:emp2put2,
emp3:emp3put2,
emp4:emp4put2,
emp5:emp5put2
}
dateTuesdayRef.child(dateTuesday).set({emp1:emp1put2,
emp2:emp2put2,
emp3:emp3put2,
emp4:emp4put2,
emp5:emp5put2});
enter2Field.val('');
}
});
});
Get the values for the things you want to stay the same from your server, and feed them back when you set the object. You could also use a custom function to autofill undefined values like I have suggested.
From the table at the top of the Firebase guide on saving data:
set( ): Write or replace data to a defined path, like messages/users/
update( ): Update some of the keys for a defined path without replacing all of the data
So if you call update() instead of replace, it will only change the values of the properties you pass in and leave other values unmodified.

How insert,update,delete value of an XML element with Extendscript scriptui

I am learning extendscript for scripting adobe illustrator.It is very difficult for me to write xml related parsing.
My problem statement is given below:- "I have taken three text boxes namely name,city and country."name" is a unique key.when i click ok button the data must be saved in xml if name does not exist else update the previous name with out creating duplicate.All the names in xml file are displayed in list box.The date of particular name could be deleted by remove button.which will remove data in selected item of list box.
The code i tried to do is:-
var myWindow = new Window ("dialog", "Form");
var txt1 = myWindow.add ("edittext");//name unique
var txt2 = myWindow.add ("edittext");//city
var txt3 = myWindow.add ("edittext");//country
var btn=myWindow.add ("button", undefined, "OK");
btn.onClick = function () {
for (i=0;i<numberofnamesinxml;i++)//coding required
{
if(txt1.text!=xmlname[i]) // to verify name not there since it is like primary key
xmlFile.open("a");
xmlFile.write(root.toXMLString());
xmlFile.copy ('C:/data.xml');
xmlFile.close();
//myList refresh
}
}
var myList = myWindow.add ("listbox");
for (i=0;i<numberofnamesinxml;i++)//coding required
{
config='C:/data.xml';
config.open("r");
data= xmlname[i] //here i need to set data to
config.close();
myList.add ("item", data);
}
var btn1=myWindow.add ("button", undefined, "remove");
btn1.onClick = function () {
myList.remove (myList1.selection[i]);
//xml data having this list name must be removed
}
myWindow.show ();
Please kindly help me.
This should not be considered a full answer. I still post it because it might help finding one.
This is what I tried to write as an answer. The read/write part works but the checking of an element exists fails.
if the child is not an exact match, xml.contains(xml) will not return true.
var path = '~/Desktop/test.xml';
var xmlfile = File(path);
if (!xmlfile.exists) {
$.writeln('xml file does not exist. Creating new one');
xmlfile = new File(path);
xmlfile.open('w');
xmlfile.write('<Root></Root>');
xmlfile.close();
}
xmlfile.open('r');
xmlcontent = xmlfile.read();
xmlfile.close();
//$.writeln(xmlcontent);
var xml = new XML(xmlcontent);
// here the problems start
// the check is only working for known elements
var child = new XML('<name data="bob"></name>');
if (xml.contains(child)) {
child.#data = 'jim';
$.writeln('A child called "name" exists. Update');
xml.replace('name', child);
} else {
$.writeln('no child called "name" exists. Append');
child.#data = 'bob';
xml.appendChild(child);
}
xmlfile.open('w');
xmlfile.write(xml.toXMLString());
xmlfile.close();
My real answer is:
Use JSON instead.

Categories