Danprime
Danprime

Reputation: 240

How to Bind Attribute from Custom Polymer Element to angularjs

I created a custom element called my-slider-input which computes values from a user input. I need to take use these values in an angular controller. I'm wondering what's the best practice to do this?

Given this polymer element:

<dom-module id="my-slider-input">
    <style>
      :host {
        display: block;
      }
    </style>
  <template>    
    <button id="input1">Input 1</button>
    <button id="input2">Input 1</button>
    <button id="input3">Input 1</button>
  </template>
</dom-module>
<script>
  (function() {
    Polymer({
      is: 'my-slider-input',
      properties: {

        value: {
          type: Object,
          computed: 'computeOutputs()',
          reflectToAttribute: true,
          notify: true
        },
        output1: {
          type: Number,
          reflectToAttribute: true,
          notify: true
        },
        output3: {
          type: Number,
          reflectToAttribute: true,
          notify: true
        },
        output2: {
          type: Number,
          reflectToAttribute: true,
          notify: true
        }
      },
      listeners: {
        'input1.down': 'computeOutputs',
        'input2.down': 'computeOutputs',
        'input3.down': 'computeOutputs'
      },
      attached: function() {
          //Fired when this component is attached.
          this.computeOutputs();
      },
      computeOutputs: function() {
        var aggregateValue = {};

        this.output1 = this.complexFunction(1);
        this.output2 = this.complexFunction(2);
        this.output3 = this.complexFunction(3);

        aggregateValue.output1 = this.output1;
        aggregateValue.output2 = this.output2;
        aggregateValue.output3 = this.output3;

        return aggregateValue;
      },
      complexFunction: function(input) {

        //some complex calculations
        return 1;   
      }
    });
    })();
  </script>

I want to get the outputs of my-slider-input, I know I can create/listen for event notifications. How can I get the output for an angularjs controller?

How do I do something like this?

<div ng-Controller="myController">
    <my-slider-input value="{{outputAggregateValue}}"></my-slider-value>
</div>

or

Should I do something like this?

<div ng-Controller="myController">
    <my-slider-input output1="{{output1}}" output2="{{output2}}" output1="{{output3}}"></my-slider-value>
</div>

Currently in either scenario, the $scope values are not updated.

If this isn't the best way (2-way vs 1-way), how do I get the output out of my custom element and work with it in my controller?

Here's a jsbin link: http://jsbin.com/kosetiyelu/edit?html,output

Thanks in advance! -Dan

Upvotes: 1

Views: 1630

Answers (3)

mbello
mbello

Reputation: 111

I am using ng-polymer-elements to do what you describe, it supports many polymer components out of the box and provides an easy way to add your own mappings for custom/other unsupported components.

Check here: https://gabiaxel.github.io/ng-polymer-elements/

From their documentation: "There are two cases where you can't get Web Components to work with your AngularJS models:

  1. Having Web Components update your model, for example <paper-input value="{{myModel}}"></paper-input> will not change myModel when the user changes the input text.
  2. Binding anything other than a string, for example <google-map map="{{myMap}}"><google-map> will not work because the expression {{myMap}} will be treated as a string. Enters ng-polymer-elements."

Upvotes: 1

alesc
alesc

Reputation: 2782

I believe it is best to use the angular-bind-polymer directive from here. The code is already written and it is working, so no need for you to implement it by yourself.

Instructions from the aforementioned page:

This will only work if the Polymer element publishes and reflects attributes. That is, it is insufficient to declare attributes:

To mark the out attribute as reflectable, declare it as such with the publish property:

Your element should therefore look like this:

<polymer-element name="x-double" attributes="in out">
  <template><!-- ... --></template>
  <script>
    Polymer("x-double", {
      publish: {
        out: {value: 0, reflect: true}
      },
      // ...
    });
  </script>
</polymer-element>

After that, just add the bind-polymer to your custom elements within the HTML code.

EDIT: Since the author is using Polymer 1.0, I have found another tutorial for passing data from Polymer to Angular: http://jcrowther.io/2015/05/26/using-polymer-webcomponents-with-angular-js/. In this tutorial, angular-bind-polymer is also used so I don't think the plugin is Polymer 0.5 specific.

EDIT 2: I have now noticed that the above tutorial does not use Polymer 1.0, but Polymer 0.9.

Upvotes: 1

Scott Miles
Scott Miles

Reputation: 11027

I can only help you with the Polymer side of your question, but here goes.

The code in your question looks like proper Polymer 1.0 code, but the code in the JS Bin is mixed up between Polymer 0.5 and 1.0. @alesc's answer is only for 0.5, so there is version confusion.

Fwiw, here is a JsBin with proper Polymer 1.0 code: http://jsbin.com/vevawi/edit?html,output

If you examine the output you can see that Polymer is reflecting the values back to the attributes as requested. As for why Angular is not picking them up, I can't help you.

Fwiw, because of the notify: true settings, Polymer is also sending property-change events. Specifically, the my-slider-input is sending object1-changed, object2-changed, object3-changed, and value-changed (non-bubbling) events. Maybe you can use those to update the values in the Angular scope.

Upvotes: 1

Related Questions