angular-custom-elements
angular-custom-elements copied to clipboard
Polymer throws warning "Unable to parse JSON"
Custom Elements upgrade the moment they're inserted and parsed. This means one of two things can happen depending on the kind of binding being used:
Interpolated Binding
// Assume baz=[1,2,3]
<x-foo bar="{{baz}}">
- Initially the element will see "{{baz}}" as the value for
bar. - Angular will fulfill the binding, transforming it into `
If the element is expecting an Array, Polymer will throw a warning because it initially tried to call JSON.parse("{{baz}}"), before Angular fulfilled the binding
Angular 1.5 Input style
// Assume baz=[1,2,3]
<x-foo bar="$ctrl.baz">
- Angular will leave the
$ctrl.bazsyntax in the DOM forever - If you're using the
ce-one-wayit will set the propertybar=[1,2,3]. Note that we're setting a property binding here, not doing string interpolation in the attribute
Similar to above, the element will initially call JSON.parse("$ctrl.baz"), the JSON parse will fail and it'll throw a warning, and then the directive will kick in and fulfill the value.
Another thing to note is how Polymer's handling the JSON.parse. https://github.com/Polymer/polymer/blob/master/src/micro/attributes.html#L199-L214
Note line 211 which sets value=null. THIS WILL CAUSE OBSERVERS TO RUN. Even though the value is null, observers run for any value change (except if the value is undefined). Polymer should set this value back to undefined. Issue filed @ https://github.com/Polymer/polymer/issues/3860
Unfortunately I haven't been able to figure out how to modify the template before it hits the page. This means we likely need to use a custom syntax for doing Angular -> Polymer bindings :(
We have tested out multiple approaches for fixing this, but have been unable to find a way to change this before polymer kicks in. If you defer the loading of polymer this only fixes it on first load, not when you load the next page.
My best solution so far has been to use ng-attr-*, where angular will set the attribute itself, and the collision is solved unless you also use ngAttr*as a prop in your element 😛
I then use my own directive similar to this, but with double binding support for ng-attr.
It's not perfect, but you don't need to do
if (/\{\{.+\}\}/.test(val)) { return; }
or similar in your computed's which is way worse.
(^for a String property. for Object/Array you need to test for null after the failed parse)
yeah I've thought about recommending ng-attr-*. It's kind of a bummer because then you're serializing everything to strings and then parsing them again in Polymer. But it might be the only way around the issue
yeah it isn't ideal, but angular 1.x and polymer isn't that great of a match unfortunately.