robdodson / angular-custom-elements

Polymer directive to hold all yr bindings together
23 stars 4 forks source link

Polymer throws warning "Unable to parse JSON" #4

Open robdodson opened 8 years ago

robdodson commented 8 years ago

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}}">
  1. Initially the element will see "{{baz}}" as the value for bar.
  2. 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">
  1. Angular will leave the $ctrl.baz syntax in the DOM forever
  2. If you're using the ce-one-way it will set the property bar=[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

robdodson commented 8 years ago

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 :(

kasperstorgaard commented 7 years ago

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)

robdodson commented 7 years ago

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

kasperstorgaard commented 7 years ago

yeah it isn't ideal, but angular 1.x and polymer isn't that great of a match unfortunately.