handlebars custom helper returns empty paragraphs [duplicate] - javascript

I'm trying to get two Handlebars variables to render inside a custom Handlebars helper I've created.
I'm using the Express.js view engine for handlebars.js, and in my app.js have set up a helper to compare equality:
const hbs = require('hbs');
app.set('view engine', 'hbs');
hbs.registerHelper('ifEqual', (a, b, options) => {
if (a === b) {
return options.fn(this);
}
return options.inverse(this);
});
My controller passes two variables to the view:
res.render('my-view', {
x: 3,
y: 3,
});
In my-view.hbs I'd like to render the variables if they're equal, so I tried:
{{#ifEqual x y}}
foo
{{x}}
{{y}}
{{/ifEqual}}
The result is only foo renders. Why don't {{x}} and {{y}} render here? Do I need to do this with a partial?

The reason your template will not render the values of x or y from within your ifEqual block is because there are no x or y properties within the context of that block. The reason that these properties are missing from the context is a very simple one: It is because in your call to registerHelper you used an Arrow Function Expression to define the Helper function.
Arrow Functions Expressions, in addition to a more compact syntax, are different from standard Function Expressions. The important difference in this case is that they do not have their own this context.
When you call registerHelper, Handlebars will bind the helper callback function to the data context of the template, in this case that would be the Object: { x: 3, y: 3 }. However, this will only work if you use a regular Function Expression as your callback and not an Arrow Function Expression - as the Arrow Function Expression cannot be dynamically bound to a different this context.
This means that you must use a regular function expression as your argument to registerHelper:
hbs.registerHelper('ifEqual', function (a, b, options) {
// Function body remains the same.
});
To get a better sense of what is wrong, you could console.log(this) within your helper using both function expression types and compare the difference.
I have created a fiddle to demonstrate the difference.

Ok so I've done this with a different approach:
hbs.registerHelper('renderVars', (a, b) => {
let output;
if (a === b) {
output = `foo ${a} ${b}`;
} else {
output = 'foo';
}
return output;
});
Then in my view:
{{#renderVars x y}}
{{/renderVars}}

Related

Modify arrow function javascript [duplicate]

This question already has answers here:
What's the meaning of "=>" (an arrow formed from equals & greater than) in JavaScript?
(14 answers)
Closed 6 years ago.
I have the following arrow function
if( rowCheckStatuses.reduce((a, b) => a + b, 0) ){}
rowCheckStatuses is an array of 1's and 0's, this arrow function adds them all up to produce a number. This number acts as a boolean to determine whether or not there is at least one "1" in the array.
The issue is, I don't really understand how arrow functions work, and my IDE thinks it's bad syntax and refuses to check the rest of my document for syntax errors.
How would I go about converting this to a regular function to alleviate both issues?
An arrow function can usually be converted by replacing
(<args>) => <body>
with
function(<args>) { return <body>; }
So yours would be
rowCheckStatuses.reduce(function(a, b) { return a + b; }, 0)
There are exceptions to this rule so it's important that you read up on arrow functions if you want to know all of the differences. You should also note that arrow functions have a lexical this.
You can refactor it as:
if( rowCheckStatuses.reduce(function(a, b){return a + b}, 0)
The initial accumulator isn't necessary (unless you expect the array to be empty sometimes), it could be:
if( rowCheckStatuses.reduce(function(a, b){return a + b})
This number acts as a boolean to determine whether or not there is at least one "1" in the array
It might be faster (and clearer) to use:
if( rowCheckStatuses.some(function(a){return a == 1}))
which will return true if there are any 1s in rowCheckStatuses and will return as soon as one is encountered. Another alternative is indexOf:
if( rowCheckStatuses.indexOf(1) != -1)
Lots of alternatives.
Replacing arrow functions with regular functions is usually unproblematic:
var f = x => y;
var g = function(x) { return y; }
Or, in your specific example:
rowCheckStatuses.reduce((a, b) => a + b, 0);
rowCheckStatuses.reduce(function(a, b) { return a + b; }, 0);
However, be aware of the exceptions:
Arrow functions don't bind a this value. Accessing this in an arrow function might thus return the value of the enclosing execution context's this:
function MyClass() {}
MyClass.prototype.f = () => this;
MyClass.prototype.g = function() { return this; }
myClass = new MyClass();
console.log(myClass.f()); // logs `Window`
console.log(myClass.g()); // logs `myClass`
Arrow functions also don't have access to a local arguments object. Accessing arguments in an arrow function might e. g. return the arguments of an enclosing function:
function test() {
var f = () => arguments;
var g = function() { return arguments; }
console.log(f()); // logs test's arguments
console.log(g()); // logs g's arguments
}
test('x');
The same holds for new.target and super. See also What are the differences (if any) between ES6 arrow functions and functions bound with Function.prototype.bind?

What is the role of the this variable when it comes to function currying using the .bind()?

I came across to the following JS code (ES5)
and I don't really I understand what is the meaning of the this variable.
function multiply(a,b){
return a * b;
}
var multipleByThree = multiply.bind(this,3);
multipleByThree(10) // outputs 30
I do understand that the bind copies the multiply function and that 'a' parameter of it, will have the value 3. But what is the purpose of the this variable?
Can you help me out please?
The this variable that you are providing to .bind() is the context. In your case, this refers to the global object space.
Here's an example of how this works:
var message = 'within global context';
function multiply(a,b){
console.log(this.message);
return a * b;
}
var someOtherContext = {
message: 'within some other context'
};
var multipleByThree = multiply.bind(this,3);
var multipleByThreeOtherContext = multiply.bind(someOtherContext, 3);
console.log(multipleByThree(10))
console.log(multipleByThreeOtherContext(10))
By changing the context that multiply executed within, we can change what variables it references.
The first argument to bind must be the thisArg:
fun.bind(thisArg[, arg1[, arg2[, ...]]])
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
That is, whatever the keyword this inside multiply will refer to. Since multiply doesn't use this at all, it's irrelevant what it refers to. You must still pass something as the first argument to bind, so likely the developer simply chose this (whatever that refers to in this code is unknown to us), but they could just as well have used false, null or anything else.
In javascript this is some kind of "reserved keyword" which refers to current object of the scope.
If this used outside of any object - it refers to window object.
Inside eventhandlers this refers to the DOM object which raised an event.
bind function provide possibility to define which object this will refer inside bound function.
For example if you using this inside function
const calculate = function (price, amount) {
return (price * amount) - this.discount;
};
You can bound a function with predefined this
const calculateWithDiscount = calculate.bind({ discount: 100 });
const total = calculateWithDiscount(1000, 2); // return 1900
When you bound function which doesn't use this object, you can easily pass null there, which clearly "tell" other developers your intents about using this in the function.
const add = function (a, b) {
return a + b;
};
const add5 = add.bind(null, 5);
const result = add5(19); // return 24
bind Method (Function) (JavaScript)
For what it's worth, you can do currying without relying upon Function.prototype.bind
Once you stop relying upon this in JavaScript, your programs can start looking like beautiful expressions
const curry = f => x => y =>
f (x,y)
const mult = (x,y) =>
x * y
const multByThree =
curry (mult) (3)
console.log (multByThree (10)) // 30
For a more generic curry implementation that works on functions of varying arity
const curry = (f, n = f.length, xs = []) =>
n === 0
? f (...xs)
: x => curry (f, n - 1, xs.concat ([x]))
If you want to bellyache about the exposed private API, hide it away with a loop – either way, this is not required to write functional programs in JavaScript
const loop = f =>
{
const recur = (...values) =>
f (recur, ...values)
return f (recur)
}
const curry = f =>
loop ((recur, n = f.length, xs = []) =>
n === 0
? f (...xs)
: x => recur (n - 1, xs.concat ([x])))
it fixes 3 as the first argument, the arguments of the new function will be preceded by 3
function multiply(a,b){
console.log(a, b);
console.log(arguments)
return a * b;
}
var multipleByThree = multiply.bind(console.log(this),3);
console.log(multipleByThree(10)) // outputs 30
console.log(multipleByThree(10, 15)) // outputs 30
passing this would provide a copy of this(i.e the global object) with the preceded arguments list
For more information check out the MDN docs
In the context of Currying the this object in the code presented has no purpose other than as a placeholder. You could replace this with the string "cats" if you wanted and still get the same result. It is simply there to occupy the first argument position and I think it is very misleading to use it in the context of
either currying or partial application when using bind. It is better to replace it with the null keyword.
In the case of this example it will pass in the global object and the rest of the code will simply ignore that value since the keyword 'this' is not present within the multiply function itself.
MDN shows a use case, visit https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
and scroll to the section headed Partially applied functions.
ES6 (aka es2015) has improved on the way this code is written by using arrow functions and the code can now be reduced to the following
const multiply = a => b => a * b
const multiplyByThree = multiply(3)
const result = multiplyByThree(10)
console.log(result)
// => 30

How can I write a JavaScript function that will call another function passed as a parameter?

I'm trying to write a JavaScript function that will integrate functions using Simpson's Rule. I fully understand the math behind Simpson's Rule, but I'm unsure of how to write a function that will integrate another function. Here's the code I'd like to implement:
integrate = function(leftBound, rightBound, numSubIntervals, expression) {
var a = leftBound,
b = rightBound,
n = numSubIntervals,
myFunc = expression;
/*implementation of simpson's rule..*/
return result;
}
My issue is that I don't know how to pass a mathematical expression (the function to be integrated) as a parameter without doing something like passing it as a string and using eval(), which is not something I want to do. I also don't want to use any third-party libraries. I want to write the function using vanilla JavaScript only. What am I missing here - is there an obvious solution to this?
Functions themselves can be arguments to other functions. For example:
integrate(0,5,10, function(x){
return x*x;
})
This example takes a function that takes a given X and squares it. Within integrate, you would call this function for given intervals of x to integrate this function using Simpson's rule.
Within integrate, the syntax for calling a function passed to it is:
var point = expression(x);
Where x is the value passed to the function named expression, and point is the return value of expression.
Here's my answer-version of my comment. You can pass the function as parameter and then call it from inside.
integrate = function(leftBound, rightBound, numSubIntervals, expression) {
var a = leftBound,
b = rightBound,
n = numSubIntervals,
myFunc = expression;
/*implementation of simpson's rule..*/
result = (b-a)/6 * (expression(a) + 4*f* ... );
return result;
}
var toIntegrate = function(x){
return 2*x*x*x - 3*x*x + 2*x - 1;
}
integrate(0, 10, 10, toIntegrate);

JSlint - make function within for loop vs. evaluating function

I have a a function that looks like this:
function strip(o) {
for (var i in o) {
var test = basic.arr.some(function(x) {return x === i} );
//JSlint -- don't make functions within loop
if (test)
delete o[i];
}
return o;
}
the code works and JSlint complains.
I understand that defining multiple functions with a loop' s repeating expression will end up in creating multiple functions each retaining the last repeating expression's value (because each loop doesn't have a distinct scope);
but in this case , since I'm evaluating the function right away, I can't think of a scenario where the actual value of i would change;
I've already resolved using a forEach method but would like to understand why this can eventually lead to problems.
fiddle
By enclosing that anonymous function declaration in for (var i in o) {, you're redefining it each time you iterate, not just once, regardless of whether or not it's "invoked immediately" -- and I'd point out your oversight of that redefinition as the reason you want to remove that construct from your code.
So you want to either get rid of for or you need to define the function earlier. I'm going to take "more" of JSLint's advice and get rid of the for as well.
This lints on JSLint.com as is:
/*jslint white:true, devel:true */
var obj = {
a: true,
b: true,
c: true
};
var basic ={
arr: ['a', 'b']
};
function strip(o) {
"use strict";
var test;
Object.keys(o).forEach(function (i) {
test = basic.arr.some(function (x) { return x === i; });
if (test) {
delete o[i];
}
});
return o;
}
strip(obj);
console.log(obj);

Evaluate one specific function in a JavaScript statement

I'm trying to mimic lazy evaluation in JavaScript by evaluating one specific function call in an expression, while leaving the other functions as-is. Is it possible to evaluate just one function in an expression without evaluating the other functions (so that all of the other function calls in the expression are left as-is)?
Here's the function I'm trying to implement:
function evaluateSpecificFunction(theExpression, functionsToEvaluate){
//Evaluate one specific function in the expression, and return the new expression, with one specific function being evaluated
}
For example:
evaluateSpecificFunction("addTwoNumbers(1, 2) + getGreatestPrimeFactor(10)", addTwoNumbers);
//This should return "3 + getGreatestPrimeFactor(10)", since only one of the functions is being evaluated
evaluateSpecificFunction("addTwoNumbers(1, 2) + getGreatestPrimeFactor(10)", getGreatestPrimeFactor);
//This should return "addTwoNumbers(1, 2) + 5";
What you can do is play with replace and a regular expression :
function getGreatestPrimeFactor(n) {
return n*2;
}
function transform(s, f) {
return s.replace(new RegExp(f+"\\(([^\\)]*)\\)", "g"), function(m, args) {
return window[f].apply(null, args.split(',').map(function(v){
return parseFloat(v)
}));
});
}
var result = transform(
"addTwoNumbers(1, 2) + getGreatestPrimeFactor(10)",
"getGreatestPrimeFactor"
);
This example assume you deal only with numeric parameters.
Demonstration (open the console)
Of course this code mostly demonstrate the idea, you should, for example, store the functions in a dedicated object and not the global context (window).
EDIT : the new version can handle more than one replacement.

Categories