I'm refactoring some JS code to CoffeeScript, and having a problem with a function.
This is the JS that works:
$(".comformt_QA").change(function(){
var array = $(".comformt_QA").map(function() {
return $(this).val();
}).toArray();
$("[name='comfort_qualitative_assessment.global_comfort_index']").val(
calc_qualitative_assessment_array(array)
).change();
});
My goal is to use this snipplet as a function, and be able to call:
class_to_calc_qualitative_assessment_array(".comformt_QA", "[name='comfort_qualitative_assessment.global_comfort_index']");
Here's the CoffeeScript:
#class_to_calc_qualitative_assessment_array = (class_param, target) ->
array = []
$(class_param).change ->
array = $(class_param).map( ->
$(this).val()
)
$(target).val(calc_qualitative_assessment_array(array)).change()
array is always empty...
Thoughts?
If you compile your coffee code to Javascript this would be the result:
this.class_to_calc_qualitative_assessment_array = function(class_param, target) {
var array;
array = [];
$(class_param).change(function() {
return array = $(class_param).map(function() {
return $(this).val();
});
});
return $(target).val(calc_qualitative_assessment_array(array)).change();
};
Coffeescript transpiles the # to the this keyword in JS. Also you don't have returns within your function - this leads to coffeescript returning the last assigned value of the function.
Maybe this would be a working approach:
class_to_calc_qualitative_assessment_array = (class_param, target) ->
array = []
$(class_param).change ->
array = $(class_param).map( ->
$(#).val()
)
return
$(target).val(calc_qualitative_assessment_array(array)).change()
return
Transpiled this looks like this:
var class_to_calc_qualitative_assessment_array;
class_to_calc_qualitative_assessment_array = function(class_param, target) {
var array;
array = [];
$(class_param).change(function() {
array = $(class_param).map(function() {
return $(this).val();
});
});
$(target).val(calc_qualitative_assessment_array(array)).change();
};
Related
I need to create a javascript object using values stored in an array. Every value should be a new key inside the previous one. What would be the best approach to achieve this?
var option = ['level_1','level_2','level_3','level_4'];
$.each( option, function( key, value ) {
// ....
});
// I'm trying to get this result
var result = {
'level_1': {
'level_2': {
'level_3': {
'level_4':{}
}
}
}
}
You can use reduceRight for this, with the ES6 computed property name syntax.
const option = ['level_1','level_2','level_3','level_4'];
const obj = option.reduceRight( (acc, lvl) => ({ [lvl]: acc }), {});
console.log(obj);
In traditional function syntax it would be:
const obj = option.reduceRight(function (acc, lvl) {
return { [lvl]: acc };
}, {});
You have to keep track of where to put the next key. So, create a variable and initially set it to result, then on each pass through the array, move where that variable points to.
var option = ['level_1','level_2','level_3','level_4'];
var result = {};
var nextKeyGoesHere = result;
option.forEach( function( value ) {
nextKeyGoesHere[value] = {};
nextKeyGoesHere = nextKeyGoesHere[value];
});
console.log(result);
Can use Array#reduce()
var option = ['level_1','level_2','level_3','level_4'];
var res = {};
option.reduce((o, key) => (o[key] = {} , o[key]), res)
console.log(res)
you can use any of the other answers that use Array#reduce, however, if you'd like a recursive version here it is:
function _makeTree(arr, index, subtree){
if(index < arr.length){
subtree[arr[index]] = {};
return _makeTree(arr, index+1, subtree[arr[index]])
}
else return;
}
function makeTree(arr){
var tree = {};
_makeTree(arr, 0, tree)
return tree;
}
var arr = ['level_1','level_2','level_3','level_4'];
console.log(makeTree(arr));
Thanks in advance for any responses:
I don't think this is a duplicate: I reviewed that article in the first comment, that is just a general breakdown of objects and using "this" within javascript.
My other this.function's perform just fine, so I at least have the basics of JS Obj's figured out.
This issue is related to using .map() with a this.function within a constructed object.
The following Google Appscript code uses .map() to update a string in a 2d array. [[string, int],[string, int]]
For some reason, when using .map() it is am unable to access the function "this.removeLeadingZero". If that same function is placed outside of the OBJ it can be called and everything works just fine. For some reason the system claims row[0] is an [object, Object] but when I typeof(row[0]) it returns "string" as it should.
Error: TypeError: Cannot find function removeLeadingZero in object [object Object]. (line 106, file "DEEP UPC MATCH")
Is there any issue using this.function's with .map() inside an object or am I using an incorrect syntax?
function test2DMapping(){
var tool = new WorkingMappingExample()
var boot = tool.arrayBuild();
Logger.log(boot)
}
function WorkingMappingExample(){
this.arr= [["01234", 100],["401234", 101],["012340", 13],["01234", 0422141],["01234", 2],["12340",3],["01234", 1],["01234", 2],["12340",3],["01234", 1],["01234", 2],["12340",3],["01234", 1],["01234", 2],["12340",3]];
//mapping appears faster that normal iterations
this.arrayBuild = function(){
var newArray1 =
this.arr.map( function( row ) {
**var mUPC = removeLeadingZero2(row[0])** //working
**var mUPC = this.removeLeadingZero(row[0])** // not working
var index = row[1]
Logger.log(mUPC + " " + index)
row = [mUPC, index]
return row
} )
return newArray1;
};
}; //end of OBJ
//THE NEXT 2 FUNCTIONS ARE WORKING OUTSIDE OF THE OBJECT
function removeLeadingZero2(upc){
try {
if (typeof(upc[0]) == "string"){
return upc.replace(/^0+/, '')
} else {
var stringer = upc.toString();
return stringer.replace(/^0+/, '')
}
} catch (err) {
Logger.log(err);
return upc;
}
}
function trimFirstTwoLastOne (upc) {
try {
return upc.substring(2, upc.length - 1); //takes off the first 2 #'s off and the last 1 #'s
} catch (err) {
Logger.log(err);
return upc;
}
}
Inside the function that you pass to map, this doesn't refer to what you think it does. The mapping function has its own this, which refers to window, normally:
var newArray1 = this.arr.map(function(row) {
// this === window
var mUPC = this.removeLeadingZero(row[0]);
var index = row[1];
Logger.log(mUPC + " " + index);
return [mUPC, index];
});
You have four options:
Array#map takes a thisArg which you can use to tell map what the this object in the function should be:
var newArray1 = this.arr.map(function(row) {
// this === (outer this)
var mUPC = this.removeLeadingZero(row[0]);
// ...
}, this); // pass a thisArg
Manually bind the function:
var newArray1 = this.arr.map(function(row) {
// this === (outer this)
var mUPC = this.removeLeadingZero(row[0]);
// ...
}.bind(this)); // bind the function to this
Store a reference to the outer this:
var self = this;
var newArray1 = this.arr.map(function(row) {
// self === (outer this)
var mUPC = self.removeLeadingZero(row[0]);
// ...
});
Use an arrow function:
var newArray1 = this.arr.map(row => {
// this === (outer this)
var mUPC = this.removeLeadingZero(row[0]);
// ...
});
Additionally, you could stop using this and new.
I have solved this issue and below is the answer in case anyone else runs into this:
this needs to be placed into a variable:
var _this = this;
and then you can call it within the object:
var mUPC = _this.removeLeadingZero(row[0])
Javascript scope strikes again!
So I'm working on updating some old projects and I am trying to find a source or an example of something I'm trying to accomplish.
what I have
// sample object of functions
var functions = {
required : function(value){
return value.length > 0;
},
isObject : function(value){
return typeof value == 'object';
}
};
Above is a sample of functions in an object. What I want to know is can the following be done:
pseudo code
//user input
var funcs = [required(''), isObject({key : 'v'})];
// what the function I'm building will process, in a sense
functions[funcs[i]](//arguments from funcs[i]);
// what would remain after each function
funcs = [false, true] // with an end result of false
I'm not 100% sure that this can't be done, I'm just not sure how in the slightest something like this would be able to come about. Let's bounce some ideas around here and see what we come up with.
Let me know if you all need any clarification of anything I asked. Thank you ahead of time for all help!
clarification on what I am trying to achieve
The object of functions is not finite, there can be any amount of functions for this specific program I am writing. They are going to be predefined, so user input is not going to be an issue. I need to be able to determine what function is called when it is passed, and make sure any arguments passed with said function are present and passed as well. So when I pass required(''), I need to be able to go through my object of functions and find functions['required'] and passed the empty string value with it. So like this functions['required']('').
other issues
The functions object is private access and the user won't have direct access to it.
How about this.
var functions = {
required : function(value){
return value.length > 0;
},
isObject : function(value){
return typeof value == 'object';
}
};
// Because these values are user inputs, they should be strings,
// so I enclosed them in quotes.
var funcs = ["required('')", "isObject({key: 'v'})"];
funcs.map(function(e) {
return eval('functions.' + e);
});
Running this should gives you an array of return values from the functions in the object.
Trivially, this could be done with:
var tests = [functions.required(''), functions.isObject({key: 'v'})];
If that's all you need, consider that my answer.
For a more general approach, the right tool here seems to be Arrays.prototype.map(). However, since you have an object containing all your functions instead of an array of functions, you'll need some way to make the correspondence. You can easily do this with a separate array of property names (e.g., ['required', 'isObject']). Then you could do something like this:
var functions = {
required : function(value){
return value.length > 0;
},
isObject : function(value){
return typeof value == 'object';
}
};
var args = ['', {key: 'v'}];
var results = ['required', 'isObject'].map(
function(test, i) {
return functions[test](args[i]);
}
);
Of course, if functions were an array instead of an object, you could simplify this:
var functions = [
/* required : */ function(value){
return value.length > 0;
},
/* isObject : */ function(value){
return typeof value == 'object';
}
];
var args = ['', {key: 'v'}];
var results = functions.map(
function(test, i) {
return test(args[i]);
}
);
If you wanted to encapsulate this a bit, you could pass the args array as a second argument to map(), in which case inside the function you would use this[i] instead of args[i].
Sure it's possible. Something like this:
var results = [];
var value = "value_to_pass_in";
for(var f in functions)
{
results.push(f.call(this, value));
}
UPDATE:
function superFunc(value)
{
var results = [];
for(var f in functions)
{
results.push(f.call(this, value));
}
return results;
}
superFunc("value_to_pass_in");
What you want is a map function. You can mimic it like this (I guess if you want one line):
https://jsfiddle.net/khoorooslary/88gh2yeh/
var inOneLine = (function() {
var resp = {};
var i = 0;
var fns = {
required : function(value){
return value.length > 0;
},
isObject : function(value){
return typeof value == 'object';
}
};
for (var k in fns) resp[k] = fns[k](arguments[i++]);
return resp;
}).apply(null, [ '' , {key : 'v'}]);
console.log(inOneLine);
var functions = {
required : function(value){
return value.length > 0;
},
isObject : function(value){
return typeof value == 'object';
}
};
var funcs = ["required('')", "isObject({key: 'v'})"];
function f(funcs){
return funcs.map(function(e) {
return eval('functions.' + e);
});
}
console.log(f(funcs));
//find value in array using function checkValue using underscoreJS _.each.
//return true, else false.
var helloArr = ['bonjour', 'hello', 'hola'];
var checkValue = function(arg) {
_.each(helloArr, function(helloArr, index) {
if (arg[index] === index) {
return true;
}
return false;
});
};
alert(checkValue("hola"));
The problem with your code is that, _.each will iterate through all the elements of the array and call the function you pass to it. You will not be able to come to a conclusion with that, since you are not getting any value returned from it (unless you maintain state outside _.each).
Note that the values returned from the function you pass to _.each will not be used anywhere and they will not affect the course of the program in any way.
But, instead, you can use _.some as an alternate, like this
var checkValue = function(arg) {
return _.some(helloArr, function(currentString) {
return arg === currentString;
});
};
But, a better solution would be, _.contains function for this purpose. You can use it like this
var checkValue = function(arg) {
return _.contains(helloArr, arg);
};
But, since you have only Strings in the Array, the best solution would be to use Array.prototype.indexOf, like this
var checkValue = function(arg) {
return helloArr.indexOf(arg) !== -1;
};
Try this:
var helloArr = ['bonjour', 'hello', 'hola'];
var checkValue = function(arr, val) {
_(arr).each(function(value) {
if (value == val)
{return console.log(true);}
else {return console.log(false);}
});
};
console.log(checkValue(helloArr,'hello'));
/* Output
false
true
false*/
I have numerous input boxes that I'm trying to store the names of into an array. I'm using this currently to get the names:
var getImplementedNames = function (selector){
$(selector).each(function() {
console.log($( this ).attr('name').replace('imp-', ''));
});
}
console.log(getImplementedNames('[id^=imp]'));
This works, but now I'd like to add all the reslts to an array. I've tried;
var array = [getImplementedNames('[id^=imp]')];
console.log(array);
Which returns an undefined array.
I'm not sure of how this is supposed to be properly handled.
Use .map()
var getImplementedNames = function (selector) {
return $(selector).map(function () {
return $(this).attr('name').replace('imp-', '');
}).get();
}
usage
console.log(getImplementedNames('[id^=imp]'));
Read Return Value from function in JavaScript
Your function isn't currently returning anything. Try:
var getImplementedNames = function (selector){
return $(selector).map(function() {
return $( this ).attr('name').replace('imp-', '');
});
}
console.log(getImplementedNames('[id^=imp]'));