paper-datatable icon indicating copy to clipboard operation
paper-datatable copied to clipboard

Formatting function not working

Open go4cas opened this issue 8 years ago • 14 comments

I have the following table column definition:

<paper-datatable-column header="amount" property="paymentAmount" format-value="{{cellCurrencyFormat}}" align="right"></paper-datatable-column>

The cellCurrencyFormat function is in an external script file, containing helper functions that are used throughout the application.

cellCurrencyFormat = function (value) {
  var cellFormat = formatCurrency (value, 'R', 2);
  console.log(cellFormat);
  return cellFormat;
};

This function is a wrapper around the main formatting function:

function formatCurrency (value, currency, precision) {
  if (!value) {
    return '';
  };
  if (isNaN(value)) {
    return "Value is not a Number";
  } else {
    currency = currency || "$";
    precision = precision || 2;
    value = Number(value);
    value = value.toFixed(precision);
  }
  var parts = value.split('.'),
    fnum = parts[0],
    decimal = parts[1] ? '.' + parts[1] : '';
  return currency + fnum.replace(/(\d)(?=(?:\d{3})+$)/g, '$1,') + decimal;
};

The console.log in the cellCurrencyFormat does not fire at all.

go4cas avatar Dec 28 '15 08:12 go4cas

For now, I've managed to get this working, by using <templates>:

<paper-datatable-column header="amount" property="paymentAmount" align="right">
    <template>
         <span>{{cellCurrencyFormat(value)}}</span>
    </template>
</paper-datatable-column>

With the cellCurrencyFormat wrapper function local to the custom element.

go4cas avatar Dec 28 '15 09:12 go4cas

Are you using the paper-datatable inside of another custom element or inside of a dom-bind? In the first case you need to define the value on the parent Polymer element and in the second case on the dom-bind. Does this sound alien or is this exactly what you've been trying already?

David-Mulder avatar Dec 28 '15 11:12 David-Mulder

@David-Mulder, it's inside a custom element. What do you mean by "define the value on the parent Polymer element"?

go4cas avatar Dec 28 '15 11:12 go4cas

So you have something along the lines of

 <dom-module>
   <template>
     <paper-datatable [...]>
       <paper-datatable-column [...] format-value="{{cellCurrencyFormat}}"></paper-datatable-column>
     </paper-datatable>
  </template>
  <script>
    Polymer(
      [...]
      cellCurrencyFormat: function(){
        [...]
      }
    );
  </script>
</dom-module>

?

David-Mulder avatar Dec 29 '15 08:12 David-Mulder

tal-ui-order-payment.html

<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../content-widget/content-widget.html">
<link rel="import" href="../status-icon/status-icon.html">
<link rel="import" href="../progress-stepper/progress-stepper.html">
<link rel="import" href="../tal-ui-content-row/tal-ui-content-row.html">
<link rel="import" href="../../bower_components/byutv-jsonp/byutv-jsonp.html">
<link rel="import" href="../../bower_components/paper-datatable/paper-datatable.html">

<dom-module id="tal-ui-order-payment">
  <template>
    <style>
      paper-datatable {
        margin: 0px;
        --paper-datatable-column-header: {
          display: none;
        }
        --paper-datatable-divider-color: transparent;
        --paper-datatable-cell: {
          color: #000;
          font-size: 0.9em;
          font-weight: 400;
          height: auto;
          line-height: 1.1em;
          white-space: nowrap;
          padding: 2px 10px 2px 10px;
          cursor: default;
        }
      }
    </style>
    <byutv-jsonp
      auto
      url="http://localhost:3030/orders/{{order-id}}/payment"
      last-response="{{order}}"
      handle-as="json"
      loading="{{loading}}">
    </byutv-jsonp>
    <content-widget heading="payments and refunds" loading={{loading}}>
      <progress-stepper steps="[[order.data.timeline]]"></progress-stepper>
      <div class="content-container" hidden$="{{!order.data.payments}}">
        <p class="section-heading">payments</p>
        <paper-datatable data="{{order.data.payments}}">
          <paper-datatable-column header="method" property="paymentType"></paper-datatable-column>
          <paper-datatable-column header="amount" property="paymentAmount" align="right">
            <template>
              <span>{{_cellCurrencyFormat(value)}}</span>
            </template>
          </paper-datatable-column>
          <paper-datatable-column header="status" property="paymentState">
            <template>
              <span>
                <status-icon status="{{value}}"></status-icon>
              </span>
            </template>
          </paper-datatable-column>
        </paper-datatable>
      </div>
      <div class="content-container">
        <p class="section-heading">authorization</p>
        <tal-ui-content-row title="status" value-content="{{order.data.Auth}}" value-type="text" value-health="{{order.data.health.statusHealth}}"></tal-ui-content-row>
        <tal-ui-content-row title="auth date" value-content="{{order.data.AuthDate}}" value-type="text" value-format="date" hidden$="{{!order.data.AuthDate}}"></tal-ui-content-row>
        <tal-ui-content-row title="amount" value-content="{{order.data.Total}}" value-type="text" value-format="currency" hidden$="{{!order.data.Total}}"></tal-ui-content-row>
        <tal-ui-content-row title="by" value-content="{{order.data.AuthUser}}" value-type="text" hidden$="{{!order.data.AuthUser}}"></tal-ui-content-row>
      </div>
    </content-widget>
  </template>
  <script>
  (function() {
    'use strict';

    Polymer({
      is: 'tal-ui-order-payment',
      _cellCurrencyFormat: function (value) {
        if (value != undefined) {
          var cellFormat = formatCurrency (value, 'R ', 2);
          return cellFormat;
        }
      }
    });
  })();
  </script>
</dom-module>

extract from tal-ui-order-payment.html

function formatCurrency (value, currency, precision) {
  if (value === undefined) {
    return '';
  };
  if (isNaN(value)) {
    return "Value is not a Number";
  } else {
    currency = currency || "$";
    precision = precision || 2;
    value = Number(value);
    value = value.toFixed(precision);
  }
  var parts = value.split('.'),
    fnum = parts[0],
    decimal = parts[1] ? '.' + parts[1] : '';
  return currency + fnum.replace(/(\d)(?=(?:\d{3})+$)/g, '$1,') + decimal;
};

go4cas avatar Dec 29 '15 09:12 go4cas

Hmm, that indeed looks the way I would expect it to look. And I understand correctly that

<paper-datatable-column header="amount" property="paymentAmount" format-value="{{_cellCurrencyFormat}}" align="right"></paper-datatable-column>

didn't work?

David-Mulder avatar Dec 29 '15 09:12 David-Mulder

No, this implementation is working now.

go4cas avatar Dec 29 '15 09:12 go4cas

That's so odd, once I have access to my development environment I will check and try figuring out what could be happening.

David-Mulder avatar Dec 29 '15 09:12 David-Mulder

Just ran into this myself. If you define the helper function like this it works in polymer 1:

<paper-datatable-column header="Size" property="Size" format-value="{{formatSize}}" >

Polymer({
                properties: {
                    formatSize:{
                        type: Function,
                        value :function(){
                            return function(v){
                                var size = parseInt(v,10);
                                if(isNaN(size)){
                                    return '';
                                }
                                return (size/1024/1024).toFixed(2) + " MB";
                            };
                        }
                    }
                },


jonaz avatar Jan 22 '16 13:01 jonaz

I just had to use the same fugly hack for filtering.

... i guess it works but it is horrible!

JensGroenborg avatar Jan 22 '16 16:01 JensGroenborg

@JensGroenborg I'm struggling trying to apply a filter this way, could you please post your solution??

ngarcial avatar Feb 12 '16 21:02 ngarcial

Sure, here is my little user admin page, for very unsecure intranet usage, hope you can make anything out of it, and if anybody figures out how to mark which rows has been updated in a paper-datatable i'm all ears.

The important parts are filter="{{filteredItems}}" and the filteredItems funciton which returns a function:

<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../bower_components/iron-flex-layout/iron-flex-layout.html">
<link rel="import" href="../bower_components/iron-ajax/iron-ajax.html">
<link rel="import" href="../bower_components/paper-button/paper-button.html">
<link rel="import" href="../bower_components/paper-input/paper-input.html">
<link rel="import" href="../bower_components/paper-toggle-button/paper-toggle-button.html">
<link rel="import" href="../bower_components/paper-datatable/paper-datatable.html">

<dom-module id="access-overrides">
    <template>
        <iron-ajax id="overrides" auto url="[[serviceUrl]]" handle-as="json" last-response="{{users}}"></iron-ajax>
        <iron-ajax id="overridesPost" url="[[serviceUrl]]" handle-as="json" method="post" body="{{users}}"></iron-ajax>

        <div class="input-row">
            <paper-input id="uid" label="User id" required="true" value="{{guid}}"
                         pattern="[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" error-message="Invalid pattern"
                         auto-validate></paper-input>
            <paper-input id="role" label="Role" value="{{role}}"></paper-input>
            <paper-toggle-button id="allow" checked="{{allow}}">Allow</paper-toggle-button>
            <paper-input id="expiresAt" label="Expires At" value="{{expiresAt}}"></paper-input>
            <div id="addRemovePanel">
                <paper-button id="addOverride" raised on-click="addOverride">
                    <iron-icon icon="add"></iron-icon>
                    Add
                </paper-button>
                <paper-button id="removeOverride" raised on-click="removeOverrides">
                    <iron-icon icon="remove"></iron-icon>
                    Remove
                </paper-button>
            </div>
        </div>
        <div>
            <paper-datatable id="overrideTable" data="{{users}}" filter="{{filteredItems}}" selectable multi-selection>
                <paper-datatable-column header="User Id" property="uid" type="String" style="" sortable></paper-datatable-column>
                <paper-datatable-column header="Role" property="role" type="String" style="" editable sortable></paper-datatable-column>
                <paper-datatable-column header="Allow" property="allow" type="Boolean" style="" editable sortable></paper-datatable-column>
                <paper-datatable-column header="Expires At" property="expiresAt" type="String" style="" default="" editable sortable></paper-datatable-column>
            </paper-datatable>
        </div>

        <paper-button id="save" raised on-click="save">
            <iron-icon icon="save"></iron-icon>
            Gem
        </paper-button>
    </template>
    <script>
        Polymer({
            is: 'access-overrides',

            properties: {
                serviceUrl: String,
                users: Array,
                filteredItems: { // Ugliest hack ever, but apparently necessary!
                    value: function() {
                        return function(user, event, items) {
                            return !user.remove;
                        }
                    }
                }
            },

            save: function(event) {
                var post = this.$.overridesPost;
                post.contentType = "application/json";
                post.generateRequest();
            },

            addOverride: function() {
                var user = {'uid': this.$.uid.value, 'role': this.$.role.value, 'allow': this.$.allow.checked, 'expiresAt': this.$.expiresAt.value};
                this.unshift('users', user);
            },

            removeOverrides: function(obj) {
                this.$.overrideTable.selectedItems.forEach(function(u) {u.remove = true});
                this.$.overrideTable.reload();
            }
        });
    </script>
</dom-module>

JensGroenborg avatar Feb 15 '16 22:02 JensGroenborg

For what it's worth, I came across this issue when having similar issues with a custom sort algorithm. Jonaz's solution did the trick for me.

ReinierKop avatar Apr 13 '16 14:04 ReinierKop

I intend to redo the behavior of the sort, filter, format-value function declaration to the following:

In <template is="dom-repeat"> the way they deal with 'outside' functions is by just putting the name of the function between as attribute like this <template filter="filterFunction">. I suggest doing the same for all mentioned function types.

And I side of the Polymer Element you have to do some calculations as the eg filter function changes:

properties: {
  filter: {
    type: Function,
    observer: '_filterFunctionChanged'
  }
},
function _filterFunctionChanged(filter) {
  var dataHost = (this.dataHost && this.dataHost._rootDataHost) || this.dataHost;
  this._filterFn = filter && (typeof filter == 'function' ? filter :
        function() { return dataHost[filter].apply(dataHost, arguments); });
  // Reload data
}

IchordeDionysos avatar Jul 24 '16 18:07 IchordeDionysos