Polymer dart: Data bind integer value to String attribute

后端 未结 2 1646
甜味超标
甜味超标 2020-12-22 00:53

I am trying to bind an integer to a String attribute. To say exactly, I am trying to bind a published integer variable to the value attribute of the text input element.

相关标签:
2条回答
  • 2020-12-22 01:09

    For Polymer 1.0.0 this worked fine for me

    Create a reusable behavior or just add the convertToNumeric() to your Polymer element:

    @HtmlImport('app_element.html')
    library app_element;
    import 'dart:html' as dom;
    import 'package:web_components/web_components.dart' show HtmlImport;
    import 'package:polymer/polymer.dart';
    
    @behavior
    abstract class InputConverterBehavior implements PolymerBase {
      @reflectable
      void convertToInt(dom.Event e, _) {
        final input = (e.target as dom.NumberInputElement);
        double value = input.valueAsNumber;
        int intValue =
            value == value.isInfinite || value.isNaN ? null : value.toInt();
        notifyPath(input.attributes['notify-path'], intValue);
      }
    }
    

    Apply the behavior to your element:

    @PolymerRegister('app-element')
    class AppElement extends PolymerElement with InputConverterBehavior {
      AppElement.created() : super.created();
    
      @property int intValue;
    }
    

    In HTML of your element configure the input element:

    • bind value to your property: value="[[intValue]]" so the input element gets updated when the property changes
    • set up event notification to call the converter when the value changes on-input="convertToNumeric" notify-path="intValue" where intValue is the name of the property to update with the numeric value.
    <!DOCTYPE html>
    <dom-module id='app-element'>
      <template>
        <style>
          input:invalid {
            border: 3px solid red;
          }
        </style>
        <input type="number" value="[[intValue]]"
               on-input="convertToInt" notify-path="intValue">
    
        <!-- a 2nd element just to demonstrate that 2-way-binding -->
        <input type="number" value="[[intValue]]"
               on-input="convertToInt" notify-path="intValue">
      </template>
    </dom-module>
    

    An alternative approach

    Create a property as getter/setter:

      int _intValue;
      @property int get intValue => _intValue;
      @reflectable set intValue(value) => convertToInt(value, 'intValue');
    

    Create a behavior or add the function directly to your element

    @behavior
    abstract class InputConverterBehavior implements PolymerBase {
      void convertToInt(value, String propertyPath) {
        int result;
        if (value == null) {
          result = null;
        } else if (value is String) {
          double doubleValue = double.parse(value, (_) => double.NAN);
          result =
              doubleValue == doubleValue.isNaN ? null : doubleValue.toInt();
        } else if (value is int) {
          result = value;
        } else if (value is double) {
          result =
              value == value.isInfinite || value.isNaN ? null : value.toInt();
        }
        set(propertyPath, result);
      }
    }
    

    This way you can use the same markup as for text input fields

    <input type="number" value="{{intValue::input}}">
    

    or if you want to delay the update of the property until the input field is left

    <input type="number" value="{{intValue::change}}">
    
    0 讨论(0)
  • 2020-12-22 01:12

    This is for Polymer <= 0.16. For Polymer >= 1.0 see my other answer.

    HTML attributes store only string values. What you could do is to use a getter/setter for binding and parse when the value is set.

    @observable
    int data;
    
    @ComputedProperty('data') // haven't tried this but should work - see comments on http://japhr.blogspot.co.at/2014/08/whats-difference-between-attribute-and.html
    @observable
    get dataValue => data;
    set dataValue(val) {
      if(val == null) {
        data = 0;
      } else if(val is num) {
        data = val.toInt();
      } else if(val is String) {
        data = num.parse(val, (v) => 0).toInt();
      } else {
        data = 0;
      }
    }
    

    or use a transformer or custom Polymer expressions
    like explained in polymer dart input binding int properties

    Alternative approache uses Dart Polymer 1.0 (also possible with Dart Polymer 0.16)

    app_element.dart

    @HtmlImport('app_element.html')
    library _template.web.app_element;
    
    import 'dart:html' as dom;
    import 'package:web_components/web_components.dart' show HtmlImport;
    import 'package:polymer/polymer.dart';
    
    @PolymerRegister('app-element')
    class AppElement extends PolymerElement {
      AppElement.created() : super.created();
    
      @property int intValue;
      @property String stringValue;
    
      @reflectable
      valueInputHandler(dom.Event event, [_]) {
        var input = (event.target as dom.NumberInputElement);
        var value = input.valueAsNumber;
        if (!value.isNaN && !value.isInfinite) {
          set('intValue', value.toInt());
          input.setCustomValidity('');
        } else {
          // just to get the `:invalid` pseudo-class for styling
          input.setCustomValidity('Not a number.');
        }
      }
    }
    

    app_element.html

    <!DOCTYPE html>
    <dom-module id='app-element'>
      <template>
        <style>
          input:invalid {
            border: 3px solid red;
          }
        </style>
        <input type="number"
               value="{{stringValue::input}}"
               on-input="valueInputHandler" >
        <div>stringValue: <span>{{stringValue}}</span></div>
        <div>intValue:<span>{{intValue}}</span></div>
      </template>
    </dom-module>
    
    0 讨论(0)
提交回复
热议问题