How *not* to destroy View when exiting a route in Ember.js

前端 未结 2 637
后悔当初
后悔当初 2021-02-02 00:32

Regarding the new Ember.js routing system (described here), if I understand correctly, views are destroyed when you exit a route.

Is there any way to bypass destruction

相关标签:
2条回答
  • 2021-02-02 01:09

    So that the state of the view is preserved when the user re-enters the route.

    I would, instead, store that information in the controller (or the state manager) so that when the route is re-entered, the new view is initialized with the old state. Does that make sense? So, for example, if it's a list of posts, and one is selected, you would store the data about which post was selected in the controller (or the state manager). After visiting a specific post and then coming back to the list, that same post would be selected.

    I can imagine a use case where this wouldn't be very useful (e.g. scrolling to a specific position in a long list) so maybe that doesn't answer your question.

    0 讨论(0)
  • 2021-02-02 01:28

    I have since figure out how to modify the routing system, so that views inserted into outlets are not destroyed. First I override the Handlebars outlet helper, so that it loads an Ember.OutletView into {{outlet}}:

    Ember.Handlebars.registerHelper('outlet', function(property, options) {
      if (property && property.data && property.data.isRenderData) {
        options = property;
        property = 'view';
      }
    
      options.hash.currentViewBinding = "controller." + property;
    
      return Ember.Handlebars.helpers.view.call(this, Ember.OutletView, options);
    });
    

    Where Ember.OutletView extends Ember.ContainerView as follows:

    Ember.OutletView = Ember.ContainerView.extend({
        childViews: [],
    
        _currentViewWillChange: Ember.beforeObserver( function() {
            var childViews = this.get('childViews');
    
                // Instead of removing currentView, just hide all childViews
                childViews.setEach('isVisible', false);
    
        }, 'currentView'),
    
        _currentViewDidChange: Ember.observer( function() {
            var childViews = this.get('childViews'),
                currentView = this.get('currentView');
    
            if (currentView) {
                // Check if currentView is already within childViews array
                // TODO: test
                var alreadyPresent = childViews.find( function(child) {
                   if (Ember.View.isEqual(currentView, child, [])) {          
                       return true;
                   } 
                });
    
                if (!!alreadyPresent) {
                    alreadyPresent.set('isVisible', true);
                } else {
                    childViews.pushObject(currentView);
                }
            }
        }, 'currentView')
    
    });
    

    Basically we override _currentViewWillChange() and just hide all childViews instead of removing the currentView. Then in _currentViewDidChange() we check if the currentView is already inside childViews and act accordingly. The Ember.View.isEqual is a modified version of Underscore isEqual:

    Ember.View.reopenClass({ 
        isEqual: function(a, b, stack) {
            // Identical objects are equal. `0 === -0`, but they aren't identical.
            // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
            if (a === b) return a !== 0 || 1 / a == 1 / b;
            // A strict comparison is necessary because `null == undefined`.
            if (a == null || b == null) return a === b;
            // Unwrap any wrapped objects.
            if (a._chain) a = a._wrapped;
            if (b._chain) b = b._wrapped;
            // Compare `[[Class]]` names.
            var className = toString.call(a);
            if (className != toString.call(b)) return false;
    
            if (typeof a != 'object' || typeof b != 'object') return false;
            // Assume equality for cyclic structures. The algorithm for detecting cyclic
            // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
            var length = stack.length;
            while (length--) {
                // Linear search. Performance is inversely proportional to the number of
                // unique nested structures.
                if (stack[length] == a) return true;
            }
            // Add the first object to the stack of traversed objects.
            stack.push(a);
            var size = 0, result = true;
            // Recursively compare objects and arrays.
            if (className == '[object Array]') {
                // Compare array lengths to determine if a deep comparison is necessary.
                size = a.length;
                result = size == b.length;
                if (result) {
                    // Deep compare the contents, ignoring non-numeric properties.
                    while (size--) {
                        // Ensure commutative equality for sparse arrays.
                        if (!(result = size in a == size in b && this.isEqual(a[size], b[size], stack))) break;
                    }
                }
            } else {
                // Objects with different constructors are not equivalent.
                if (a.get('constructor').toString() != b.get('constructor').toString()) {
                    return false;
                }
    
                // Deep compare objects.
                for (var key in a) {
                    if (a.hasOwnProperty(key)) {
                        // Count the expected number of properties.
                        size++;
                        // Deep compare each member.
                        if ( !(result = b.hasOwnProperty(key) )) break;
                    }
                }
            }
            // Remove the first object from the stack of traversed objects.
            stack.pop();
            return result;
        }
    });
    
    0 讨论(0)
提交回复
热议问题