Create basic library firebase error - javascript

I have developed some applications using Firebase. Over time, I realized that I am repeating a lot of unnecessary code and decided to create a small library to help me increase productivity. Right at the beginning, I tried to create this object in Javascript:
read.childRoot = function(att) {
var acessChildRoot = firebase.database().ref("root/");
acessChildRoot.once('value').then(function(snapshot) {
alert(snapshot.child("nome").val());
});
}
And I tried to access through this line of code:
alert(read.childRoot("nome"));
So I was able to read the reference I wanted, but the first return was the undefined value. How can I filter this value and just display the value I really want to see?

It seems that you want to wait for the first value to be set on a node.
In that case, I recommend using this snippet (from my gist):
var listener = ref.on('value', function(snapshot) {
if (snapshot.exists()) {
console.log('Value is now '+snapshot.val());
ref.off('value', listener);
}
});

Related

Filtering smart-table on transformed data

Apologies in advance, I am not a very experienced JS programmer, and even less so with AngularJS, but am trying to make some improvements on a legacy codebase that is using Angular 1.5.9 and Smart Table to display information from a database.
I've read all about st-search and st-safe-src vs. st-table, etc., but I am having trouble filtering on my table, since there are transformations happening on the underlying data before it gets displayed. The ng-repeat variable in my case is transaction, which has various fields to hold information for that transaction, such as payee, which holds a UUID pointing to another database document. In the app, we display the name of that payee using a function from another controller (dbCtrl.getPayeeName()), but the underlying data is the UUID. Thus, when attempting to filter with Smart Table, it does not filter on the displayed names, and only works when entering the UUID into the filter field.
A small example (with lots of the intervening bits removed, but hopefully enough to demonstrate my confusion):
<div class="account"
st-table="displayedTransactions"
st-safe-src="transactions"
disable-ng-animate>
...
<div><input st-search="payee" placeholder="search for payee" class="input-sm form-control" type="search"/></div>
...
<div ng-repeat="transaction in displayedTransactions track by transaction.id">
...
<div class="account__td" transaction-field-focus-name="payee">
{{dbCtrl.getPayeeName(transaction.payee)}}
</div>
...
</div>
Is there a relatively simple way to get the filtering to work for a situation like this where the displayed data is different than the underlying data? From what I'm reading in the documentation, it sounds like this might require some sort of custom plugin, which sounds like more work, but I could maybe figure out. I just wanted to see if I'm missing something obvious before heading down that route.
Circling back on this, I was able to accomplish what I needed using the st-set-filter attribute as described in the Strict mode filtering section of the documentation, as well as this helpful answer from laurent back in 2014.
Essentially, I added st-set-filter="transactionFilters" to my table in my html template, as well as input tags with st-search="prop_to_search" attributes. Then in my applications module (I put this in one of the controllers, not sure if that's totally correct) I defined a filter such as below. expression gets passed into this code as an object with string values for whatever you typed in, so if you had three search fields, you'd get an object like:
{
"prop_to_search1": "value1",
"prop_to_search2": "value2",
"prop_to_search3": "value3"
}
In the filter function, I wrote an if block for each property that could come in, and then do my custom transformations and pattern matching there. This way, I have full control over the eventual matching, and rather than searching on the UUID, I can do something like $rootScope.dbCtrl.getPayeeName(uuidToSearch) instead. This is all acceptably performant in my use case, but I could probably cache those database lookups as a potential optimization.
angular.module('myApp').filter('transactionFilters', function($rootScope, $filter){
return function(array, expression){
// console.log(`expression is: ${JSON.stringify(expression, null, 4)}`)
return array.filter(function(val, index){
// in this function's context, `expression` is an object with
// the active filters entered in each field; `val` is the data
// representation of each row of the table
// if this function returns true, the row will match and smart-table
// will show it, otherwise it will be hidden
// define matches all at once, check them all, then return
// a big logical AND on all of them
let accountMatch = true;
let payeeMatch = true;
let categoryMatch = true;
if (expression.account) {
uuidToSearch = val.account // this is the account UUID
strToSearch = $rootScope.dbCtrl.getAccountName(uuidToSearch).toLowerCase(); // convert to an account name (we could memoize this to improve performance)
if (strToSearch) {
// if the account had a name (it always should, but catch in case)
// then check if the row's account contains the text entered in the filter field
accountMatch = strToSearch.includes(expression.account.toLowerCase());
} else {
accountMatch = false;
}
}
if (expression.payee){
if (val.payee) {
uuidToSearch = val.payee
strToSearch = $rootScope.dbCtrl.getPayeeName(uuidToSearch).toLowerCase();
}
if (strToSearch) {
payeeMatch = strToSearch.includes(expression.payee.toLowerCase());
} else {
payeeMatch = false;
}
}
if (expression.category) {
if (val.category) {
strToSearch = $rootScope.dbCtrl.getCategoryName(val.category, val.date).toLowerCase()
categoryMatch = strToSearch.includes(expression.category.toLowerCase())
} else {
categoryMatch = false;
}
}
return (
accountMatch &&
payeeMatch &&
categoryMatch
)
})
}
});

Overwriting existing object properties

I am having trouble with two small blocks of code and understanding why one works and one doesn't.
I have an array of 'tasks'.
When a user updates a task, I need to update the AuditLog, to show the update.
I have two blocks of code, first one works, second one doesn't.
1st block - when I view the updated task, it shows the updated log.
2nd block - when I view the updated task, the log is not updated.
I suspect that it is something to do with the way I am referencing, assigning things.
This block correctly updates the "task" and viewing it shows the updated "audit log".
//update task with server response 'a'
this.updateTask(task).subscribe(a => {
let updatedTask = initializeTask(a);
task.auditLog = updatedTask.auditLog;
});
Then I thought I could simplify the code a bit...
but when using this block, when I view the task, it does not show the updated log.
(I should mention that printing 'intializeTask(a)' works correctly and prints the updated log values, so it's not to do with that).
//update task with server response 'a'
this.updateTask(task).subscribe(a => {
task = initializeTask(a);
});
I feel like I may be missing something fundamental in the way JavaScript references/assigns variables etc. Perhaps someone can shed some light on it.
Thanks in advance!
PS: initializeTask simply ensures that nothing is left undefined and that dates are formatted correctly:
export function initializeTask(t): Task {
t.subject = t.subject || '';
t.startTime = initDate(t.startTime);
t.state = t.state || 'Published';
t.createdBy = t.createdBy || '';
if (t.auditLog) {
t.auditLog.forEach(d => {
d.createdOn = initDate(d.createdOn);
});
}
return t;
}

How to delete/remove nodes on Firebase

I'm using Firebase for a web app. It's written in plain Javascript using no external libraries.
I can "push" and retrieve data with '.on("child_added")', but '.remove()' does not work the way it says it should. According to the API,
"Firebase.remove() -
Remove the data at this Firebase location. Any data at child locations will also be deleted.
The effect of the delete will be visible immediately."
However, the remove is not occurring immediately; only when the entire script is done running. I need to remove and then use the cleared tree immediately after.
Example code:
ref = new Firebase("myfirebase.com") //works
ref.push({key:val}) //works
ref.on('child_added', function(snapshot){
//do stuff
}); //works
ref.remove()
//does not remove until the entire script/page is done
There is a similar post here but I am not using Ember libraries, and even so it seems like a workaround for what should be as simple as the API explains it to be.
The problem is that you call remove on the root of your Firebase:
ref = new Firebase("myfirebase.com")
ref.remove();
This will remove the entire Firebase through the API.
You'll typically want to remove specific child nodes under it though, which you do with:
ref.child(key).remove();
I hope this code will help someone - it is from official Google Firebase documentation:
var adaRef = firebase.database().ref('users/ada');
adaRef.remove()
.then(function() {
console.log("Remove succeeded.")
})
.catch(function(error) {
console.log("Remove failed: " + error.message)
});
To remove a record.
var db = firebase.database();
var ref = db.ref();
var survey=db.ref(path+'/'+path); //Eg path is company/employee
survey.child(key).remove(); //Eg key is employee id
Firebase.remove() like probably most Firebase methods is asynchronous, thus you have to listen to events to know when something happened:
parent = ref.parent()
parent.on('child_removed', function (snapshot) {
// removed!
})
ref.remove()
According to Firebase docs it should work even if you lose network connection. If you want to know when the change has been actually synchronized with Firebase servers, you can pass a callback function to Firebase.remove method:
ref.remove(function (error) {
if (!error) {
// removed!
}
}
As others have noted the call to .remove() is asynchronous. We should all be aware nothing happens 'instantly', even if it is at the speed of light.
What you mean by 'instantly' is that the next line of code should be able to execute after the call to .remove(). With asynchronous operations the next line may be when the data has been removed, it may not - it is totally down to chance and the amount of time that has elapsed.
.remove() takes one parameter a callback function to help deal with this situation to perform operations after we know that the operation has been completed (with or without an error). .push() takes two params, a value and a callback just like .remove().
Here is your example code with modifications:
ref = new Firebase("myfirebase.com")
ref.push({key:val}, function(error){
//do stuff after push completed
});
// deletes all data pushed so far
ref.remove(function(error){
//do stuff after removal
});
In case you are using axios and trying via a service call.
URL: https://react-16-demo.firebaseio.com/
Schema Name: todos
Key: -Lhu8a0uoSRixdmECYPE
axios.delete(`https://react-16-demo.firebaseio.com/todos/-Lhu8a0uoSRixdmECYPE.json`). then();
can help.

Accessing custom defined variable/object in javascript in for...in loop

Let me explain the whole problem. I was trying to avoid writing this as it could be a long explanation.
I am working with a tool called Lectora. This is an authoring tool which generates HTML pages and SCORM compliant packages to be deployed to the LMS.
When I insert a button in the Lectora, the code that is generated is something like this...
<script>
// some code here...
button63 = new ObjButton('button63', ....);
button63.setImages('images/btn_next_en.png','images/btn_next_en.png','images/btn_next_mouseover_en.png');
button63.build();
button64 = new ObjButton('button64', ....);
button64.setImages('images/btn_back_en.png','images/btn_back_en.png','images/btn_back_mouseover_en.png');
button64.build();
button65897 = new ObjButton('button65897', ....);
button65897.setImages('images/btn_submit_en.png','images/btn_submit_en.png','images/btn_submit_mouseover_en.png');
button65897.build();
// some more code here...
</script>
So I try to write:
<script>
var arr_buttons = [];
for(var i in window)
{
if(window[i] typeof object)
{
if(window[i] != null)
{
if(window[i] instanceof ObjButton)
{
arr_buttons.push(i);
}
}
}
}
alert(arr_buttons.length); // gives me 845 in IE11 and it gives me 44 in IE8
</script>
And when I check the contents of arr_buttons in console or by any other method, I do not find button65897 of any other button object in it. Which makes me think that it is not iterated at all!! This is my problem.
ObjButton is a Lectora created javascript object and I cannot edit it.
Now, I have set the language option in another variable and depending on the variable value for language, I want to get hold of the object 'button65897' and change its images. Now I am finding it difficult to get hold of 'button65897' in IE8.
Isn't there any way to get hold of the object 'button65897' in IE8?

This object constructor is preventing my script from running

I'm working on a project (creating a browser based check list). One of my goals has been to write every piece by hand without a library like jquery or a mysql database.
Currently I'm trying to create on object for managing tasks. I'm not finished the primary function, but everything is closed, and I don't detect any errors. Furthermore, I'm haven't iterated it or called it's functions yet, so there's nothing to reference it yet. When I comment it out, the script runs normally.
I've included the xml request links up above and tested them successfully in a separate portion of the script.
I'm testing in firefox.
I'm writing this in SciTE
Here's the code:
function Task(name,node,childNode,divClass,content,onclick)
{
function retrieveTask(node,childNode)
{
var taskArray = [];
taskArray.push(xmlDoc.getElementsByTagName(name)[node].childNodes[childNode].nodeValue;)
taskArray.push(xmlDoc.getElementsByTagName(description)[node].childNodes[childNode].nodeValue;)
taskArray.push(xmlDoc.getElementsByTagName(complete)[node].childNodes[childNode].nodeValue;)
return taskArray;
}
function displayTask(name,content)
{
var task = retrieveTask(node,childNode);
var clickDiv = "";
formatDiv(name,"task",task[1],clickDiv);
task[2] === true ? formatDiv(name+1,"incompleteBox"," ",clickDiv) : formatDiv(name+1,"completeBox","O",clickDiv);
}
}
If anyone could give me some insight or tips that would be awesome. This isn't homework, it's a hobby, so it's a self teaching process.
...childNodes[childNode].nodeValue;)
should be );

Categories

Resources