如何在 Aurelia 中强制绑定重新评估或重新渲染 [英] How to force binding re-evaluate or re-rendering in Aurelia

查看:40
本文介绍了如何在 Aurelia 中强制绑定重新评估或重新渲染的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我开始使用 Aurelia、RethinkDB 和一个简单的 TODO 应用程序套接字.IO.我似乎在重新渲染或重新评估通过 Socket.IO 更改的对象时遇到问题.所以基本上,在第一个浏览器上一切正常,但不会在第二个浏览器中重新渲染,而在控制台中显示对象确实在我的对象中显示差异.问题仅在于更新对象,它可以完美地从待办事项数组中创建/删除对象.

HTML

    <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}<a href="#" click.delegate="$parent.deleteItem(item, $event)"><i class="glyphicon glyphicon-trash"></i></a>

<div show.bind="item.isEditing"><form submit.delegate="$parent.editEnd(item)"><input type="text" value.bind="item.title" blur.delegate="$parent.editEnd(item)"/></表单>

带有 RethinkDB 变更源的 NodeJS

//附加一个 RethinkDB 更改提要以查看任何更改r.table(配置表).变化().跑().then(函数(光标){//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);}});}).错误(功能(错误){console.log("Changefeeds 失败:", err);});

Aurelia 代码监视 Socket.on

//更新项目socket.on("todo_update", 数据 => {让 pos = arrayFindObjectIndex(this.items, 'id', data.id);如果(位置 >= 0){console.log('更新前');console.log(this.items[pos]);this.items[pos] = 数据;this.items[pos].title = this.items[pos].title + '[更新]';console.log('更新后');console.log(this.items[pos]);}});//创建项目,只有在项目列表中没有项目时才添加项目以避免被骗socket.on("todo_create", 数据 => {如果 (!_.some(this.items, function (p) {返回 p.id === data.id;})) {this.items.unshift(data);}});//删除项目,只有在项目列表中找到才删除项目socket.on("todo_delete", 数据 => {让 pos = arrayFindObjectIndex(this.items, 'id', data.id);如果(位置 >= 0){this.items.splice(pos, 1);}});

socket.on("todo_update", ...){} 没有让第二个浏览器重新渲染,但在更新之前/之后在控制台中显示对象确实在对象本身.我什至更改了 todo 标题属性,并且也不会重新渲染.

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

解决方案

Aurelia 通过覆盖数组的 mutator 方法(push、pop、splice、shift 等)来观察数组内容的变化.这适用于大多数用例并且性能非常好(没有脏检查,在内存和 CPU 方面非常轻量级).不幸的是,这留下了一种改变 aurelia 无法看到"的数组的方法:索引赋值……例如 myArray[6] = 'foo'.由于没有调用数组方法,绑定系统不知道数组发生了变化.

在你的情况下,尝试改变这个:

//更新项目socket.on("todo_update", 数据 => {让 pos = arrayFindObjectIndex(this.items, 'id', data.id);如果(位置 >= 0){console.log('更新前');console.log(this.items[pos]);this.items[pos] = 数据;//<-- 将其更改为: this.items.splice(pos, 1, data);this.items[pos].title = this.items[pos].title + '[更新]';console.log('更新后');console.log(this.items[pos]);}});

I am starting with a simple TODO app with Aurelia, RethinkDB & Socket.IO. I seem to have problem with re-rendering or re-evaluating an object that is changed through Socket.IO. So basically, everything works good on the first browser but doesn't get re-rendered in the second browser while displaying the object in the console does show differences in my object. The problem is only on updating an object, it works perfectly on creating/deleting object from the array of todo items.

HTML

<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>

NodeJS with RethinkDB changefeeds

// 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);
    });

Aurelia code watching Socket.on

// 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);
  }
});

The socket.on("todo_update", ...){} is not making the second browser re-render but showing the object in the console before/after update does show differences in the object itself. I even changed the todo title property and that too doesn't get re-rendered.

How can I get Aurelia to re-render in my second browser with the new object properties? Don't be too hard on me, I'm learning Aurelia/RethinkDB/NodeJS/Socket.IO all the same time...

解决方案

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]);
  }
});

这篇关于如何在 Aurelia 中强制绑定重新评估或重新渲染的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆