Polymer 1.0 observers watching a object path is no

2019-09-11 05:57发布

jsFiddle: https://jsfiddle.net/ghstahl/09tL1ku7/

<script src="https://cdn.rawgit.com/download/polymer-cdn/1.1.3/lib/webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="https://cdn.rawgit.com/download/polymer-cdn/1.1.3/lib/polymer/polymer.html">
<link rel="import" href="https://cdn.rawgit.com/download/polymer-cdn/1.1.3/lib/paper-styles/paper-styles.html">
<link rel="import" href="https://cdn.rawgit.com/download/polymer-cdn/1.1.3/lib/paper-styles/color.html">
<link rel="import" href="https://cdn.rawgit.com/download/polymer-cdn/1.1.3/lib/paper-styles/default-theme.html">
<link rel="import" href="https://cdn.rawgit.com/download/polymer-cdn/1.1.3/lib/paper-ripple/paper-ripple.html">
<link rel="import" href="https://cdn.rawgit.com/download/polymer-cdn/1.1.3/lib/paper-behaviors/paper-inky-focus-behavior.html">
<link rel="import" href="https://cdn.rawgit.com/download/polymer-cdn/1.1.3/lib/iron-checked-element-behavior/iron-checked-element-behavior.html">
<link rel="import" href="https://cdn.rawgit.com/download/polymer-cdn/1.1.3/lib/paper-toggle-button/paper-toggle-button.html">
<link rel="import" href="https://cdn.rawgit.com/download/polymer-cdn/1.1.3/lib/paper-input/paper-input.html">
<link rel="import" href="https://cdn.rawgit.com/download/polymer-cdn/1.1.3/lib/paper-button/paper-button.html">
<link rel="import" href="https://cdn.rawgit.com/download/polymer-cdn/1.1.3/lib/iron-flex-layout/iron-flex-layout.html">
<link rel="import" href="https://cdn.rawgit.com/download/polymer-cdn/1.1.3/lib/iron-flex-layout/classes/iron-flex-layout.html">
<link rel="import" href="https://cdn.rawgit.com/download/polymer-cdn/1.1.3/lib/iron-flex-layout/classes/iron-shadow-flex-layout.html">
<link rel="import" href="https://cdn.rawgit.com/download/polymer-cdn/1.1.3/lib/paper-dropdown-menu/paper-dropdown-menu.html">
<link rel="import" href="https://cdn.rawgit.com/download/polymer-cdn/1.1.3/lib/paper-menu-button/paper-menu-button.html">
<link rel="import" href="https://cdn.rawgit.com/download/polymer-cdn/1.1.3/lib/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
<link rel="import" href="https://cdn.rawgit.com/download/polymer-cdn/1.1.3/lib/iron-behaviors/iron-control-state.html">
<link rel="import" href="https://cdn.rawgit.com/download/polymer-cdn/1.1.3/lib/iron-behaviors/iron-button-state.html">
<link rel="import" href="https://cdn.rawgit.com/download/polymer-cdn/1.1.3/lib/iron-icons/iron-icons.html">
<link rel="import" href="https://cdn.rawgit.com/download/polymer-cdn/1.1.3/lib/iron-icon/iron-icon.html">
<link rel="import" href="https://cdn.rawgit.com/download/polymer-cdn/1.1.3/lib/iron-selector/iron-selector.html">
<link rel="import" href="https://cdn.rawgit.com/download/polymer-cdn/1.1.3/lib/paper-item/paper-item.html">
<link rel="import" href="https://cdn.rawgit.com/download/polymer-cdn/1.1.3/lib/paper-behaviors/paper-button-behavior.html">
<dom-module id="pingo-toggle">
<style>
    .line {
        margin-bottom: 40px;
    }
    .line span {
        margin-left: 24px;
    }
</style>
<template>
    <div class="line">
        <paper-toggle-button checked={{singleToggle.data}}></paper-toggle-button> <span>{{singleToggle.label}}</span>
<span>{{computeBooleanToString(singleToggle.data)}}</span>

    </div>
    <template is="dom-repeat" items="{{_workingArray}}">
        <div class="line">
            <paper-toggle-button checked={{item.value.data.checked}}></paper-toggle-button> 
<span>{{item.value.label}}</span>
<span>{{item.value.id}}</span>
<span>{{computeBooleanToString(item.value.data.checked)}}</span>

        </div>
    </template>
</template>
<script>
    (function() {
        Polymer({
            is: 'pingo-toggle',
            properties: {

                singleToggle: {
                    type: Object,
                    notify: true
                },

                toggleItems: {
                    type: Object,
                    notify: true,
                    observer: '_toggleItemsChanged'
                },
            },
            _toggleItemsChanged: function(newValue, oldValue) {
                if (this.toggleItems !== undefined) {
                    this._workingArray = this._toArray(this.toggleItems);
                }
            },
            _toArray: function(obj) {
                var index = 0;
                var thisElement = this;
                this._arrayData = Object.keys(obj).map(function(key) {
                    var id = "item_" + index;
                    ++index;
                    var val = {};
                    val.data = obj[key];
                    val.label = "hi:" + key;
                    val.data = obj[key];
                    val.id = id;
                    val.original = obj.key;
                    return {
                        name: key,
                        value: val
                    };
                });
                return this._arrayData;
            },
            computeBooleanToString: function(a) {
                return a === true ? 'true' : 'false';
            }
        });
    })();
</script>
</dom-module>
<dom-module id="pingo-toggle-container">
<style>
</style>
<template>
    <pingo-toggle single-toggle={{_singleToggle}} toggle-items={{_toggleItems}}></pingo-toggle>
    <paper-item>{{_singleToggleHello}}</paper-item>
    <paper-item>{{_toggleItemsHello}}</paper-item>
</template>
<script>
    (function() {
        Polymer({
            is: 'pingo-toggle-container',
            properties: {
                _singleToggleHello: {
                    type: String,
                    notify: true,
                    value: "Well Hello There"
                },
                _toggleItemsHello: {
                    type: String,
                    notify: true,
                    value: "Hi there from many"
                },

                _singleToggle: {
                    type: Object,
                    notify: true,
                    value: {
                        label: "Single Toggle",
                        data: true
                    }
                },
                _toggleItems: {
                    type: Object,
                    notify: true,
                    value: {
                        a: {
                            label: "a Toggle2",
                            checked: true
                        },
                        b: {
                            label: "a Toggle2",
                            checked: false
                        }
                    }
                }
            },

            // Observers
            /////////////////////////////////////////////////////////
            observers: ['_toggleItemsChanged(_toggleItems.*)', '_singleToggleChanged(_singleToggle.*)'],
            // Smart check. only fire if we change state.
            _singleToggleChanged: function(changeRecord) {
                var thisElement = this;

                this._singleToggleHello = this.computeBooleanToString(this._singleToggle.data) + Math.random() + changeRecord.path;
                console.log("_singleToggle in pingo-toggle-container changed:" + changeRecord.path);

            },
            _toggleItemsChanged: function(changeRecord) {
                var thisElement = this;

                this._toggleItemsHello = "_workingToggleItemsChanged fired" + Math.random() + changeRecord.path;

                console.log("pingo-toggle-container notWorking:" + changeRecord.path);

            },
            computeBooleanToString: function(a) {
                return a === true ? 'true' : 'false';
            },

            ready: function(e) {

            }
        });
    })();
</script>
</dom-module>
<pingo-toggle-container></pingo-toggle-container>

Scenario: Parent element owns a data object. Parent element passes portion of the data object to children elements which bind to values in the object. When children change the value, because they have an object reference, the data is changed directly in the parent owned master data object.

Problem: '_toggleItemsChanged(_toggleItems.*)' fires once, the very first time, but never fires again even though data in _toggleItems has changed.

Proof: In the pingo-toggle-container element;

  • Put a breakpoint at _singleToggleChanged and _toggleItemsChanged.
    • Both fire at startup.
  • Toggle both 'hi:a' and 'hi:b' back and forth.
    • nothing fires.
  • So I set 'hi:a' and 'hi:b' both to True.
  • 'Single Toggle' does fire, so I toggle that and my breakpoint hits.
    • evaluate this._toggleItems;
    • Hmm, you both are set to true. You can toggle 'hi:a' and 'hi:b' to false and redo the test. Now they are both set to false.

Why you not fire observers: ['_toggleItemsChanged(_toggleItems.)', '_singleToggleChanged(_singleToggle.)'], for data change?

Expected: I want the _toggleItemsChanged function to get called with the changeRecord.path of _toggleItems.a.checked or _toggleItems.a.checked repectively.

1条回答
乱世女痞
2楼-- · 2019-09-11 06:49

I don't know if I could understand your example right, but I believe you are trying to observe a deeper sub-property change. It won't work.

Observers cannot watch that deeper. They observe the first level properties changes only when you use . If you need to go deeper, you need to observe other paths, like _toggleItems.a. and so on.

查看更多
登录 后发表回答