Search code examples
javascriptasynchronouspolymer

Empty value on Polymer computed attribute


I am trying to use computed attribute in Polymer but I always get an empty value. In this case I have an attribute in my custom element called datagraph. And I make a post request to a server, get a JSON file, calculate the result and then show it. This is my custom element:

<dom-module id="cost-card">
  <template>
    <style>
      p.datos3{
        color: #10cebc;
        text-align: center;
        font-size: 22px;
        margin-top: 0px;
      }
    </style>  
    <p class="datos3">{{datagraph}}</p>  
  </template>
  <script>
    Polymer({
      is: "cost-card",

      properties:{
    usr:{
      type: Number,
      value: 2
    },
    command:{
      type: String,
      value: "SP_GetCostoCampania"
    },  
    datagraph:{
      type: Number,
      computed: 'getCost(command,usr)'
    }
  },

      getCost: function(command,usr){

        var options = {
          hostname: 'localhost',
          path: '/',
          port: 8081,
          secure: false,
          method: 'POST',
          headers: {
            'x-powered-by': 'HTTPClient.js'
          },
          'Content-Type': 'application/json'
        }

        var innerCost;

        var example1 = new HTTPClient(options);
        example1.post("/executeGraph1?command="+ command + "&param1=" + usr, function (err, res, body) {

          body = JSON.parse(body);

          innerCost = body[0].price * body[0].exchengeRate;
        });

        return innerCost;
      }
    });
  </script>
</dom-module>

I have an express server running, information is being delivered correctly but the {{datagraph}} tag keeps empty. I think it may be because the post request is an anychronous task, and the value is being delivered later but I have also tried using Promise with the same result.

Does anyone know the proper way to do this?


Solution

  • As you've hinted, getCost is always going to return undefined because return innerCost is going to execute before the post's callback.

    Computed properties are meant to take in other properties as arguments and are designed to be synchronous. If getCost took in some argument, even then you would want to use an observer that directly sets this.datagraph within the callback.

    Since you aren't feeding any arguments into getCost, I would suggest you instead use a ready callback that makes the post request and sets this.datagraph within the callback.

    For example:

    Polymer( {
        is: "cost-card",
    
        properties: {
            usr: { type: Number, value: 2 },
            command: { type: String, value: "SP_GetCostoCampania" },
            datagraph: Number
        },
    
        observers: [ "getCosto(command, usr)" ],
    
        getCosto: function ( command, usr ) {
    
            var options = {
                hostname: "localhost",
                path: "/",
                port: 8081,
                secure: false,
                method: "POST",
                headers: { "x-powered-by": "HTTPClient.js" },
                "Content-Type": "application/json"
            };
    
            const uri = `/executeGraph1?command=${command}&param1=${usr}`;
            new HTTPClient( options ).post( uri, ( err, res, body ) => {
    
                // values have changed, ignore result (ideally cancel the HTTP request)
                if ( command !== this.command || usr !== this.usr ) return;
    
                body = JSON.parse( body );
    
                this.datagraph = body[ 0 ].price * body[ 0 ].exchengeRate;
    
            } );
    
        }
    
    } );