Update Aurelia observed property on change to containing array

a 夏天 提交于 2019-12-02 00:12:27

问题


I have a simple class, Event with a computed property:

import moment from 'moment';

export class Event {
    constructor(data) {
        Object.assign(this, data);
    }

    get playedFromNow() { 
        return moment(this.CreateDate).fromNow();
    }
}

playedFromNow just returns a string based on the CreateDate property, like 7 minutes ago.

The viewmodel gets an array of events and the view renders the events. The array gets updated via websockets every time a new event occurs (every few minutes).

<div repeat.for="event of events">
    <div class="media-body">
        <h4 class="media-heading">${event.title} <small>${event.playedFromNow}</small></h4>
    </div>
</div>

And the (relevant) viewmodel code:

let  socket = io();
socket.on(`new-event`, (data) => { 
  this.events.unshift(new Event(data)); // add to the event array at the top
});

// subscribe
let subscription = bindingEngine.collectionObserver(this.events).subscribe();
// unsubscribe
subscription.dispose();

Currently the property is dirty checked, which means the property is checked and changes very frequently - this is a bit unnecessary and there are a lot of events shown on a screen so I'm concerned about performance over time. Is there a way that I can trigger the recalculation based on the array binding and update code in the VM?:


回答1:


The latest aurelia release has a new feature: binding behaviors that will help with this use case.

First step would be to remove the playedFromNow property from the view-model. We're going to put the logic in a value-converter to eliminate the dirty-checking and enable the logic to be reused in other views:

from-now.js

import moment from 'moment';

export class FromNowValueConverter {
  toView(date) {
    return moment(date).fromNow();
  }
}

Now lets update our view to use the value converter as well as the built-in signal binding behavior. With signal we'll be able to tell the binding when to refresh.

Change ${event.playedFromNow} to:

${event.CreateDate | fromNow & signal:'tick'}

In plain english this binding says, convert the date value using the fromNow converter and refresh the binding whenever tick is signaled.

Don't forget to import the value converter at the top of your view:

<!-- this goes at the top of any view using the FromNowValueConverter -->
<require from="./from-now"></require>

Finally, let's fire the tick signal periodically... every minute?

import {BindingSignaler} from 'aurelia-templating-resources';

@inject(BindingSignaler)
export class App {  
  constructor(signaler) {
    // refresh all bindings with the signal name "tick" every minute:
    setInterval(() => signaler.signal('tick'), 60 * 1000);
  }
}


来源:https://stackoverflow.com/questions/33759154/update-aurelia-observed-property-on-change-to-containing-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!