I have the follwoing:
HB.formButtons.deactivatingButton = function(inputs) {
inputs.forEach(function(argument){
argument.parent().removeClass(HB.formButtons.SUBMIT_BUTTON_STYLE);
});
}
which I than call in various parts like so:
HB.formButtons.deactivatingButton($(HB.personalDetails.SUBMIT_PERSONAL_DETAILS_SELECTOR), $(HB.personalDetails.CANCEL_PERSONAL_DETAILS_SELECTOR));
The console. throws the following error:
Uncaught TypeError: formsInput.forEach is not a function
Why?
Considering your input to be HTMLCollection, the forEach doesn't work on a collection. forEach works on Array
You can, however, make it work like
HB.formButtons.deactivatingButton = function(inputs) {
[].forEach.call(inputs, function(argument){
argument.parent().removeClass(HB.formButtons.SUBMIT_BUTTON_STYLE);
});
}
If you wanted to pass your function array of two elements you have to use square brackets [].
HB.formButtons.deactivatingButton(
[
$(HB.personalDetails.SUBMIT_PERSONAL_DETAILS_SELECTOR),
$(HB.personalDetails.CANCEL_PERSONAL_DETAILS_SELECTOR)
]);
alternative you can use the special variable arguments in your function. Described at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments
Related
I have a problem passing an array.push function in javascript having a code like this:
const array = [];
addToArray("works", (e) => array.push(e));
addToArray("notWorks", array.push);
doConsoleLog("hello", console.log);
function addToArray(element, pushFn) {
pushFn(element);
}
function doConsoleLog(message, log) {
log(message);
}
Just curious how's that first call of addToArray works, but second causes TypeError: Cannot convert undefined or null to object. How is it possible? Type of array.push is a function. It is not possible to pass functions directly like in the case of console.log above, which works pretty well?
push is a method of array. When invoked, it uses this as a reference to the object it is being called on. If you pass it around like a normal function, you will lose that reference, the method will use the value of this defined at the moment of the call (inside addToArray, this is probably document.window), and will therefore fail.
In order to pass around a method, you need to bind it to the object you want it to operate on, in this case array. This is true for any object method in JavaScript. Function.prototype.bind() exists exactly for this purpose: it "binds" a function (in this case your method) to a given value of this, in order to work correctly.
const array = [];
addToArray("now it works", array.push.bind(array));
// or
addToArray("now it works", Array.prototype.push.bind(array));
function addToArray(element, pushFn) {
pushFn(element);
}
Once you pass a function like you did in the second case, it executes itself immediately, and array.push doesn't really mean something.
A callback function should be executed later on in the outer function.
Unlike the second example, in the first one you don't execute the function immediately, but only when you call it inside the outer function.
Your code have a lot of mistakes. What exactly should do this code? if you want to push new items in array use spread operator
const array = [...[], "works", "notWorks"]
const array = [];
addToArray("works", (e) => array.push(e));
addToArray("notWorks", array.push);
doConsoleLog("hello", console.log);
function addToArray(element, pushFn) {
pushFn(element); //function must return something
}
function doConsoleLog(message, log) {
log(message); //function must return something
}
I've gathered an Array (I think) of required form elements, and have added 'blur' listener.
var formInputs = $(':input').filter('[required]');
formInputs.each(function(i) {
$(this).on('blur', function() { // Each time we leave a 'required' field, check to see if we can activate the 'submit' button.
submitEnabler(formInputs);
});
});
So, once someone has left one of these fields, I want to run through this array using .every() and check if the fields are valid - that is if they have a 'success' class that I have defined.
function isValid(input) {
return input.hasClass('is_glowing_success');
}
function submitEnabler(inputs) {
console.log(inputs.every(isValid));
}
I keep getting back:
Uncaught TypeError: inputs.every is not a function
at submitEnabler
Now, I could do something like this...
for (var i = 0; i < inputs.length; i++) {
if ($(inputs[i]).hasClass('is_glowing_success')) {
console.log('yes');
} else {
console.log('no');
}
}
But, why can't I just use: Array.Prototype.every() ?
Because jQuery objects have no every method, and formInputs is a jQuery object.
If you want an array instead, call get() to get one.
I've gathered an Array (I think) of required form elements...
No, it's just jQuery object. jQuery objects are very array-like, but they aren't arrays. Worse, they have some array-like methods (such as filter and map) that call their callbacks with different arguments than the equivalent Array.prototype methods.
In isValid, you'd need to handle the fact you're now dealing with a raw DOM element, which means either wrapping it with a jQuery object and using hasClass:
function isValid(input) {
return $(input).hasClass('is_glowing_success');
}
or using the DOM's classList:
function isValid(input) {
return input.classList.contains('is_glowing_success');
}
That latter works on all modern browsers, but not all older ones. However, it can be polyfilled on older browsers. More about that on MDN.
jQuery does not have a .every() method. .every is defined at Array.prototype.
You can use .toArray() to convert jQuery object to an Array, within .every() callback function pass current DOM element to jQuery() to get jQuery object representation of element where .hasClass() can be chained.
function submitEnabler(inputs) {
console.log(inputs.toArray().every(isValid));
}
function isValid(input) {
return $(input).hasClass('is_glowing_success');
}
I will suggest you use array.map()
for example where input is the array
input.map(function(input){
return $(input).hasClass('is_glowing_success');
});
this is just an example read more here
I have an array
var arr = [' A ', ' b ', 'c'];
and I want to trim the spaces from each of the element from array.
It can be done by using Array.map as
arr.map(function(el) {
return el.trim();
});
I'm curious about passing the trim/toLowerCase function directly to the map as callback function, like arr.map(Math.max.apply.bind(Math.max, null)); to get the maximum element from each subarray or arr.map(Number); to cast each element to Number.
I've tried
arr.map(String.prototype.trim.apply);
but it is throwing error
Uncaught TypeError: Function.prototype.apply was called on undefined, which is a undefined and not a function
I expect that String.prototype.trim.apply should be called for each element in the array with the context set to the element from array(passed to apply);
I've also tried different combinations of apply, call and bind with no success.
Why the function on prototype cannot be referenced when using map
How function can be passed as parameter to map
arr.map(String.prototype.trim.call.bind(String.prototype.trim));
call uses this internally, which must point to the trim function to work properly in this case. Simply passing String.prototype.trim.call would leave call unbound to any method, resulting in the this value pointing to window instead.
It works, but when used apply instead of call it throws error,
arr.map(String.prototype.trim.apply.bind(String.prototype.trim));
The problem is that map will pass 2 arguments, the item and the index. Therefore it ends up calling something like 'String.prototype.trim.apply('test', 0) which fails since the second argument must be an array.
one more thing [' A ', ' B ',
'c'].map(String.prototype.trim.call.bind(String.prototype.toLowerCase));,
in this, I've used trim.call and passed toLowerCase as context then
why we need trim here, why trim is not called
When using call.bind the path that you chose to access the call function reference becomes irrelevant. The function that will get called is the one that is bound.
If you want to compose functions together you will need a different approach:
var call = Function.prototype.call,
trim = call.bind(String.prototype.trim),
toLowerCase = call.bind(String.prototype.toLowerCase),
trimAndLowerCase = pipelineFrom(trim, toLowerCase);
[' TeST '].map(trimAndLowerCase);
function pipelineFrom(fn1, fn2) {
return function (val) {
return fn2(fn1(val));
};
}
However at this point you're better off with:
arr.map(function (val) {
return val.trim().toLowerCase();
});
This works, it sure is long-winded though:
var t = String.prototype.trim.call.bind(String.prototype.trim);
arr.map(t);
Because it's longwinded there are blog posts and modules devoted to uncurrying, which is what you are trying to do here.
I did ask about this here once...
I'm receiving this error after attempting to optimise some code I'm working on.
Initially I was using canvas.forEachObject(function(obj){}) which was working fine but I needed to streamline the process somewhat.
I now have a function that iterates through the canvas and adds all the relevant object type to an array that I will then use.
function getObjects(){
var canvasObjects = canvas.getObjects();
var theArray = new Array();
for(obj in canvasObjects){
if(canvasObjects[obj].get('type') == 'thisType'){
theArray.push(canvasObjects[obj]);
}
if(canvasObjects[obj].get('type') == 'group'){
var groupObjects = canvasObjects[obj].getObjects();
for(groupObj in groupObjects){
if(groupObjects[groupObj].get('type') == 'thisType'){
theArray.push(groupObjects[groupObj]);
}
}
}
}
return theArray;
}
I'm then calling a function in an animation loop that uses the array in order to determine if a collision has occurred.
Array created here:
var geoArray = getObjects();
function detectCollision(target) {
target.setCoords();
geoArray.forEachObject(function(obj)
//for(obj in geoArray) //1st attempt - same result
{
obj.setCoords();
if(obj!=target && target.intersectsWithObject(obj)){
//..do stuff
}
});
}
The array is built fine and contains the correct number of objects so I'm sure there is no problem there. The problem occurs when I run the collision function and the type error problem occurs. Searching indicates that I may not be returning the object type but I'm not sure if this is the case and if so I'm not sure how to fix it.
Many thanks for any help.
Edit: the exact error is:
[Error] TypeError: 'undefined' is not a function (evaluating 'geoArray.forEachObject')
Edit, the error occurs always within the collision loop and as soon as 'obj' is called.
The method you're using to iterate through the array is not correct. The forEachObject is not a method of a plain JavaScript Array. It is a method defined on fabric.Collection.
The error simply indicates that you trying to use an undefined type as a function; You can either iterate using the forEach method or using a common for loop.
So I have a Hashtable defined (with jshashtable.js):
hashy = new Hashtable();
I put some keys in it:
hashy.put("hi", "yay");
hashy.put("hello", "yes");
Now I want to iterate it with .each, as the doc says:
hashy.each(iterator());
But it says 'object is not a function'
Now, if I do this:
hashy.each(function() { });
It works, but is there a way to call an existing function this way?
I just realized the most obvious answer would be to do:
hashy.each(function() { iterator(); });
Assuming your iterator function is something like the following:
function iterator(key, value) {
// Do something with key and/or value
}
... then just pass the function in without the parentheses. With the parentheses, you're executing the function immediately (just once) and passing the returned value into each(), which is probably not what you intended.
hashy.each(iterator);