无法在PolymerJS 3.0中的路由函数中访问更改的数组“值”? (使用iron-ajax和app-route元素)

时间:2018-08-21 13:23:56

标签: routing polymer polymer-3.x iron-ajax app-route

我是Polymer的新手,目前正在学习 Polymer 3.0 。我正在尝试制作一个如下运行的应用程序:

  1. 从公开网址获取播放列表数据(使用iron-ajax元素)
  2. 在handleResponse()函数中处理数据,并将值分配给' playlistNames '变量。
  3. 使用路由显示播放列表和歌曲

问题:(我被困在那里)

在刷新页面http://127.0.0.1:8081/playlist1上,路由器正在加载404页面而不是播放列表页面,因为playlistName为空。但是,如果我单击任何播放列表(刷新页面后),则表明路由器正在工作。

我无法使用其他函数'_routePageChanged'访问更新后的playlistNames数组。代码段如下。

handleResponse() func中,我得到了正确的输出(带有播放列表列表的数组)。但是在_routePageChanged() func'中,输出为[],这是一个空数组。

app-console-output-screenshot


问题:

我的理解:app-route元素先于iron-ajax元素处理。

如何在playlistNames中访问 _routePageChanged 的新值?


文件:my-element.js

class MyApp extends PolymerElement {
    static get template() {
      return html `  
        <!-- make api calls to fetch the playlists -->
        <iron-ajax
                auto
                url=""
                handle-as = "json"
                on-response="handleResponse"
                last-response="{{ajaxResponse}}">
        </iron-ajax>

        <app-location route="{{route}}" url-space-regex="^[[rootPath]]">
        </app-location>

        <app-route route="{{route}}" pattern="[[rootPath]]:page" data="{{routeData}}" tail="{{subroute}}">
        </app-route>
  
        ...
            <iron-pages selected="[[page]]" attr-for-selected="name" role="main">
              <my-view404 name="view404"></my-view404>
              <data-send name="playlist" prop1="[[selectedPlaylist]]"></data-send>
            </iron-pages>
      `;
    }

    static get properties() {
      return {
        page: {
          type: String,
          reflectToAttribute: true,
          observer: '_pageChanged'
        },
        playlists: {
          type: Array,
          reflectToAttribute: true,
          value: 'waiting...',
          reflectToAttribute: true
        },
        playlistNames: {
          type: Array,
          value: function() {
            return [];
          }
        },
        selectedPlaylist: {
          type: String,
          value: 'selectedPlaylist is empty'
        },
        routeData: Object,
        subroute: Object
      };
    }

    static get observers() {
      return [
        '_routePageChanged(routeData.page, this.playlistNames.splices)'
      ];
    }
  
    // this function is called on api call
    handleResponse(event, request) { 
      //  get all the playlists from the api call response
      this.playlists = request.response.playlists;

      // get all the playlist names
      for(let playlist of this.playlists) {
        if(this.playlistNames.length < this.playlists.length) {
          // this.playlistNames.push(playlist.name);
          this.push('playlistNames', playlist.name);
        }  
      }
      console.log('handleResponse playlists', this.playlistNames); // ['playlist1', 'playlist2' ...]
  
      // on refreshing url, if any route is present, then find its id to fetch songs list from api
      if(this.routeData.page){
        for(let playlist of this.playlists){
          if(playlist.name === this.routeData.page){
            this.selectedPlaylist = playlist.id;
          }
        }
      }
    }

    // this func is called on route change or page refresh
    _routePageChanged(page, data) {
      console.log('routeData.page=', page);
      console.log('data=', data); // undefined
      console.log('_routePageChanged playlists.length=', this.playlistNames.length); // 0
      console.log('_routePageChanged playlists=', this.playlistNames); // empty  

      if (!page) {
        this.page = 'view404';
      } else if (["playlist1", "playlist2"].indexOf(page)  !== -1) {
      //playlistNames is empty[],
      // } else if (this.playlistNames.indexOf(page) !== -1) { 
        this.page = 'playlist';
      } else {
        this.page = 'view404';
      }
    }
  
    _pageChanged(page) {
      switch (page) {
        case 'view404':
          import('./my-view404.js');
          break;
        case 'playlist':
          import('./playlist-songs.js');
          break;
      }
    }
  }

1 个答案:

答案 0 :(得分:3)

编辑:改进的答案

正如您在评论中所述,当路由更改到视图时,_routePageChanged()将始终在handleResponse()之前运行(因为handleResponse()是异步的),因此handleResponse()会这样做,仅在_routePageChanged()之后执行。

如果您要遵循我的解决方案,则需要首先使对数组属性playlistNames的更改可见,因此:

代替:

this.playlistNames.push(playlist.name);

使用:

this.push('playlistNames', playlist.name);

As documented here

解决方案-如果您确实需要检查_routePageChanged()

您可以更改_routePageChanged来观察两个属性,而不仅仅是一个属性page。因此,您可以将观察者声明为_routePageChanged(page)而不是_routePagePlaylistNamesChanged(page, playlistNames),并在其中添加逻辑。这样,观察者will fire anytime any of the two properties change value就可以拥有逻辑,例如:

_routePagePlaylistNamesChanged(page, playlistNames) {
  if(page == "myelement" && playlistNames.length > 0){
    //This is correct page and the playlistNames are defined
    console.log('_routePagePlaylistNamesChanged playlists', this.playlistNames);
  }
}