I came across an Angular.js service named $httpParamSerializer and thought it could be useful for my code. However, when I tried to inject it Angular.js didn't recognize it and threw an "unknown provider" error.
Isn't $httpParamSerializer a built-in service (just like $http)? Why is this happening?
I have no problem injecting other built-in services such as $http, $httpBackend etc.
Thanks.
It was just recently added in Angular v1.4.0-rc.0. - so, check and fix your version of Angular:
<script src="https://code.angularjs.org/1.4.0-rc.0/angular.js">
I needed this also, but at the moment we cannot upgrade, so I just took code and created provider and added it to my "common" module. Once we upgrade, I'll just remove it.
(function (angular) {
'use strict';
var serviceId = '$httpParamSerializer';
var common = angular.module('common');
common.provider(serviceId, $HttpParamSerializerProvider);
function $HttpParamSerializerProvider() {
function sortedKeys(obj) {
return Object.keys(obj).sort();
}
function forEachSorted(obj, iterator, context) {
var keys = sortedKeys(obj);
for (var i = 0; i < keys.length; i++) {
iterator.call(context, obj[keys[i]], keys[i]);
}
return keys;
}
function encodeUriQuery(val, pctEncodeSpaces) {
return encodeURIComponent(val).
replace(/%40/gi, '#').
replace(/%3A/gi, ':').
replace(/%24/g, '$').
replace(/%2C/gi, ',').
replace(/%3B/gi, ';').
replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
}
function serializeValue(v) {
if (isObject(v)) {
return isDate(v) ? v.toISOString() : toJson(v);
}
return v;
}
function isUndefined(value) { return typeof value === 'undefined'; }
var isArray = Array.isArray;
function isObject(value) {
// http://jsperf.com/isobject4
return value !== null && typeof value === 'object';
}
/**
* #ngdoc service
* #name $httpParamSerializer
* #description
*
* Default {#link $http `$http`} params serializer that converts objects to strings
* according to the following rules:
*
* * `{'foo': 'bar'}` results in `foo=bar`
* * `{'foo': Date.now()}` results in `foo=2015-04-01T09%3A50%3A49.262Z` (`toISOString()` and encoded representation of a Date object)
* * `{'foo': ['bar', 'baz']}` results in `foo=bar&foo=baz` (repeated key for each array element)
* * `{'foo': {'bar':'baz'}}` results in `foo=%7B%22bar%22%3A%22baz%22%7D"` (stringified and encoded representation of an object)
*
* Note that serializer will sort the request parameters alphabetically.
* */
this.$get = function() {
return function ngParamSerializer(params) {
if (!params) return '';
var parts = [];
forEachSorted(params, function(value, key) {
if (value === null || isUndefined(value)) return;
if (isArray(value)) {
forEach(value, function(v, k) {
parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(v)));
});
} else {
parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(value)));
}
});
return parts.join('&');
};
};
}
}(angular))
Related
I am trying to create an SDK with javascript, using the standard object pattern. It works perfectly, unless I want to dynamically configure one of the resultant objects, e.g. if its demo use a simple RNG, if its a real game, use a HW RNG (different RNG implementation). Below does not work:
sdk.js
var Sdk = (function () {
var rng;
var localRng = (function() {
var getInt = function(min, max) { // min and max included
return Math.floor(Math.random() * (max - min + 1) + min);
}
return {
getInt: getInt
}
})();
var init = function(demo=true) {
if (demo ) {
console.log("initiing sdk as demo");
rng = localRng;
} else {
console.log("ALERT, REAL not implemented")
}
};
return {
init:init,
rng:rng,
}
})();
main.js
sdk.init(true);
var start = sdk.rng.getInt(1,12);
The problem is that sdk.rng is undefined.
If I hard code it thus:
var rng = (function() {
var getInt = function(min, max) { // min and max included
return Math.floor(Math.random() * (max - min + 1) + min);
}
return {
getInt: getInt
}
})();
in the above it works.
The crux is that you can play a game in demo mode or real mode, so it has to be possible to switch how the SDK does stuff under the hood (i.e. which object it uses, the demo one or real one). Obviously in the real sdk, and the real rng, there are a lot more functions, both private and public (returned)
Any help appreciated.
When you do
return {
init:init,
rng:rng,
}
you're returning an object whose init property points to the current reference of init (which is the function), and whose rng property points to the current reference of rng (which is undefined). It sounds like you'd want to dynamically return a reference to the local variable rng instead, which can be done by making the returned object's rng property a getter which returns that local variable:
return {
init:init,
get rng() {
return rng;
}
}
var sdk = (function () {
var rng;
var localRng = (function() {
var getInt = function(min, max) { // min and max included
return Math.floor(Math.random() * (max - min + 1) + min);
}
return {
getInt: getInt
}
})();
var init = function(demo=true) {
if (demo ) {
console.log("initiing sdk as demo");
rng = localRng;
} else {
console.log("ALERT, REAL not implemented")
}
};
return {
init:init,
get rng(){
return rng;
}
}
})();
sdk.init(true);
var start = sdk.rng.getInt(1,12);
console.log(start);
Rather than reassigning the variable, though, you might consider just saving a reference to the returned object, and assigning to a property of it when init is called:
var sdk = (function () {
var rng;
var localRng = (function() {
var getInt = function(min, max) { // min and max included
return Math.floor(Math.random() * (max - min + 1) + min);
}
return {
getInt: getInt
}
})();
var init = function(demo=true) {
if (demo ) {
console.log("initiing sdk as demo");
returnedObj.rng = localRng;
} else {
console.log("ALERT, REAL not implemented")
}
};
const returnedObj = { init };
return returnedObj;
})();
sdk.init(true);
var start = sdk.rng.getInt(1,12);
console.log(start);
I am aware that similar questions have been asked before, but methodology changes quickly so I'm seeking to understand current best practices. (In fact, as recently as 2 days ago, Chad Killingsworth added a comment to an accepted answer from three years ago that #expose annotation is now deprecated.)
I'm using the module pattern. Working JSFIDDLE of the below code:
/** #const */
var MATHCALCS = (function () {
'use strict';
var MY = {};
/**
* #constructor
* #param {!Object} obj
* #expose
*/
MY.ModuleStruct = function (obj) {
/** #expose */
this.color = (obj.color !== undefined) ? obj.color : null;
/** #expose */
this.size = (obj.size !== undefined) ? obj.size : null;
};
/**
* #expose
*/
MY.ModuleStruct.prototype.clone = function () {
return new MY.ModuleStruct({
"color": this.color,
"size": this.size
});
};
MY.moduleProperty = 1;
/**
* #type {function(!Array<number>)}
* #expose
*/
MY.moduleMethod = function (a) {
var i, x = 0;
for (i = 0; i < a.length; i += 1) {
x = x + a[i];
}
return x;
};
return MY;
}());
window["MATHCALCS"] = MATHCALCS;*
Currently, using #expose annotation, above can be minified with Closure in advance mode and the following calls work (minified example):
// call a public method
alert(MATHCALCS.moduleMethod([1, 2, 3]));
// allocate a new structure
var ms = new MATHCALCS.ModuleStruct({
"color": "red",
"size": "small"
});
alert(ms.color + '\t' + ms.size);
// clone a second instance
var ms2 = ms.clone();
alert(ms2.color + '\t' + ms2.size);
alert(ms !== ms2); // cloned objs are not equal
// and directly update the properties of the object
ms2.color = "white";
ms2.size = "large";
alert(ms2.color + '\t' + ms2.size);
If possible, without changing away from the module pattern, I would like to update code (approx 10,000 lines) to use #export annotation. However, when I replace #expose with #export Closure raises this error:
ERROR - #export only applies to symbols/properties defined in the global scope.
Q: Is it possible, and if so, how should the above code be annotated to work with ADVANCED_OPTIMIZATIONS?
I am aware that I can possibly use this type of notation:
MY["ModuleStruct"] = MY.ModuleStruct;
MY["ModuleStruct"]["prototype"]["clone"] = MY.ModuleStruct.prototype.clone;
but exporting object properties this way will become tedious. Further JSLint complains about weird assignments so I would rather use JSDocs annotation.
Until the issue raised by #ChadKillingsworth is resolved, here's a solution which will enable you to use #export with only minor modifications to your code:
/** #const */
var MATHCALCS = {};
goog.scope(function () {
'use strict';
var MY = MATHCALCS;
/**
* #constructor
* #param {!Object} obj
* #export
*/
MY.ModuleStruct = function (obj) {
this.color = (obj.color !== undefined) ? obj.color : null;
this.size = (obj.size !== undefined) ? obj.size : null;
};
/**
* #export
*/
MY.ModuleStruct.prototype.clone = function () {
return new MY.ModuleStruct({
"color": this.color,
"size": this.size
});
};
MY.moduleProperty = 1;
/**
* #type {function(!Array<number>)}
* #export
*/
MY.moduleMethod = function (a) {
var i, x = 0;
for (i = 0; i < a.length; i += 1) {
x = x + a[i];
}
return x;
};
});
The changes are:
Change the #expose tags to #export.
Create an empty MATHCALCS object outside the module wrapper function, and make the MY alias point to it.
Instead of executing the module wrapper function immediately (IIFE), pass it to goog.scope(). This enables aliasing within scope functions, allowing the compiler to work out that the exported symbols are being defined on the global MATHCALCS object. This prevents the compiler from raising the error ("#export only applies to symbols/properties defined in the global scope").
Remove the following items, which are not needed:
The #export tags on this.color and this.size
return MY;
window["MATHCALCS"] = MATHCALCS;
When compiled with this command:
java -jar compiler.jar \
--js closure/goog/base.js \
--js mathcalcs.js \
--js_output_file mathcalcs.min.js \
--compilation_level ADVANCED_OPTIMIZATIONS \
--generate_exports \
--formatting PRETTY_PRINT \
--output_wrapper '(function() {%output%}).call(window);'
you'll get:
(function() {var f = this;
function g(a, d) {
var b = a.split("."), c = f;
b[0] in c || !c.execScript || c.execScript("var " + b[0]);
for (var e;b.length && (e = b.shift());) {
b.length || void 0 === d ? c[e] ? c = c[e] : c = c[e] = {} : c[e] = d;
}
}
;function h(a) {
this.color = void 0 !== a.color ? a.color : null;
this.size = void 0 !== a.size ? a.size : null;
}
g("MATHCALCS.ModuleStruct", h);
h.prototype.clone = function() {
return new h({color:this.color, size:this.size});
};
h.prototype.clone = h.prototype.clone;
g("MATHCALCS.moduleMethod", function(a) {
var d, b = 0;
for (d = 0;d < a.length;d += 1) {
b += a[d];
}
return b;
});
}).call(window);
The g() function is the compiled version of goog.exportSymbol() – see the #export docs for more details.
Note: if you want to run the code uncompiled, you'll need to load the Closure Library, or define goog.scope() yourself:
var goog = {};
goog.scope = function(fn) {
fn();
};
Here's a fork of your JSFiddle with all these changes.
The following code is my attempt at a fairly generic javascript hash code implementation. I'm planning to use this code in conjunction with a hash table implementation (e.g. jshashtable) that utilizes hashCode() if its defined for keys. I have attempted to adhere closely to java's hash code implementations for numbers, strings, and arrays.
Questions:
Are there any issues with this implementation regarding correctness
or performance?
Are there any pre-existing implementations for hash
codes that do the same (or roughly the same) thing?
Aside from
jshashtable, are there other hash table implementations that utilizes
hashCode() and equals() in the same way that I should also consider?
NOTE: I'm aware that the code below could leverage other libs like underscore and jquery but I'd prefer not to have any 3rd party deps for my implementation. This is not say that I'm not interested in hash code libs that themselves may depend on jquery, underscore, etc.
/**
* Computes a hash code for an object based on a given subset of its fields
* #param obj any type
* #param keys an array of strings representing some subset of the keys in obj or undefined
* #returns {Number} a java-like hash code for obj based on the hash codes of a subset of its fields
* specified in keys.
*/
function hashCode(obj, keys) {
if (!isDefined(keys)) return typeHashCode(obj);
var result = 1;
for (var k = 0; k < keys.length; k++) {
var key = keys[k];
if (isDefined(obj[key]))
result = multiplyBy31AndAdd(result, typeHashCode(obj[key]));
}
return result;
}
/**
* #param obj
* #returns {Number}
*/
function typeHashCode(obj) {
var result = 1;
if (isDefined(obj)) {
if (typeof obj === 'string')
result = multiplyBy31AndAdd(result, stringHashCode(obj));
else if (typeof obj === 'number' && isFinite(obj))
result = multiplyBy31AndAdd(result, numberHashCode(obj));
else if (typeof obj === 'object') {
if (nonEmptyObject(obj)) {
if (isDefined(obj[hashCode]))
result = multiplyBy31AndAdd(result, obj.hashCode());
else {
if (Array.isArray(obj))
result = multiplyBy31AndAdd(result, arrayHashCode(obj));
else {
//This is what jshashtable does. If there were an easy and agreed upon way
//of uniquely identifying objects in javascript, a better approach
//may be to use the object's id
result = multiplyBy31AndAdd(result, stringHashCode(obj.toString()));
}
}
}
}
}
return result;
}
/**
* Generates a hash code for a 64 bit floating point number, similar to java's hash
* code implementation. This does not handle NaN and Inf the same way as java.
* More info can be found at [1]
* [1] http://stackoverflow.com/questions/2003493/javascript-float-from-to-bits
* #param num a finite number as defined by isFinite()
* #returns {Number}
*/
function numberHashCode(num) {
var buf = new ArrayBuffer(8);
(new Float64Array(buf))[0] = num;
return (new Uint32Array(buf))[0] ^ (new Uint32Array(buf))[1];
}
/**
* Generates a hash code for a string, similar to java's hash code
* implementation. More info can be found at [1]
* [1] http://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript-jquery
* #returns {Number}
*/
function stringHashCode(str) {
var hash = 0;
if (str.length === 0) return hash;
for (var i = 0; i < str.length; i++) {
var character = str.charCodeAt(i);
hash = multiplyBy31AndAdd(hash, character);
}
return hash;
}
/**
* #param array
* #returns {Number} hash code for the array
*/
function arrayHashCode(array) {
var result = 1;
for (var i = 0; i < array.length; i++) {
result = multiplyBy31AndAdd(result, typeHashCode(obj));
}
return result;
}
/**
* Code taken from:
* http://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript-jquery
* #param currentValue a number
* #param toAdd a number
* #returns {Number} the 32 bit integer representation of 31 * currentValue + toAdd
*/
function multiplyBy31AndAdd(currentValue, toAdd) {
var rv = ((currentValue<<5)-currentValue)+toAdd;
return rv & rv; //Convert to 32 bit integer
}
function isDefined(obj) {
return !(obj === undefined || obj === null);
}
/**
* Taken from http://stackoverflow.com/questions/4994201/is-object-empty
* #param obj an object
* #returns {Boolean} obj is {}
*/
function nonEmptyObject(obj) {
return !(Object.keys(obj).length === 0);
}
Just starting out with mocha and cannot for the life of me figure out why it thinks Helper is undefined at the indicated line/columns below:
test.js
var assert = require('assert'),
helper = require('../src/js/helper.js');
describe('helper', function() {
describe('#parseValue', function() {
it('should return number of minutes for a properly formatted string', function() {
assert.equal(1501, (new Helper()).parseValue('1d 1h 1m', 'when'));
^^^^^^^^^^^^
});
});
});
helper.js
(function(exports) {
'use strict';
function Helper(opts) {
this.opts = opts || {};
/**
* Parse a value based on its type and return a sortable version of the original value
*
* #param {string} val input value
* #param {string} type type of input value
* #returns {mixed} sortable value corresponding to the input value
*/
this.parseValue = function(val, type) {
switch (type) {
case 'when':
var d = val.match(/\d+(?=d)/),
h = val.match(/\d+(?=h)/),
m = val.match(/\d+(?=m)/);
if (m)
m = parseInt(m, 10);
if (h)
m += parseInt(h, 10) * 60;
if (d)
m += parseInt(d, 10) * 1440;
val = m;
break;
default:
break;
}
return val;
};
}
exports.helper = Helper;
})(this);
I wrote a quick test in the browser without mocha to ensure my helper.js functions were accessible and it worked fine, so I really am at a loss. I am running this directly on my server by calling mocha from the command line in my directory.
You never define Helper in test.js—only helper on this line:
var helper = require('../src/js/helper.js');
Use the lower case helper that you defined.
By the way, you might want to change your exports line in helper.js from this:
exports.helper = Helper;
To this:
exports.Helper = Helper;
Then use helper in test.js like so:
assert.equal(1501, (new helper.Helper()).parseValue('1d 1h 1m', 'when'));
Or just do something like this:
var Helper = require('../src/js/helper.js').Helper;
In JavaScript, is it possible to insert a line into a function that already exists? I want to create a function that inserts a line at a specific position in a function:
function insertLine(theFunction, lineToInsert, positionToInsert){
//insert a line into the function after the specified line number
}
For example, would it be possible to programmatically insert the line checkParameterTypes(min, "string", max, "string"); before the first line of this function?
function getRandomInteger(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
If you want something to happen at the beginning of a function, you can use the following. You do have access to this and the arguments from your injected function. So it will still work for functions that require a specific context.
function inject(before, fn) {
return function(){
before.apply(this, arguments);
return fn.apply (this, arguments);
}
}
For example
function add(a, b) {
return a + b;
}
function concat(a, b) {
return a + b;
}
/**
* You can repeat index and type to check multiple arguments
*/
function createArgumentChecker(index, type /**index, type, ... */) {
var originalArgs = arguments;
return function() {
for (var i=0; i < originalArgs.length; i+=2) {
var index = originalArgs[i],
requestedType = originalArgs[i+1],
actualType = typeof arguments[index];
if (typeAtIndex != actualType) {
console.log("Invalid argument passed at index " + index +
". Expected type " + requestedType + "but it's " + actualType );
}
}
}
}
function logArguments() {
console.log(this, arguments);
}
// Inject an argument checker
add = inject(add, createArgumentChecker(0,"number", 1, "number"));
concat = inject (concat, createArgumentChecker(0, "string", 1, "string"));
// You can even do it multiple times, inject an argument logger;
add = inject(add, logArguments);
concat = inject(concat, logArguments);
JSfiddle
This can be handy when debugging websites that you can't modify the source code, I wouldn't use it do parameter checking unless you can strip it our for the production version.
Yes you can but using eval is always evil ;)
function insertInbetween (arr, value, index) {
var inserted, i, newarr = [];
for (i = 0; i < arr.length; i++) {
if(i == index && !inserted) {
newarr[i] = value;
inserted = true;
}
newarr.push(arr[i]);
}
return newarr;
}
function test (a, b) {
console.log(a,b);
}
var fstrarr = test.toString().split('\n');
eval(insertInbetween(fstrarr, "console.log('injected!');", 1).join('\n'));
Edit:
As mentioned in the comments to your question you'll loose scope by doing so.