Ember Handlebars Confusion With Passing In Values - ember.js

I currently have a helper that looks like:
Ember.Handlebars.registerHelper('ifEq', function(a, b, opts) {
if (a == b) {
return opts.fn(this);
} else {
return opts.inverse(this);
}
});
and in my template, I do
GRAPH_TYPE: {{graphType}}
{{#ifEq graphType "p_graph"}}
TEST1
{{else}}
TEST2
{{/ifEq}}
However, this displays
GRAPH_TYPE: p_graph TEST2
This leaves me confused as there should be an exact string match above.
So, I dug into the web inspector and noticed that the value of a in the Handlebars helper was of the value graphType. Why wasn't the value passed in and how do I ensure that it is passed in?

You need to register it as a bound helper:
Ember.Handlebars.registerBoundHelper('ifEq', function(a, b, opts) {
^ like so
When you register a normal/basic helper, you're going to see the parameters passed in by string value as you're witnessing.
However, if you want the argument strings to be bound to properties in your template (which, in this case, you do), you need to use the function signature above.

Related

Recompute Ember custom helper on change of a controller property that is passed to the helper

I'm changing the value of a property in my controller and the helper fails to recompute them.
Sample code here:
My template looks like,
{{#if (my-helper info)}}
<span>Warning</span>
{{/if}}
In my controller,
changeAction: function() {
let that = this,
info = that.get("info");
set(info, "showWarning", true);
}
my helper,
import { helper as buildHelper } from '#ember/component/helper';
export default buildHelper(function(params) {
let that = this,
info = that.get("info");
if(info.showWarning ) {
return true;
} else {
return false
}
});
I see several issues with your code:
The template helper seems to get an object as it's first and only position param: {{my-helper info}} while info is { showWarning: true }. A template helper does recompute if the value passed it changes but not if a property of that value changes. A quick fix would be {{my-helper info.showWarning}}.
In your template helper your are trying to access the property on it's this context. As far as I know that's not supported. As you are using a positional param and it's the first one, it's available as first entry inparams array. So your template helper should look like:
export default buildHelper(function([info]) {
if(info.showWarning ) {
return true;
} else {
return false
}
});
What version of Ember are you using? If it's >= 3.1 you don't need to use this.get() in your controller. If you are using Ember < 3.1 you need to use info.get() also in template helper.
But as described before I would not recommend passing an object to a template helper as it's only updated if the object itself is replaced. Changing a property of it is not enough. You might be able to do so using Class-based Helpers but I wouldn't recommend to do so as it's error prune.

Ember hasMany and size of array(s)

I have a relation hasMany and I want get the next index number. So, in my controller I have :
nextStepIndex: Ember.computed(function () {
return this.get('floor').get('steps').get('length') + 1;
}).property('nextStepIndex')
I used too :
nextStepIndex: Ember.computed(function () {
return this.get('floor').get('steps.length') + 1;
}).property('nextStepIndex')
But the length is always 0. The step is not saved and the floor too. All object was just created with createdRecord and the step is added with pushObject.
I saw in the steps relation they have a lot or array :
DS.PromiseManyArray
DS.PromiseArray
ArrayProxy
MutableArray
Array
My "step" object is in the ArrayProxy. So when I call the length method what size I will obtain?
So, if I can get the child record in the {{#each}} template directive, I expect to have the right size when I call the length method.
I known I can get the ArrayProxy size, but I don't want make a assumption on the implementation.
It looks as if your "property" is not set correctly
property('floor.steps.[]')
Also keep in mind it won't get triggered unless you call it from template or use it in another relation in component/controller.
Btw if your're dealing with async "steps" then computed property wont just do it out of box. You would need to use
nextStepIndex: function() {
var stepsPromise = this.get('floor.steps');
return DS.PromiseArray.create({
promise: stepsPromise.then(function(steps) {
// return your logics here
})
});
}.property('floor.steps.[]')

If comparison in each loop with parent variable using handlebars

The problem is setup on JSFiddle: https://jsfiddle.net/sshadmand/fNPvf/16812/
Given ...
The data passed to the template is:
{
"curr_level": 0,
"levels" : [item1, item2, item3 ...]
}
The handlebars template is:
<div>
{{#each levels}}
{{../curr_level}} == {{#index}}
{{#ifeq ../../curr_level #index}}yes{{else}}no{{/ifeq}}
{{/each}}
</div>
The #ifeq helper function is:
Handlebars.registerHelper('ifeq', function(val1, val2, options) {
console.log("if equal", val1, typeof(val1), val2, typeof(val2));
if (val1 == val2){
return options.fn(this);
}
return options.inverse(this);
});
The problem is:
Accessing the parent curr_level variable using ../ works to print the value to the screen, but when the curr_level variable is sent to the helper it is undefined. I have tried passing different depths to the helper e.g. curr_level, ../curr_level, ../../curr_level etc
For all depths "val1" in the helper is undefined. Again, I am able to access the curr_level variable when it is not using the comparison helper.
Note: This is similar to, but very different from this SO question asking about parents. The main difference being I am trying to pass the parent variable to a helper function:
Access properties of the parent with a Handlebars 'each' loop

How to compare special fields in google mock?

I have got question connected with google test. I would like to ask if while inducing "EXPECT_CALL(*A, some_method(mes1));" in test case there is possiblity to compare fields included
in mes1 class.
struct Mes
{
int a;
};
//short section of test case:
Mes mes1 = Mes();
EXPECT_CALL(*A, some_method(mes1));
I would like to ask if in google mock is a possiblity to compare special fields included in Mes. Something like:
EXPECT_CALL(*A, some_method(mes1), compare(Mes.a));//in this case google mock would compare only field "a" from Mes.
It depends on what you want to do with the result of the comparison. If you simply want to query the value of the field, you can simply define a function to do something with it:
// Note: The signature of someFunction needs to match some_method.
void someFunction(const Mes& mes)
{
// Do something with mes.a
}
Then set up your expectation as follows:
EXPECT_CALL(*A, some_method(mes1)).WillOnce(Invoke(someFunction));
Note that if some_method returns a value, you may also have to provide a Return action.
Alternatively, if you want your test to fail if the field isn't some specific value, you need to write a custom matcher:
MATCHER_P(MesFieldEq, val, "")
{
return (arg.a == val);
}
Then use it in your expectation as follows:
// Fails unless mes.a is equal to 42.
EXPECT_CALL(*A, some_method(MesFieldEq(42));

Handlebars.registerHelper - Way to get content of Block?

is there a way in registerHelper to get the content of a block?
Lets assume we have the following template:
{{#myif test}}thats the content i want to have{{/myif}}
And the following registerHelper Code:
Ember.Handlebars.registerBoundHelper('myif', function(test)
{
// do something
return <content of handlebars block>;
});
Many thanks!
Handlebars provides the nested block to the helper as options.fn, where options is the last argument of your helper. You can invoke this block with a context object which is where that block will pick up values from.
To pass the context of the helper itself you can call it with this.
In this case you will probably also want options.inverse which is an optional block that will be used if your condition is false.
Ember.Handlebars.registerHelper('myif', function(condition, options) {
if (condition) {
return options.fn(this);
} else {
return options.inverse(this);
}
});
And the subsequent use in the template,
{{#myif condition}}
true block here
{{else}}
else block here
{{/myif}}