如何强制在Aurelia中重新评估或重新渲染绑定

时间:2016-04-04 04:04:11

标签: javascript sockets aurelia rethinkdb aurelia-binding

我从一个简单的TODO应用开始,使用Aurelia,RethinkDB& Socket.IO。我似乎在重新渲染或重新评估通过Socket.IO更改的对象时遇到问题。所以基本上,一切都在第一个浏览器上运行良好但在第二个浏览器中没有重新渲染,而在控制台中显示对象确实显示了我的对象的差异。问题仅在于更新对象时,它完全适用于从待办事项数组创建/删除对象。

HTML

<div id="myModal"  data-keyboard="true" data-backdrop="static" class="modal fade" role="dialog" style="overflow-y: hidden;">
  <div class="modal-dialog modal-lg" style="overflow-y: hidden;" >
        <div class="modal-content" style="overflow-y: hidden;">
        <div class="modal-body" style="overflow-y: hidden;">
        <button type="button"  class="close" data-dismiss="modal">&times;</button>
        <iframe frameborder="0" style="overflow-y: hidden; max-height:85%;" ></iframe>
      </div>
    </div>
  </div>
</div>

带有RethinkDB更改源的NodeJS

<ul>
    <li repeat.for="item of items">
      <div show.bind="!item.isEditing">
        <input type="checkbox" checked.two-way="item.completed" click.delegate="toggleComplete(item)" />
        <label class="${item.completed ? 'done': ''} ${item.archived ? 'archived' : ''}" click.delegate="$parent.editBegin(item)">
          ${item.title}
        </label>
        <a href="#" click.delegate="$parent.deleteItem(item, $event)"><i class="glyphicon glyphicon-trash"></i></a>
      </div>
      <div show.bind="item.isEditing">
        <form submit.delegate="$parent.editEnd(item)">
          <input type="text" value.bind="item.title" blur.delegate="$parent.editEnd(item)" />
        </form>
      </div>
    </li>
  </ul>

Aurelia代码正在观看Socket.on

// attach a RethinkDB changefeeds to watch any changes
r.table(config.table)
    .changes()
    .run()
    .then(function(cursor) {
        //cursor.each(console.log);
      cursor.each(function(err, item) {
        if (!!item && !!item.new_val && item.old_val == null) {
          io.sockets.emit("todo_create", item.new_val);
        }else if (!!item && !!item.new_val && !!item.old_val) {
          io.sockets.emit("todo_update", item.new_val);
        }else if(!!item && item.new_val == null && !!item.old_val) {
          io.sockets.emit("todo_delete", item.old_val);
        }
      });
    })
    .error(function(err){
        console.log("Changefeeds Failure: ", err);
    });

// update item socket.on("todo_update", data => { let pos = arrayFindObjectIndex(this.items, 'id', data.id); if(pos >= 0) { console.log('before update'); console.log(this.items[pos]); this.items[pos] = data; this.items[pos].title = this.items[pos].title + ' [updated]'; console.log('after update'); console.log(this.items[pos]); } }); // create item, only add the item if we don't have it already in the items list to avoid dupes socket.on("todo_create", data => { if (!_.some(this.items, function (p) { return p.id === data.id; })) { this.items.unshift(data); } }); // delete item, only delete item if found in items list socket.on("todo_delete", data => { let pos = arrayFindObjectIndex(this.items, 'id', data.id); if(pos >= 0) { this.items.splice(pos, 1); } }); 没有使第二个浏览器重新渲染,但在更新之前/之后显示控制台中的对象确实显示了对象本身的差异。我甚至改变了todo title属性,也没有重新渲染。

如何让Aurelia在我的第二个浏览器中使用新的对象属性重新渲染?不要太难我,我同时学习Aurelia / RethinkDB / NodeJS / Socket.IO ......

1 个答案:

答案 0 :(得分:20)

Aurelia observes changes to the contents of an array by overriding the array's mutator methods (push, pop, splice, shift, etc). This works well for most use-cases and performs really well (no dirty-checking, extremely lightweight in terms of memory and cpu). Unfortunately this leaves one way of mutating an array that aurelia can't "see": indexed assignment... eg myArray[6] = 'foo'. Since no array methods were called, the binding system doesn't know the array changed.

In your case, try changing this:

// update item
socket.on("todo_update", data => {
  let pos = arrayFindObjectIndex(this.items, 'id', data.id);
  if(pos >= 0) {
    console.log('before update');
    console.log(this.items[pos]);

    this.items[pos] = data; // <-- change this to: this.items.splice(pos, 1, data);

    this.items[pos].title = this.items[pos].title + ' [updated]';
    console.log('after update');
    console.log(this.items[pos]);
  }
});