I'm trying to implement a simple function in pure lodash way.
function forward(i) => {
return (j) => {
return String.fromCharCode(i + j)
}
}
So that I can do _.range(26).map(forward(65)). Take me some time to make this work:
function a = _.wrap(String.fromCharCode, (fn, a, b) => fn(a + b))
function b = _.ary(a, 2)
function forward = _.curry(b)
Now my question is is there an easier way to do this? and how do I use sum to construct (fn, a, b) => fn(a + b)?
One last thing is I couldn't find wrap function file in Lodash repo.
The function _.curry(...) is kind of strange when it comes to calling functions with various parameters. Let me guide you with an example below.
The ary-function (_.ary(..., 2)) takes any function and ensures its never called with more than a specific amount of arguments (in this case two). Less arguments than specified, will just end up calling the underlying function with less arguments. A definition of this function could look like this:
function ary() {
const args = arguments;
// implementation
}
There is no way to tell how many arguments the function is expecting, as you would with a function with actual parameters (function(a, b) { }). If you would define const forward1 = _.curry(_.ary(target, 2)), and call it with forward1(42)(2), the curry function would just pass down the first argument to ary as it thinks its done.
We can get around this by using an overload of curry that specifies how many parameters the underlying function is expecting (const forward2 = _.curry(target, 2)). Only in the case where forward2 is called in a curry-style (not sure what its even called) with two parameters, it passes it down to target. A call with one argument will just return a new function, waiting for it to be called with the second argument. Now we can get rid of the ary-call, as it serves us no purpose anymore.
As for chaining actions, there's a helper for that. For example: c(b(a(...) can be rewritten to _.flow([a, b, c]). Lodash also provides a function for a + b, which is _.add().
Together your problem can be rewritten to:
const forward = _.curry(_.flow([_.add, String.fromCharCode]), 2);
or more verbose:
const methods = _.flow([
_.add,
String.fromCharCode
]);
const forward = _.curry(methods, 2);
Note that the 2 corresponds to the amount of parameters the _.add method expects.
Related
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}}
How to debug lodash chain functions in browser.
Ex:
if (_.size(_.values(_.omit(this.user, 'language')).filter(Boolean)) < 2)
If we want to debug _.omit(this.user, 'language') and then the end result with another function _.values() as shown in the example,what should be done.
I tried searching but can only find console.log but if we want to debug right in the browser how can we do it.
Chain functions and lodash sequences are usually "debugged" or "tapped" into via _.tap or _.thru:
tap: This method invokes interceptor and returns value. The interceptor is
invoked with one argument; (value). The purpose of this method is to
"tap into" a method chain sequence in order to modify intermediate
results.
so something like this:
const obj = { name: 'Ace', language: 'English', age: 3 }
const result = _(obj)
.tap(x => console.log(x))
.omit('language')
.tap(x => console.log(x))
.omit('age')
.tap(x=> console.log(x))
.value()
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
thru: This method is like _.tap except that it returns the result of
interceptor. The purpose of this method is to "pass thru" values
replacing intermediate results in a method chain sequence.
I have below code to create column:
DTColumnBuilder.newColumn(null).withTitle('Validation').renderWith(validationRenderer)
and render function:
function validationRenderer(data, type, full, meta) {
.......
}
Now, I want to pass custom parameters to validationRenderer so that I can access it inside the function, like below:
DTColumnBuilder.newColumn(null).withTitle('Validation').renderWith(validationRenderer('abc'))
function validationRenderer(data, type, full, meta, additionalParam) {
// do something with additionalParam
}
I could not find it in the documentation but there must be something to pass additional parameters in meta as per the reference from here
Yes, you can. Or, better, you technically can, but you may use a clever workaround to handle your issue.
I had this issue today, and found a pretty sad (but working) solution.
Basically, the big problem is that the render function is a parameter passed to the datatable handler, which is (of course) isolated.
In my case, to make a pratical example, I had to add several dynamic buttons, each with a different action, to a dynamic datatable.
Apparently, there was no solution, until I thought the following: the problem seems to be that the renderer function scope is somewhat isolated and unaccessible. However, since the "return" of the function is called only when the datatable effectively renders the field, you may wrap the render function in a custom self-invoking-anonymous-function, providing arguments there to use them once the cell is being rendered.
Here is what I did with my practical example, considering the following points:
The goal was to pass the ID field of each row to several different custom functions, so the problem was passing the ID of the button to call when the button is effectively clicked (since you can't get any external reference of it when it is rendered).
I'm using a custom class, which is the following:
hxDatatableDynamicButton = function(label, onClick, classNames) {
this.label = label;
this.onClick = onClick;
this.classNames = this.classNames || 'col5p text-center';
}
Basically, it just creates an instance that I'm later using.
In this case, consider having an array of 2 different instances of these, one having a "test" label, and the other one having a "test2" label.
I'm injecting these instances through a for loop, hence I need to pass the "i" to my datatable to know which of the buttons is being pressed.
Since the code is actually quite big (the codebase is huge), here is the relevant snippet that you need to accomplish the trick:
scope.datatableAdditionalActionButtons.reverse();
scope._abstractDynamicClick = function(id, localReferenceID) {
scope.datatableAdditionalActionButtons[localReferenceID].onClick.call(null, id);
};
for (var i = 0; i < scope.datatableAdditionalActionButtons.length; i++) {
var _localReference = scope.datatableAdditionalActionButtons[i];
var hax = (function(i){
var _tmp = function (data, type, full, meta) {
var _label = scope.datatableAdditionalActionButtons[i].label;
return '<button class="btn btn-default" ng-click="_abstractDynamicClick('+full.id+', '+i+')">'+_label+'</button>';
}
return _tmp;
})(i);
dtColumns.unshift(DTColumnBuilder.newColumn(null).notSortable().renderWith(hax).withClass(_localReference.classNames));
}
So, where is the trick? the trick is entirely in the hax function, and here is why it works: instead of passing the regular renderWith function prototype, we are using a "custom" render, which has the same arguments (hence same parameters) as the default one. However, it is isolated in a self invoking anonymous function, which allows us to arbitrarely inject a parameter inside it and, so, allows us to distinguish, when rendering, which "i" it effectively is, since the isolated scope of the function is never lost in this case.
Basically, the output is as follow:
And the inspection actually shows that elements are effectively rendered differently, hence each "i" is being rendered properly, while it wouldn't have if the function wouldn't have been wrapped in a self invoking anonymous function:
So, basically, in your case, you would do something like this:
var _myValidator = (function(myAbcParam){
var _validate = function (data, type, full, meta) {
console.log("additional param is: ", myAbcParam); // logs "abc"
return '<button id="'+myAbcParam+'">Hello!</button>'; // <-- renders id ="abc"
}
return _validate ;
})('abc');
DTColumnBuilder.newColumn(null).withTitle('Validation').renderWith(_myValidator);
// <-- note that _myValidator is passed instead of "_myValidator()", since it is already executed and already returns a function.
I know this is not exactly the answer someone may be expecting, but if you need to accomplish something that complex in datatable it really looks like the only possible way to do this is using a self invoking anonymous function.
Hope this helps someone who is still having issues with this.
I use cucumber and chai-as-promised as assertion library. What is the right way to check the count value. I use equal but it works only after converting string to integer.Is there a way to assert a integer value directly?
this.Then(/^the list should contain "([^"]*)" items$/, function (arg1, callback) {
var count=parseInt(arg1);
expect(element.all(by.repeater('item in list.items')).count()).to.eventually.equal(count).and.notify(callback);
});
If you really wanted to, I believe you could bypass parseInt() by using Chai's satisfy() method and JavaScript coercion, as shown below. However, I personally prefer the method you are currently using as it is easier to understand and coercion can be tricky.
this.Then(/^the list should contain "([^"]*)" items$/, function (arg1, callback) {
expect(element.all(by.repeater('item in list.items')).count()).to.eventually.satisfy(function(count) { return count == arg1 } ).and.notify(callback);
});
var take = R.curry(function take(count, o) {
return R.pick(R.take(count, R.keys(o)), o);
});
This function takes count keys from an object, in the order, in which they appear. I use it to limit a dataset which was grouped.
I understand that there are placeholder arguments, like R.__, but I can't wrap my head around this particular case.
This is possible thanks to R.converge, but I don't recommend going point-free in this case.
// take :: Number -> Object -> Object
var take = R.curryN(2,
R.converge(R.pick,
R.converge(R.take,
R.nthArg(0),
R.pipe(R.nthArg(1),
R.keys)),
R.nthArg(1)));
One thing to note is that the behaviour of this function is undefined since the order of the list returned by R.keys is undefined.
I agree with #davidchambers that it is probably better not to do this points-free. This solution is a bit cleaner than that one, but is still not to my mind as nice as your original:
// take :: Number -> Object -> Object
var take = R.converge(
R.pick,
R.useWith(R.take, R.identity, R.keys),
R.nthArg(1)
);
useWith and converge are similar in that they accept a number of function parameters and pass the result of calling all but the first one into that first one. The difference is that converge passes all the parameters it receives to each one, and useWith splits them up, passing one to each function. This is the first time I've seen a use for combining them, but it seems to make sense here.
That property ordering issue is supposed to be resolved in ES6 (final draft now out!) but it's still controversial.
Update
You mention that it will take some time to figure this out. This should help at least show how it's equivalent to your original function, if not how to derive it:
var take = R.converge(
R.pick,
R.useWith(R.take, R.identity, R.keys),
R.nthArg(1)
);
// definition of `converge`
(count, obj) => R.pick(R.useWith(R.take, R.identity, R.keys)(count, obj),
R.nthArg(1)(count, obj));
// definition of `nthArg`
(count, obj) => R.pick(R.useWith(R.take, R.identity, R.keys)(count, obj), obj);
// definition of `useWith`
(count, obj) => R.pick(R.take(R.identity(count), R.keys(obj)), obj);
// definition of `identity`
(count, obj) => R.pick(R.take(count, R.keys(obj)), obj);
Update 2
As of version 18, both converge and useWith have changed to become binary. Each takes a target function and a list of helper functions. That would change the above slightly to this:
// take :: Number -> Object -> Object
var take = R.converge(R.pick, [
R.useWith(R.take, [R.identity, R.keys]),
R.nthArg(1)
]);