Extract all constants out of angular cache - angularjs

I know i can use $injector.has('<constant name>') to get a constant by name but the problem is i don't know the name ahead of time, i just want to get a list of all angular constants that (for example) start with "json_". The reason i need this is because i'm building a module that people can plugin to their own code, this is why i won't know the names ahead of time but i can at least ask the programmer to start the constants i need to work with, with "json_". Currently i have to tell them to name their constants exactly "json1", "json2", "json3", etc and this is bad because the user has to keep track of where they are in numbering and it's not good design. There doesn't seem to be anything directly within the API's to do what i'm trying to do.

There is no built-in way to get all constants in an angular module, but you can achieve this by loop through _invokeQueue which an internal using array to hold all registered services on a given angular module. If you registered a constant called json_obj in angular.module('app'), then in angular.module('app')._invokeQueue should contain an array like:
['$provider', 'constant', ['json_obj', valueObj]]
So you can get a list of json_* constants by:
function getJsonConstants(){
var queue = angular.module('myApp')._invokeQueue;
var jsonConstant = [];
angular.forEach(queue, function(item){
if(item[1] === 'constant'){
if(item[2][0].match(/\bjson_/gi)){
jsonConstant.push({
key: item[2][0],
value: item[2][1]
})
}
}
})
return jsonConstant;
}
One more thing, this function can only return all constant registered in angular.module('myApp'), if myApp has any dependent modules, you should loop all _invokeQueue in those modules to get completed constant list.

Related

Uncaught Cannot convert Array to Object[][] when passing array of arrays to range.setValues()

Desired Behaviour
Populate Google Sheet with array of arrays from a Javascript file.
// in js file (within google apps script project)
var aoa = [["row_01_val01", "row_01_val02", "row_01_val03"],
["row_02_val01", "row_02_val02", "row_02_val03"]]; // etc
google.script.run.withSuccessHandler(console.log("success")).populateSpreadsheet(aoa);
// in code.gs
// define target_range (ignore discrepancies between example values above)
var target_range = active_sheet.getRange(2, 1, 834, 20);
// set values of target_range
target_range.setValues(aoa);
Current Behaviour
// chrome developer tools (firefox/firebug not supported at work)
Uncaught Cannot convert Array to Object[][]
Question
I'm unable to post more specific code due to work restrictions (cannot access SO from work, or take code home, hence the pseudo code), but are there any common 'gotchas' when it comes to passing an array of arrays from a Javascript file to Code.gs for use in setValues()?
What I've Tried
In the js file, console.log(typeof(aoa)) returns object just before passing it to populateSpreadsheet() within Code.gs, and then Logger.log(aoa) within populateSpreadsheet() also returns object
Example:
var outer_array = [];
inner_array = [1,2,3];
outer_array.push(inner_array);
typeof(outer_array);
"object"
I've tried to refactor the code several times, but am wondering if there are any common gotchas like size constraints, quotas, or timeouts or some other 'quirk' I haven't considered?
This question and answer, for example, required the array of arrays to be reconstructed before passing it to setValues() (I tried this but it didn't work in my instance):
https://stackoverflow.com/a/11066322/1063287
Another thing I considered is that I'm using splice()(MDN reference) to add some values to the inner array's within Code.gs, so I'm not sure if that somehow changes the type permissible to be passed to setValues()?

Is it possible to access constants without injection?

I am using gulp-ng-config in my project to dynamically generate some constants at build time.
This is working just fine, but it got me and a colleague thinking about how constants are accessed in an angular app.
If you want to access constants in controllers that are defined on the same module that the constants belong to, do you still have to inject the constants by name to the controllers so you can access their values?
Looking at various examples, I'm pretty sure this is the only way - just wondered if there was some other way that didn't require a further dependency to be injected.
The constants injection is part of a best-practice-approach.
It's just a syntactical overhead preventing you from doing bad stuff like defining global variables and using them all over the place.
Of course you still can go ahead and define variables on the global window-scope and use them everywhere, but i cleary wouldn't suggest to do so.
So you can do
window.foo = 123;
and somewhere else
alert (window.foo);
this will show the wanted value but, of course, this is very bad practice.
You can also define variables on the angular $rootScope and use them anywhere. Yet, bottom line this is nothing else than defining them on window scope and shouldn't be done as well.
The last option (and probably the best for your scenario) is to define one constant OBJECT containing some more values. This way you just have to inject one constant object instead of many different ones.
Say you have two constants so far
$width = 1024
$height = 768
there is nothing bad about defining one injectable constant
$config = {
width: 1024,
height: 768
};
if you just want to access the $constant from outside the angular world you can always do it like this:
angular.element('body').injector().get('$constant')
assuming you declared your ng-app on the 'body' element or even further outside (like the 'html' element).
This is what dependency injection is made for : to force you to show all dependencies to your model.
Otherwise you can use the injector and use the method $get to get the values but i don't recommend it.
A last way would be to use a provider to store all constants and inject only the resulting service. However this will mask from which module each constants come from.

What is the reason for assigning this to a locale variable without a callback?

As far as I know assigning this to a variable is used within callbacks where the this scope may change. But digging through the ExtJS source I found it used in all sorts of functions but not always. So is there any reason that I would assign this to a local variable beneath the scope or is the ExtJS source just struggling with different developer styles?
#kevhender pointed me to the right sencha forum thread where evan has given a very good explanation.
It's only for the size. And here's a example:
function doA() {
var me = this;
me.a();
me.b();
me.c();
me.d();
me.e();
me.f();
me.g();
me.h();
me.i();
me.j();
me.k();
me.l();
}
function doB() {
this.a();
this.b();
this.c();
this.d();
this.e();
this.f();
this.g();
this.h();
this.i();
this.j();
this.k();
this.l();
}
Compressed we get:
function doA(){var a=this;a.a();a.b();a.c();a.d();a.e();a.f();a.g();a.h();a.i();a.j();a.k();a.l()}
function doB(){this.a();this.b();this.c();this.d();this.e();this.f();this.g();this.h();this.i();this.j();this.k();this.l()};
It adds up.
According to that we should
NOT use a local var if we use this only up to three times
function doA(){var a=this;a.a();a.b();a.c();};
function doB(){this.a();this.b();this.c();};
and use it if we use this more often then three times
function doA(){var a=this;a.a();a.b();a.c();a.d()};
function doB(){this.a();this.b();this.c();this.d()};
There are a few reasons for this, the most significant being that using a local variable will save a few bytes during compression of the files. It may not seem like much for a small bit of code, but it can add up a good bit over time.
There is a long thread at the Sencha forums talking about this very issue: http://www.sencha.com/forum/showthread.php?132045.
As you've correctly stated this is sometimes used in places where the scope might change.
There are cases where you want to do the same to make sure there are no scoping issues.
Other than that, the devs sometimes just assign this to a variable out of habit more than out of necessity.

quering for objects with angularFireCollection?

I used the implicit method for retrieving data objects:
setData = function(segment){
var url = 'https://myFireBase.firebaseio.com/';
var rawData = angularFire(url+segment,$rootScope,'data',{});
rawData.then(function(data){
// sorting and adjusting data, and then broadcasting and/or assinging
}
}
This code is located inside a service that gets called from different locations, by development stages it'll probably be around 100 - 150 so I got out of the controllers and into a service, but now firebase data-binding would obviously over-write the different segments so I turned back to explicit methid, to have the different firebases only sending the data to site instead of data-binding and over-writing each other:
var rawData = angularFireCollection(url+segment);
And right there I discovered why I chose the implicit in the first place: There's an argument for the typeof, i could tell firebase if I'm calling a string, an array, an object etc. I even looked at the angularfire.js and saw that if the argument is not given, if falls back to identifying it as an array by default.
Now, I'm definitely going to move to the explicit method (that is, if no salvation comes with angular2.0), and reconstructing my firebase jsons to fit the array-only policy is not that big of a deal, but surely there's an option to explicitly call objects, or am I missing something?
I'm not totally clear on what the question is - with angularFireCollection, you can certainly retrieve objects just fine. For example, in the bundled chat app (https://github.com/firebase/angularFire/blob/gh-pages/examples/chat/app.js#L5):
$scope.messages = angularFireCollection(new Firebase(url).limit(50));
Each message is stored as an object, with its own unique key as generated by push().
I'm also curious about what problems you found while using the implicit method as your app grew. We're really looking to address problems like these for the next iteration of angularFire!

Sorting and managing numerous variables

My project has classes which, unavoidably, contain hundreds upon hundreds of variables that I'm always having to keep straight. For example, I'm always having to keep track of specific kinds of variables for a recurring set of "items" that occur inside of a class, where placing those variables between multiple classes would cause a lot of confusion.
How do I better sort my variables to keep from going crazy, especially when it comes time to save my data?
Am I missing something? Actionscript is an Object Oriented language, so you might have hundreds of variables, but unless you've somehow treated it like a grab bag and dumped it all in one place, everything should be to hand. Without knowing what all you're keeping track of, it's hard to give concrete advice, but here's an example from a current project I'm working on, which is a platform for building pre-employment assessments.
The basic unit is a Question. A Question has a stem, text that can go in the status bar, a collection of answers, and a collection of measures of things we're tracking about what the user does in that particular type of questions.
The measures are, again, their own type of object, and come in two "flavors": one that is used to track a time limit and one that isn't. The measure has a name (so we know where to write back to the database) and a value (which tells us what). Timed ones also have a property for the time limit.
When we need to time the question, we hand that measure to yet another object that counts the time down and a separate object that displays the time (if appropriate for the situation). The answers, known as distractors, have a label and a value that they can impart to the appropriate measure based on the user selection. For example, if a user selects "d", its value, "4" is transferred to the measure that stores the user's selection.
Once the user submits his answer, we loop through all the measures for the question and send those to the database. If those were not treated as a collection (in this case, a Vector), we'd have to know exactly what specific measures are being stored for each question and each question would have a very different structure that we'd have to dig through. So if looping through collections is your issue, I think you should revisit that idea. It saves a lot of code and is FAR more efficient than "var1", "var2", "var3."
If the part you think is unweildy is the type checking you have to do because literally anything could be in there, then Vector could be a good solution for you as long as you're using at least Flash Player 10.
So, in summary:
When you have a lot of related properties, write a Class that keeps all of those related bits and pieces together (like my Question).
When objects have 0-n "things" that are all of the same or very similar, use a collection of some sort, such as an Array or Vector, to allow you to iterate through them as a group and perform the same operation on each (for example, each Question is part of a larger grouping that allows each question to be presented in turn, and each question has a collection of distractors and another of measures.
These two concepts, used together, should help keep your information tidy and organized.
While I'm certain there are numerous ways of keeping arrays straight, I have found a method that works well for me. Best of all, it collapses large amounts of information into a handful of arrays that I can parse to an XML file or other storage method. I call this method my "indexed array system".
There are actually multiple ways to do this: creating a handful of 1-dimensional arrays, or creating 2-dimensional (or higher) array(s). Both work equally well, so choose the one that works best for your code. I'm only going to show the 1-dimensional method here. Those of you who are familiar with arrays can probably figure out how to rewrite this to use higher dimensional arrays.
I use Actionscript 3, but this approach should work with almost any programming or scripting language.
In this example, I'm trying to keep various "properties" of different "activities" straight. In this case, we'll say these properties are Level, High Score, and Play Count. We'll call the activities Pinball, Word Search, Maze, and Memory.
This method involves creating multiple arrays, one for each property, and creating constants that hold the integer "key" used for each activity.
We'll start by creating the constants, as integers. Constants work for this, because we never change them after compile. The value we put into each constant is the index the corresponding data will always be stored at in the arrays.
const pinball:int = 0;
const wordsearch:int = 1;
const maze:int = 2;
const memory:int = 3;
Now, we create the arrays. Remember, arrays start counting from zero. Since we want to be able to modify the values, this should be a regular variable.
Note, I am constructing the array to be the specific length we need, with the default value for the desired data type in each slot. I've used all integers here, but you can use just about any data type you need.
var highscore:Array = [0, 0, 0, 0];
var level:Array = [0, 0, 0, 0];
var playcount:Array = [0, 0, 0, 0];
So, we have a consistent "address" for each property, and we only had to create four constants, and three arrays, instead of 12 variables.
Now we need to create the functions to read and write to the arrays using this system. This is where the real beauty of the system comes in. Be sure this function is written in public scope if you want to read/write the arrays from outside this class.
To create the function that gets data from the arrays, we need two arguments: the name of the activity and the name of the property. We also want to set up this function to return a value of any type.
GOTCHA WARNING: In Actionscript 3, this won't work in static classes or functions, as it relies on the "this" keyword.
public function fetchData(act:String, prop:String):*
{
var r:*;
r = this[prop][this[act]];
return r;
}
That queer bit of code, r = this[prop][this[act]], simply uses the provided strings "act" and "prop" as the names of the constant and array, and sets the resulting value to r. Thus, if you feed the function the parameters ("maze", "highscore"), that code will essentially act like r = highscore[2] (remember, this[act] returns the integer value assigned to it.)
The writing method works essentially the same way, except we need one additional argument, the data to be written. This argument needs to be able to accept any
GOTCHA WARNING: One significant drawback to this system with strict typing languages is that you must remember the data type for the array you're writing to. The compiler cannot catch these type errors, so your program will simply throw a fatal error if it tries to write the wrong value type.
One clever way around this is to create different functions for different data types, so passing the wrong data type in an argument will trigger a compile-time error.
public function writeData(act:String, prop:String, val:*):void
{
this[prop][this[act]] = val;
}
Now, we just have one additional problem. What happens if we pass an activity or property name that doesn't exist? To protect against this, we just need one more function.
This function will validate a provided constant or variable key by attempting to access it, and catching the resulting fatal error, returning false instead. If the key is valid, it will return true.
function validateName(ID:String):Boolean
{
var checkthis:*
var r:Boolean = true;
try
{
checkthis = this[ID];
}
catch (error:ReferenceError)
{
r = false;
}
return r;
}
Now, we just need to adjust our other two functions to take advantage of this. We'll wrap the function's code inside an if statement.
If one of the keys is invalid, the function will do nothing - it will fail silently. To get around this, just put a trace (a.k.a. print) statement or a non-fatal error in the else construct.
public function fetchData(act:String, prop:String):*
{
var r:*;
if(validateName(act) && validateName(prop))
{
r = this[prop][this[act]];
return r;
}
}
public function writeData(act:String, prop:String, val:*):void
{
if(validateName(act) && validateName(prop))
{
this[prop][this[act]] = val;
}
}
Now, to use these functions, you simply need to use one line of code each. For the example, we'll say we have a text object in the GUI that shows the high score, called txtHighScore. I've omitted the necessary typecasting for the sake of the example.
//Get the high score.
txtHighScore.text = fetchData("maze", "highscore");
//Write the new high score.
writeData("maze", "highscore", txtHighScore.text);
I hope ya'll will find this tutorial useful in sorting and managing your variables.
(Afternote: You can probably do something similar with dictionaries or databases, but I prefer the flexibility with this method.)

Resources