javascript - Polymer v1.3.1 databind 无法使用或不使用带有重复模板和 json 数组的 iron-ajax

标签 javascript json data-binding polymer-1.0

目标

通过 Polymer 显示 json 对象数组中的 html 表。

问题

无法将 json 数据与消息绑定(bind): Polymer::Attributes:无法将数组解码为 JSON

这个测试反射(reflect)了什么?

使用iron-ajax或直接使用ajax记录上面相同的消息,此测试的结果是直接使用ajax绕过iron-ajax可能出现的问题。问题是将 Web 服务返回的 json 绑定(bind)到 Polymer 转发器。

聚合物 Dom 元素

<polymer-element name="fixtures-list">

<!--    <iron-ajax auto id="matchesService" verbose="true"
        params='{{ajaxParams}}'
        url="http://localhost:20440/MatchesService.svc/matches/GetAllForTeamInSeason"
        handle-as="json"
        method="GET"
        on-request="handleRequestSent"
        on-response="handleResponseReceived"
        on-error="handleError"
        last-response="{{matches}}"
        debounce-duration="300"></iron-ajax>-->

    <table class="table table-responsive">
        <thead>
            <tr>
                <th>Date</th>
                <th><abbr title="Kick Off">KO</abbr>/Result</th>
                <th></th>
                <th>Opponent</th>
                <th>Venue</th>
                <th><abbr title="Competition">Comp</abbr></th>
                <th><abbr title="Televised">TV</abbr>/<abbr title="Attendance">ATT</abbr></th>
            </tr>
        </thead>
        <tbody>
            <template is="dom-repeat" items="{{matches}}">
                <tr>
                    <td>{{KickOff}}</td>
                    <td>
                        <template if="{{IsResult}}">
                            {{Result}}
                        </template>
                        <template if="{{!IsResult}}">
                            {{KickOff}}
                        </template>
                    </td>
                    <td>{{Result}}</td>
                    <td>{{OpponentNameShort}}</td>
                    <td>{{Venue}}</td>
                    <td>{{EventAbbreviations}}</td>
                    <td>
                        <template if="{{IsResult}}">
                            {{Attendance}}
                        </template>
                        <template if="{{!IsResult}}">
                            {{BroadcasterAbbreviations}}
                        </template>
                    </td>
                </tr>
            </template>
        </tbody>
    </table>

    <script>
        Polymer({
            is: 'fixtures-list',
            properties: {
                siteid: {
                    type: Number,
                    value: -1,
                    notify: true,
                    reflectToAttribute: true,
                    observer: 'logChange'
                },
                teamid: {
                    type: Number,
                    value: -1,
                    notify: true,
                    reflectToAttribute: true,
                    observer: 'logChange'
                },
                seasonid: {
                    type: Number,
                    value: -1,
                    notify: true,
                    reflectToAttribute: true,
                    observer: 'logChange'
                },
                ajaxParams: {
                    type: Object,
                    computed: 'processParams(siteid, teamid, seasonid)'
                }
            },
            matches: [],
            ready: function () {
                console.log('polymer element ready');
                $.ajax({
                    url: 'http://localhost:20440/MatchesService.svc/matches/GetAllForTeamInSeason',
                    data: {
                        siteId: this.siteid,
                        teamId: this.teamid,
                        seasonId: this.seasonid
                    },
                    error: function () {
                        console.log('ajax error');
                    },
                    dataType: 'json',
                    success: function (data) {
                        //console.log(JSON.parse(data));
                        this.matches = data;
                    },
                    type: 'GET'
                });
            },
            processParams: function(siteid, teamid, seasonid) {
                console.log('processParams: ' + siteid + ', ' + teamid + ', ' + seasonid);
                return {
                    siteId: siteid,
                    teamId: teamid,
                    seasonId: seasonid
                }
            },
            logChange: function(newValue, oldValue) {
                console.log('Param changed to: ', newValue);
            },
            handleRequestSent: function (request) {
                console.log('ReqSent');
                //console.log(request);
            },
            handleResponseReceived: function (response) {
                console.log('ResReceived');
                //console.log(response);
                //console.log("Received response: " + JSON.stringify(response.detail.response));
                //this.result = response.detail.response;
            },
            handleError: function (event) {
                console.log('error');
                //var request = event.detail.request;
                //var error = event.detail.error;
                //console.log(request);
                //console.log(error);
            }
        });
    </script>
</polymer-element>

聚合物-micro.html

以下函数返回Polymer::Attributes:无法将数组解码为JSON消息,我为每个语句添加了控制台日志,并注释掉了在try/catch 获取数组类型 JSON.parse 了解更多详细信息。

起初我以为这个过程是双重 JSON 解码,所以我将 ajax dataType 设置为“text”,并尝试使用 JSON.parse 手动解析数据,数据解析成功。

deserialize: function (value, type) {
switch (type) {
    case Number:
        console.log('Number: ' + value);
value = Number(value);
break;
    case Boolean:
        console.log('Boolean: ' + value);
value = value != null;
break;
    case Object:
        console.log('Object: ' + value);
try {
value = JSON.parse(value);
} catch (x) {
}
break;
    case Array:
        console.log('Array: ' + value);
try {
value = JSON.parse(value);
} catch (x) {
//value = null;
console.warn('Polymer::Attributes: couldn`t decode Array as JSON');
}
break;
    case Date:
        console.log('Date: ' + value);
value = new Date(value);
break;
    case String:
        console.log('String: ' + value);
default:
break;
}
return value;
}

Firebug Console Logs

JSON returned from web service

结论

感觉好像 Polymer 正在将 {{matches}} 作为字符串而不是实际数据,如果有人能够阐明这项相对较新的技术,我将非常感激 - 谢谢。

最佳答案

嗨,我找到了答案,第一行以聚合物元素标签开头,该标签用于旧版本的聚合物,新版本使用 dom-module。

还添加了观察者,以确保在通过 ajax 获取数据之前设置所有变量。

这是一个工作版本:

<dom-module id="fixtures-list">
<template>
    <row>
        <div class="col-lg-6 col-md-6 col-sm-6 col-xs-12">
            <select id="fixtures-list-season-selector" class="selectpicker"></select>
        </div>
        <div class="col-lg-6 col-md-6 col-sm-6 col-xs-12 text-right">
            <span class="label label-info">home match</span>
        </div>
    </row>

    <table class="table table-responsive">
        <thead>
        <tr>
            <th>Date</th>
            <th class="text-center">
                <span class="hidden-xs"><abbr title="Kick Off">KO</abbr>/Result</span>
                <span class="visible-xs"><abbr title="Kick Off">KO</abbr>/<abbr title="Result">Res</abbr></span>
            </th>
            <th></th>
            <th>Opponent</th>
            <th class="hidden-xs">Venue</th>
            <th class="hidden-xs" class="text-center"><abbr title="Competition">Comp</abbr></th>
            <th class="hidden-xs" class="text-center"><abbr title="Televised">TV</abbr>/<abbr title="Attendance">ATT</abbr></th>
            <th></th>
        </tr>
        </thead>
        <tbody>
        <template is="dom-repeat" items="{{fixturesData}}" as="fixture">
            <tr class$="{{highlightRow(fixture.IsHome)}}">
                <td>
                    <span class="hidden-xs">{{displayDate(fixture.KickOff)}}</span>
                    <span class="visible-xs">{{displayShortDate(fixture.KickOff)}}</span>
                </td>
                <td class="text-center">
                    <template is="dom-if" if="{{fixture.IsResult}}">
                        {{fixture.Score}}
                    </template>
                    <template is="dom-if" if="{{!fixture.IsResult}}">
                        {{displayTime(fixture.KickOff)}}
                    </template>
                </td>
                <td>
                    <template is="dom-if" if="{{fixture.IsResult}}">
                        {{fixture.Result}}
                    </template>
                </td>
                <td>{{fixture.OpponentNameShort}}</td>
                <td class="hidden-xs">{{fixture.Venue}}</td>
                <td class="text-center hidden-xs">{{fixture.EventAbbreviations}}</td>
                <td class="text-center hidden-xs">
                    <template is="dom-if" if="{{fixture.IsResult}}">
                        {{fixture.Attendance}}
                    </template>
                    <template is="dom-if" if="{{!fixture.IsResult}}">
                        {{fixture.BroadcasterAbbreviations}}
                    </template>
                </td>
                <td class="text-center">
                    <template is="dom-if" if="{{fixture.IsResult}}">
                        <a href="/MatchReport/{{fixture.Id}}/" class="btn btn-default">view</a>
                    </template>
                    <template is="dom-if" if="{{!fixture.IsResult}}">
                        <a href="/MatchPreview/{{fixture.Id}}/" class="btn btn-default">view</a>
                    </template>
                </td>
            </tr>
        </template>
        </tbody>
    </table>
</template>

<script>
    Polymer({
        is: 'fixtures-list',
        properties: {
            siteid: {
                type: Number,
                value: -1,
                notify: true,
                reflectToAttribute: true,
                observer: 'logChange'
            },
            teamid: {
                type: Number,
                value: -1,
                notify: true,
                reflectToAttribute: true,
                observer: 'logChange'
            },
            dateformatstring: {
                type: String,
                value: '',
                notify: true,
                reflectToAttribute: true,
                observer: 'logChange'
            },
            timeformatstring: {
                type: String,
                value: '',
                notify: true,
                reflectToAttribute: true,
                observer: 'logChange'
            },
            seasonstarted: {
                type: String,
                value: '',
                notify: true,
                reflectToAttribute: true,
                observer: 'logChange'
            },
            ajaxParams: {
                type: Object,
                computed: 'processParams(siteid, teamid, seasonid)'
            },
            fixturesData: {
                type: Array,
                value: function () { return []; }
            }
        },
        isAttributeValuesReady: false,
        observers: [
            // Note that this function  will not fire until *all* parameters given have been set to something other than `undefined`
            'attributesReady(siteid, teamid, dateformatstring, timeformatstring)'
        ],
        attributesReady: function (siteid, teamid, dateformatstring, timeformatstring) {
            this.isAttributeValuesReady = true;
            console.log('attributesReady: ' + siteid + ', ' + teamid + ', ' + dateformatstring + ', ' + timeformatstring);

            //this.$.matchesService.set('params.siteId', siteid);
            //this.$.matchesService.set('params.teamId', teamid);
            //this.$.matchesService.set('params.dateFormatString', dateFormatString);
            //this.$.matchesService.set('params.timeFormatString', timeFormatString);
            //this.$.matchesService.generateRequest();
        },
        loadMatchesList: function () {
            var self = this;

            $.ajax({
                url: 'http://localhost:20440/MatchesService.svc/matches/GetAllForTeamInSeason',
                data: {
                    siteId: this.siteid,
                    teamId: this.teamid,
                    seasonId: $('#fixtures-list-season-selector').val()
                },
                error: function () {
                    console.log('ajax error');
                },
                dataType: 'json',
                success: function (data) {
                    console.log('fixtures-list: matches data received');
                    self.fixturesData = data;
                },
                type: 'GET'
            });
        },
        ready: function () {
            //console.log('polymer element ready');
            var self = this;

            if (self.isAttributeValuesReady) {
                $.ajax({
                    url: 'http://localhost:20440/SeasonsService.svc/seasons/GetAll',
                    data: {
                        siteId: this.siteid,
                        teamId: this.teamid
                    },
                    error: function () {
                        //console.log('ajax error');
                    },
                    dataType: 'json',
                    success: function (data) {
                        //console.log('fixtures-list: season data received');
                        //console.log(data);

                        var defaultId = 0;
                        for (var i = 0; i < data.length; i++) {
                            if (i == 0) {
                                defaultId = data[i].Id;
                            }
                            if (i < 100) {
                                $('#fixtures-list-season-selector').append('<option value="' + data[i].Id + '">' + data[i].Name + '</option>');
                            }
                            if (self.seasonstarted.length > 0 && self.seasonstarted == data[i].Name) {
                                break;
                            }
                        }

                        setTimeout(function () {
                            console.log('init select');
                            $('#fixtures-list-season-selector').selectpicker('val', defaultId).on('changed.bs.select', function (e) {
                                self.loadMatchesList();
                            });
                        }, 500);

                        self.loadMatchesList();
                    },
                    type: 'GET'
                });
            }
        },
        displayDate: function (jsonDate) {
            var jsDate = new Date(jsonDate.match(/\d+/)[0] * 1);
            var tmpDateFormatString = this.dateformatstring;
            if (tmpDateFormatString.length <= 0 || (tmpDateFormatString.length > 0 && tmpDateFormatString == 'NaN')) {
                tmpDateFormatString = "ddd, d mmm";
            }
            return dateFormat(jsDate, tmpDateFormatString);
        },
        displayShortDate: function (jsonDate) {
            var jsDate = new Date(jsonDate.match(/\d+/)[0] * 1);
            var tmpDateFormatString = this.dateformatstring;
            return dateFormat(jsDate, "d mmm");
        },
        displayTime: function (jsonDate) {
            var jsDate = new Date(jsonDate.match(/\d+/)[0] * 1);
            var tmpTimeFormatString = this.timeformatstring;
            if (tmpTimeFormatString.length <= 0 || (tmpTimeFormatString.length > 0 && tmpTimeFormatString == 'NaN')) {
                tmpTimeFormatString = "HH:MM";
            }
            return dateFormat(jsDate, tmpTimeFormatString);
        },
        highlightRow: function(isHome) {
            var css = '';
            if (isHome) {
                css = 'info';
            }
            return css;
        },
        processParams: function (siteid, teamid) {
            //return 'siteId='+ siteid + '&teamId=' + teamid + '&seasonId=' + $('#fixtures-list-season-selector').val();

            return JSON.stringify({
                siteId: siteid,
                teamId: teamid,
                seasonId: $('#fixtures-list-season-selector').val()
            });
        },
        logChange: function (newValue, oldValue) {
            console.log('Param changed to: ', newValue);
        },
        handleRequestSent: function (request) {
            console.log('ReqSent');
            //console.log(request);
        },
        handleResponseReceived: function (response) {
            console.log('ResReceived');
            //console.log(response);
            //console.log("Received response: " + JSON.stringify(response.detail.response));
            //this.result = response.detail.response;
        },
        handleError: function (event) {
            console.log('error');
            //var request = event.detail.request;
            //var error = event.detail.error;
            //console.log(request);
            //console.log(error);
        }
    });
</script>

关于javascript - Polymer v1.3.1 databind 无法使用或不使用带有重复模板和 json 数组的 iron-ajax,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36174761/

相关文章:

javascript - 匹配除两个特定字符串之外的任何内容

json - 如何将 "push"一个 json 对象转换为 Go 中的数组?

javascript - 获取Json信息

WPF 数据绑定(bind)

javascript - 通过保留数据类型将数据从 JSON 导出到 excel

javascript - 使用 Objective-C 在 iPhone 中创建 MS Word 文档

javascript - 限制用户在php中多次添加一件商品到购物车

c# - 如何将 SqlHierarchyId 序列化为字符串

asp.net - 如何在代码隐藏中使用 Eval 来设置 Page.Title

qt - 当 QML 对象不可见时防止 QML 属性绑定(bind)?