Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hold sync during set_state? #2259

Closed
vidartf opened this issue Nov 8, 2018 · 3 comments · Fixed by #3271
Closed

Hold sync during set_state? #2259

vidartf opened this issue Nov 8, 2018 · 3 comments · Fixed by #3271

Comments

@vidartf
Copy link
Member

vidartf commented Nov 8, 2018

While reviewing #2256, I considered that maybe a more elegant solution would be to use hold_sync when setting the state from an update message. This would ensure that any new state changes as a direct response to the update (i.e. synchronous changes from validators or observers) all get collapsed into a single update message to the frontend. This collapsed update could then be verified against the property lock simplifying the logic.

A possible problem is that if multiple attributes change, then there is a potential for a change in the order of JS-side change notifications. For example:

  • Previously a new state cause the updates: {foo: 5}, then {bar: 1}. This would trigger the change:foo and change events on the JS side first, with only foo updated. Then change:bar and change with bar updated.
  • Now, the new state cause the update: {foo: 5, bar: 1}. This triggers change:foo and change:bar in undefined order, then a single change event, all with both foo and bar updated.

This could potentially be an issue for selections, e.g. here. In this case, the view-code would need to always update the options and index in the same go, using hasChanged to confirm e.g. like this:

initialize(parameters) {
    super.initialize(parameters);
    this.listenTo(this.model, 'change', (model, value, options) => this._updateSelection(options));
    // Create listbox here so that subclasses can modify it before it is populated in render()
    this.listbox = document.createElement('select');
}

updateSelection(options: any = {}) {
    // Debounce set calls from ourselves:
    if (options.updated_view === this) {
        return;
    }
    const optsChanged = this.hasChanged('_options_labels');
    const idxChanged = this.hasChanged('index');
    // The attributes we care about did not change, skip
    if (!idxChanged && !optsChanged) {
        return;
    }

    // Get the index first!
    const idx = this.model.get('index');

    if (optsChanged) {
        // Need to update options:
        ... // Code as before
    }
    // Always set the index
    this.listbox.selectedIndex = index === null ? -1 : index;
}
@maartenbreddels
Copy link
Member

To fill in some things we considered during the meeting:
If not possible with backbone to handle these multiple changes in 1 event handler this may be an option to step away from it (cc @jasongrout)
A possible workaround would be to do the validation after a requestAnimationFrame, but that feels like a hack.
In any case, this should be a version 8.0 change.

@vidartf
Copy link
Member Author

vidartf commented Nov 8, 2018

A possible workaround would be to do the validation after a requestAnimationFrame, but that feels like a hack.

I did not include this in the issue as I forgot that backbone actually sets all the attributes before any events are triggered. As such, this workaround should not do anything.

@vidartf
Copy link
Member Author

vidartf commented Nov 8, 2018

Also: The fix for the selection widgets should be used anyways, as all widgets should deal with set being called with multiple arguments at the same time. As it stands now, the selection controls are likely to fail if hold_sync is used, which should be fixed!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants