Firebase get full path of reference URL in dataSnapshot (javascript API) - javascript

Say I have the following:
var firebaseARef = new Firebase("http://this.is.my/firebase/url/A/reference")
var firebaseBRef = new Firebase("http://this.is.my/firebase/url/B/reference")
When I define my .on() functions, I'd like to specify a single handler, and then do all of the handling in one place in my code, rather than having to define the functions inline with the .on() definition. To illustrate:
var handleAllFirebaseStuff = function(dataSnapshot){
var name = dataSnapshot.name(); //PROBLEM HERE: returns "reference", no way to distinguish!
switch(name){
case "http://this.is.my/firebase/url/A/reference": //How do I get this full reference from dataSnapshot?
/* do stuff for A reference */
case "http://this.is.my/firebase/url/B/reference": //How do I get this full reference from dataSnapshot?
/* do stuff for B reference */
default:
break;
}
}
firebaseARef.on('value', handleAllFirebaseStuff);
firebaseBRef.on('value', handleAllFirebaseStuff);
The problem is dataSnapshot.name() will only return "reference" in both cases, making it impossible to distinguish between the two references in the switch/case statement!
I'm certain that dataSnapshot contains this information somewhere, but I have yet to uncover it in any convenient fashion. Exploring the dataSnapshotobject in the console, I find that there is an object buried within called path that contains (among other things) an array, using the example above, that would contain ["firebase", "url", "A", "reference"], but there is no easy way to access it.
If I had access to that array, I could rebuild the URL or find a more convenient way to handle the switch/case statement. I think a full string of the reference would be more appropriate as an easily accessible value from dataSnapshot.

To get back from a Snapshot to the full URL, you do:
snapshot.ref().toString()
The toString part is somewhat counter-intuitive. I often find myself having to test it, to see if that's indeed the way to go.
hint It would be nice if there was also a more explicit getUrl method hint
UPDATE:
With recent SDK versions ref is no longer a function, so you'll have to use:
snapshot.ref.toString();

Related

javascript How do I "dereference" a variable's content for use as a variable name?

I want to reduce the I/O overhead of fetching information from the server using XMLHttpRequest() or ActiveXObject(), as appropriate, by making a general-purpose function for doing the fetch which then stores the fetched data using sessionStorage.<variable>. The trouble is, I don't know in advance what the variable names all are, and I intentionally don't want to know.
I was thinking that if there is some way to "dereference" a variable, like we can easily do in BASH, for example, this would be trivial. For example, if the fetched data was in newData, and the name of the file it was fetched from is in dataFile, and if the dereference syntax was, say $(<variableName>), then one could write code like this to store and fetch the data:
//Store the data:
sessionStorage.$(dataFile) = newData;
//Fetch the data:
var storedData = sessionStorage.$(dataFile);
Get it? ... OK, now, how do I ACTUALLY do this?!
...The only other way around this I can see is VERY clumsy - make arrays, one with name, another with values - there MUST be an easier way! TIA.
As always, it is good to visit the docs first. There you can see, that sessionStorage (like localStorage or Map) has no properties at all (except a hidden property pointing to internal memory but thats another thing), but rather makes the data available through its get or set methods:
sessionStorage.set("a name", "a value");
However the session/localStorage provides also global getters/setters, so in theory one can do:
sessionStorage.name = "value";
If the keys name is dynamic one could use bracket notation:
sessionStorage[aName] = aValue;
However, they havent it even mentioned in the docs, so this feature is neither widely supported nor a good coding style.
Try this. Not exactly sure I followed your question clearly but I would try this if you are having issues using the variable name as string within your other code.
var_param = GET_YOUR_VAR_SOMEHOW; // strip your params as needed
let f1 = { getVarName:var_param.toString()} // object = to f2
let f2 = 'getVarName'; // string = to f1 key
var storedData = sessionStorage.$(f1[f2]); // result of f1[f2] should be your incoming var string, de-referenced from any content.

Why is this parameter not used?

In Backbone 1.1.2, at line 279
// Return a copy of the model's `attributes` object.
toJSON: function(options) {
return _.clone(this.attributes);
},
options is clearly not used, so why have it there at all. It is just wasted memory.
What am I missing here?
Per comment here is one way of calling this code -so why pass options when it will not be used?
toJSON: function(options) {
return this.map(function(model){ return model.toJSON(options); });
},
It doesn't waste memory, since the argument would have to be available as arguments[0] anyway (either options is a function call and the vm has to do it for side-effects anyway, or it's just an object and so it's just a reference).
It also serves as a document reference to what superclasses can implement.
Since JS is using prototypes for its object orientation, if you create a toJSON function in one of your superclasses, it'll be used instead.
There's no functional reason for including that in the Model.toJSON signature -- it is strictly for developers' benefit.
From the link that #t.niese uncovered:
Morning #aoboturov! Thanks for pointing this out. It's actually intentional and is meant to remind you that collection.toJSON(options) passes along the options argument to each of its models by default. See #1222 and #1098 for details.
(Note that the referenced #1222 is basically just a dupe, and #1098 is where they added the feature in the first place.)
In other words, the parameter is put there for the sake of clarity for developers who may want to override the Model.toJSON implementation. The collection passes along the original Backbone.sync call's options object, since some implementations of Model.toJSON might want to use it.
Including that options parameter in the signature doesn't affect memory usage at all (even if it did, the effect would be miniscule), since the Collection.toJSON implementation passes that options object as an argument, either way.

When should I prefer a clone over an reference in javascript?

at the moment I'm writing a small app and came to the point, where I thought it would be clever to clone an object, instead of using a reference.
The reason I'm doing this is, because I'm collecting objects in a list. Later I will only work with this list, because it's part of a model. The reference isn't something I need and I want to avoid having references to outside objects in the list, because I don't want someone to build a construct, where the model can be changed from an inconsiderate place in their code. (The integrity of the information in the model is very important.)
Additional I thought I will get a better performance out of it, when I don't use references.
So my overall question still is: When should I prefer a clone over an reference in javascript?
Thanks!
If stability is important, then clone it. If testing shows that this is a bottleneck, consider changing it to a reference. I'd be very surprised if it is a bottleneck though, unless you have a very complicated object which is passed back and forth very frequently (and if you're doing that it's probably an indication of a bad design).
Also remember that you can only do so much to save other developers from their own stupidity. If they really want to break your API, they could just replace your functions with their own by copying the source or modifying it at runtime. If you document that the object must not be changed, a good developer (yes, there are some) will follow that rule.
For what it's worth, I've used both approaches in my own projects. For small structs which don't get passed around much, I've made copies for stability, and for larger data (e.g. 3D vertex data which may be passed around every frame), I don't copy.
Why not just make the objects stored in the list immutable? Instead of storing simple JSON-like objects you would store closures.
Say you have an object with two properties A and B. It looks like that:
myObj = {
"A" : "someValue",
"B" : "someOtherValue"
}
But then, as you said, anyone could alter the state of this object by simply overriding it's properties A or B. Instead of passing such objects in a list to the client, you could pass read-only data created from your actual objects.
First define a function that takes an ordinary object and returns a set of accessors to it:
var readOnlyObj = function(builder) {
return {
getA : function() { return builder.A; },
getB : function() { return builder.B; }
}
}
Then instead of your object myObj give the user readOnlyObj(myObj) so that they can access the properties by methods getA and getB.
This way you avoid the costs of cloning and provide a clear set of valid actions that a user can perform on your objects.

javascript Object.assign() functionality

I'm wanting to directly update the object referred by a function argument from within the scope of that function. An example:
var thisObj = { "val" : "original value" };
function modFunc(objRef) {
objRef = { "val" : "modified" };
console.log(objRef); // { "val" : "modified" }
}
console.log(thisObj); // { "val" : "original value" };
I understand why this happens, and I realize that I could have used
objRef.val = "modified";
within modFunc to perform the modification. For reasons specific to my project though, I would like to be able to accomplish something like:
function modFunc(objRef) {
objRef.self = { "val" : "modified" }; // Of course this will not work,
// but is there an Object property or method that allows one to access
// the actual memory pointer being referenced by the variable?
}
where I can specify that I want to directly modify thisObj to reference the new object that I instantiate within modFunc. Is this possible? I know there are tools like Object.assign() that I could use to do this but it's not supported universally, or library tools like bind() that I could use if I imported the library, but it just seems like there might be some native syntax that would allow me to do this and I just haven't been able to find it?..
I've spent some time looking, otherwise I try not to ask questions like this. I also know there are other similar posts to this one, but nothing exactly like what I'm asking and I don't have the 'reputation' here to be able to respond directly to posts etc. so I didn't see an easy way to focus the discussion. Anyway, thanks for any help!
What you're asking for is, essentially, a call-by-reference mechanism, or the ability to explicitly create a reference to a variable. In JavaScript, that's not possible. You can (as you note) pass around references to objects and use those to modify object property values (and to add and remove properties, even), but that's not quite the same thing.
This would be true assignment by reference which javascript doesn't support. It only supports the false, misunderstood kind of assignment by reference.
since you cant deal with references, you can simply make objRef a global variable, and not pass it as an arg at all. then you're updating the original object.

Javascript - Passing arguments to function

I've always passed arguments to a function like so:
setValue('foo','#bar')
function setValue(val,ele){
$(ele).val(val);
};
Forgive the silly example. But recently I have been working on a project that has some functions that take a lot of arguments. So I started passing the arguments through as an object (not sure if that's the correct way to put that), like so:
setValue({
val:'foo',
ele:'#bar'
});
And then in the function:
function setValue(options){
var value = options.val;
var element = options.ele;
$(element).val(value);
};
My question is, is there a better way to do that? Is it common practice (or okay) to call these 'options'? And do you typically need to 'unpack' (for lack of a better term) the options and set local vars inside the function? I have been doing it this way in case one of them was not defined.
I'm really looking to not create bad habits and write a bunch of code that is ugly. Any help is appreciated and + by me. Thanks.
I do the exact same thing, except I don't declare a new variable for each option inside the function.
I think options is a good name for it although I shorten it to opts.
I always have a "default" object within the function that specify default values for each available option, even if its simply null. I use jQuery, so I can just use $.extend to merge the defaults and user-specified options like this: var opts = $.extend({}, defaults, opts);
I believe this is a great pattern. I've heard an options object like this referred to as a "builder object" in other languages (at least in the context of object creation). Here are some of the advantages:
Users of your function don't have to worry about what order the parameters are in. This is especially helpful in cases like yours where the method takes a lot of arguments. It's easy to get those mixed up, and JavaScript will not complain!
It's easy to make certain parameters optional (this comes in handy when writing a plugin or utility).
There are some pitfalls though. Specifically, the user of your function could not specify some of the options and your code would choke (note that this could also happen with a normal JS function: the user still doesn't have to supply the correct arguments). A good way for handling this is to provide default values for parameters that are not required:
var value = options.val || 0;
var element = options.ele || {};
$(element).val(value);
You could also return from the function immediately or throw an exception if the correct arguments aren't supplied.
A good resource for learning how to handle builder objects is to check out the source of things like jQueryUI.
I realize this question is a year old, but I think the cleanest way to pass an arbitrary number of arguments to a JavaScript function is using an array and the built in apply method:
fun.apply(object, [argsArray])
Where fun is the function, object is your scope/context in which you want the function to be executed and the argsArray is an array of the arguments (which can hold any number of arguments to be passed.
The current pitfall right now is that the arguments must be an array (literal or object) and not an array-like object such as {'arg' : 6, 'arg2' : "stuff"}. ECMAScript 5 will let you pass array-like objects, but it only seems to work in FireFox at the moment and not IE9 or Chrome.
If you look at the jQuery implementation, it uses an options class to handle most of the arbitrary-number-of-parameters functions, so I think you are in good company.
The other way is to test for arguments.length, but that only works if your arguments are always in the same order of optionality.
It's worth remembering that all functions have a bonus parameter called arguments that is an object very much like a JS array (it has length but none of the array functions) that contains all the parameters passed in.
Useful if you want to pass in a range of parameters (e.g.
function Sum() {
var i, sum = 0;
for (i=0; i < arguments.length; i++){
sum+=arguments[i];
}
return sum;
};
If this isn't the case and you just have a lot of parameters, use the params object as you've described.
Nothing wrong with that practice.
"Options" seems like as good a name as any.
You don't need to "unpack" them, but if you'll be accessing the same item several times, it will be a little more efficient to reference them in local variables because local variable access is generally quicker than property lookups.

Categories