使用缓冲存储+无限网格和动态数据

时间:2013-06-12 18:45:06

标签: extjs extjs4 extjs4.2

目标是为动态数据集使用缓冲存储。 工作流程如下:

  1. 服务器上已存在某些数据。
  2. 客户使用缓冲商店&无限网格来处理数据。
  3. 当应用程序运行时,正在加载商店 并且'load'事件将网格滚动到最后一条消息。
  4. 某些记录已添加到服务器。
  5. 客户端获取推送通知并运行存储重新加载。 topic.store.load({addRecords:true});
  6. 加载事件会运行并尝试再次滚动到最后一条消息,但会失败:
  7. TypeError:offsetsTo为null e = Ext.fly(offsetsTo.el || offsetsTo,'_ internal')。getXY();

    似乎网格视图不刷新,并且不显示添加的记录,只显示其位置上的空白区域。 任何想法如何才能正确刷新网格视图?

    商店初始化:

    Ext.define('orm.data.Store', {
      extend: 'Ext.data.Store',
      requires: ['orm.data.writer.Writer'],
      constructor: function (config) {
        Ext.apply(this, config);
        this.proxy = Ext.merge(this.proxy, {
          type: 'rest',
          batchActions: true,
          reader: {
            type: 'json',
            root: 'rows'
          },
          writer: {
            type: 'orm'
          }
        });
        this.callParent(arguments);
      }
    });
    
    Ext.define('akma.chat.model.ChatMessage', {
      extend:'Ext.data.Model',
      fields:[
        { name:'id', type:'int', defaultValue : undefined },
        { name:'createDate', type:'date', dateFormat:'Y-m-d\\TH:i:s', defaultValue : undefined },
        { name:'creator', type:'User', isManyToOne : true, defaultValue : undefined },
        { name:'message', type:'string', defaultValue : undefined },
        { name:'nameFrom', type:'string', defaultValue : undefined },
        { name:'topic', type:'Topic', isManyToOne : true, defaultValue : undefined }
      ],
      idProperty: 'id'
    });
    
    
    
    Ext.define('akma.chat.store.ChatMessages', {
       extend: 'orm.data.Store',
       requires: ['orm.data.Store'],
       alias: 'store.akma.chat.store.ChatMessages',
       storeId: 'ChatMessages',
       model: 'akma.chat.model.ChatMessage',
       proxy: {
       url:  'http://localhost:8080/chat/services/entities/chatmessage'
      }
    });
    
    var store = Ext.create('akma.chat.store.ChatMessages', {
      buffered: true,
      pageSize: 10,
      trailingBufferZone: 5,
      leadingBufferZone: 5,
      purgePageCount: 0,
      scrollToLoadBuffer: 10,
      autoLoad: false,
      sorters: [
        {
          property: 'id',
          direction: 'ASC'
        }
      ]
    });
    

    网格初始化:

    Ext.define('akma.chat.view.TopicGrid', {
      alias: 'widget.akma.chat.view.TopicGrid',
      extend: 'akma.chat.view.grid.DefaultChatMessageGrid',
      requires: ['akma.chat.Chat', 'akma.UIUtils', 'Ext.grid.plugin.BufferedRenderer'],
      features: [],
      hasPagingBar: false,
      height: 500,
      loadedMsg: 0,
      currentPage: 0,
      oldId: undefined,
      forceFit: true,
      itemId: 'topicGrid',
      selModel: {
        pruneRemoved: false
      },
      multiSelect: true,
      viewConfig: {
        trackOver: false
      },
      plugins: [{
        ptype: 'bufferedrenderer',
        pluginId: 'bufferedrenderer',
        variableRowHeight: true,
        trailingBufferZone: 5,
        leadingBufferZone: 5,
        scrollToLoadBuffer: 10
      }],
      tbar: [{
        text: 'unmask',
        handler: function(){
          this.up('#topicGrid').getView().loadMask.hide();
        }
      }],
    
      constructor: function (config) {
    
        this.topicId = config.topicId;
        this.store = akma.chat.Chat.getMessageStoreInstance(this.topicId);
        this.topic = akma.chat.Chat.getTopic(this.topicId);
    
        var topicPanel = this;
    
        this.store.on('load', function (store, records) {
          var loadedMsg = store.getTotalCount();
          var pageSize = store.pageSize;
          store.currentPage = Math.ceil(loadedMsg/pageSize);
            if (records && records.length > 0) {
              var newId = records[0].data.id;
              if (topicPanel.oldId) {
                var element;
                for (var i = topicPanel.oldId; i < newId; i++) {
                  element = Ext.get(i + '');
                  topicPanel.blinkMessage(element);
                }
              }
              topicPanel.oldId = records[records.length-1].data.id;
              var view = topicPanel.getView();
              view.refresh();
              topicPanel.getPlugin('bufferedrenderer').scrollTo(store.getTotalCount()-1);
            }
        });
    
        this.callParent(arguments);
        this.on('afterrender', function (grid) {
          grid.getStore().load();
        });
        var me = this;
        akma.UIUtils.onPasteArray.push(function (e, it) {
          if(e.clipboardData){
            var items = e.clipboardData.items;
            for (var i = 0; i < items.length; ++i) {
              if (items[i].kind == 'file' && items[i].type.indexOf('image/') !== -1) {
                var blob = items[i].getAsFile();
                akma.chat.Chat.upload(blob, function (event) {
                  var response = Ext.JSON.decode(event.target.responseText);
                  var fileId = response.rows[0].id;
                  me.sendMessage('<img src="/chat/services/file?id=' + fileId + '" />');
                })
              }
            }
          }
        });
        akma.UIUtils.addOnPasteListener();
      },
      sendMessage: function(message){
        if(message){
          var topicGrid = this;
          Ext.Ajax.request({
            method: 'POST',
            url: topicGrid.store.proxy.url,
            params:{
              rows: Ext.encode([{"message":message,"topic":{"id":topicGrid.topicId}}])
            }
          });
        }
      },
      blinkMessage: function (messageElement) {
        if (messageElement) {
          var blinking = setInterval(function () {
            messageElement.removeCls('red');
            messageElement.addCls('yellow');
            setTimeout(function () {
              messageElement.addCls('red');
              messageElement.removeCls('yellow');
            }, 250)
    
          }, 500);
          setTimeout(function () {
            clearInterval(blinking);
            messageElement.addCls('red');
            messageElement.removeCls('yellow');
          }, this.showInterval ? this.showInterval : 3000)
        }
      },
      columns: [        {
          dataIndex: 'message',
          text: 'Message',
          renderer: function (value, p, record) {
            var firstSpan = "<span id='" + record.data.id + "'>";
            var creator = record.data.creator;
            return Ext.String.format('<div style="white-space:normal !important;">{3}{1} : {0}{4}</div>',
                value,
                creator ? '<span style="color: #' + creator.chatColor + ';">' +     creator.username + '</span>' : 'N/A',
                record.data.id,
                firstSpan,
                '</span>'
            );
          }
        }
      ]
    });
    

    upd :似乎问题不在View中。 bufferedrenderer插件绑定滚动到记录。 它运行一个回调函数:

           callback: function(range, start, end) {
    
                me.renderRange(start, end, true);
    
                targetRec = store.data.getRange(recordIdx, recordIdx)[0];
    

    .....

     store.data.getRange(recordIdx, recordIdx)[0] 
    

    尝试获取商店中的最后一条记录。 ....

     Ext.Array.push(result, Ext.Array.slice(me.getPage(pageNumber), sliceBegin, sliceEnd));
    

    getPage返回给定页面的所有记录,但缺少最后一条记录,即商店未完全更新。

    任何想法如何解决?

2 个答案:

答案 0 :(得分:4)

问题是store.load()没有用新数据填充商店PageMap。最简单的解决方法是使用store.reload()代替。

答案 1 :(得分:0)

也许你在收听加载事件时要早点。我在我的应用程序中做的大致相同(不滚动到最后,但加载后的某些任意记录)。我在store.load()的回调中执行view-refresh和bufferedrender-scrollTo。

鉴于您的代码,这将是:

this.on('afterrender', function (grid) {
      var store = grid.getStore();
      store.load({
          callback: function {
              // snip
              var view = topicPanel.getView();
              view.refresh();
              topicPanel.getPlugin('bufferedrenderer').scrollTo(store.getTotalCount()-1);
           }
      });
});