Breaking change with this and #each and String Objects?


#1

Hello everyone,
has there been a recent breaking change i missed about $each or this ?
One user reported me today a bug i find strange :
I am using the usual blaze construct with #each

{{#each arrayOfStrings}}
  <div class="checkbox">
    <input type="checkbox"> {{this}}
  </div>
{{/each}}

I have an onclick event handler on the checkbox class
The problem is that in the eventHandler, this is not a String Primitive, but a String Object (Wrapper Object), with typeof this = 'object'

I have doublechecked, the arrayOfStrings which is returned by a template helper contains String primitives and not String object.

This code has been working correctly for more than a year, so i guess it has been broken by a recent blaze change.

Thank you in advance


#2

I think it’s a bug.
Minimal repro here:


I’m gonna file an issue.


#3

#4

You should include the .meteor so it can be run, and we can see the package versions you are using. Ignore the .meteor/local directory instead.


#5

I dont want to be rude, but how exactly that minimal repo should help someone?
You dont show us in any way what is not working in your event handler.
If we see how you are trying to use event or template instance than we can comment.
Maybe you are doing something wrong way there.


#6

Don’t want to be rude, but have you read the readme ?


#7

Create a new GitHub repository with a name … and push your code to it. (Make sure to include the .meteor/packages and .meteor/release files!)

No need for anyone to be rude, when the intent here is to be helpful.


#8

Ok, don’t bother, i will stick with meteor issue reporting.


#9

Well, as usual, just wrong testing
If issue is with spacebars “this” you need to access it as spacebars “this”

Try this

bugtest:html

<head>
  <title>bugtest</title>
</head>

<body>
  <h1>Each test</h1>
  {{> hello}}
</body>

<template name="hello">
  {{#each testField}}
    {{this}} is type: {{printType this}} <br/>
  {{/each}}
</template>

and bugtest.js

if (Meteor.isClient) {

  Template.hello.helpers({
    printType: function (testInput) {
      return typeof testInput;
    },
    testField: function () {
      return ["car", "submarine", "plane"];
    }
  });
}

And the output

car is type: string 
submarine is type: string 
plane is type: string

If you replace one of strings in array by number, it detects it as number etc…


#10

I don’t see what your code has to do with the issue i’m having.

I’m just saying that in the past, this in event handler when used with string elements generated with #each was of type String, but is now of type Object.
This change broke my code in production, which has been working fine for the 9 last months.
I was askin if this was a known breaking change or a regression. I would bet for the latter since i don’t know why this in the event handler would be of type string object and not string primitive.


#11

Key word here is “in the event handler”, not in the rendered template or helpers.


#12

This seems to be what is happening:
https://github.com/meteor/meteor/tree/devel/packages/spacebars#with

If the argument to #with is a string or other non-object value, it may be promoted to a JavaScript wrapper object (also known as a boxed value) when passed to helpers, because JavaScript traditionally only allows an object for this. Use String(this) to get an unboxed string value or Number(this) to get an unboxed number value.


#13

You seems to be right Jorgeer. I didn’t know you could not use a primitive value as this.
What i’m now wondering is why this has been working fine in the past.
Thank you for your help.


#14

I could be a side effect of the new {{#each person in persons}} syntax shipped with 1.2, but I don’t see #each documentation mentioning String(this), so either way, there was really a discrepancy you found, if it worked before :smile:


#15

The problem is that if indeed this as primitive is not legal (and that seems pretty logical when you think about it, this is always referring to an Object), there is not a chance the old way is coming back.
I am currently auditing the broken module in my app, and i’m contemplating with horror that i have used this as a string primitive numerous times in this only module… i’m wondering how many loc are broken in my app because of this !
I’m starting to believe that those that advise to stay away from this have a pretty good point indeed !


#16

I don’t know if it’s useful for you @vjau but you can use valueOf() to assert the primitive.


#17

Garrilla, that what i first wrote, but then i thought it was better to use String(this), because this.valueOf() or this.toString() will throw if this is undefined (i don’t know if this can happen…).