Last active
August 29, 2015 14:11
-
-
Save trezy/c0b35b29d4795e3387ca to your computer and use it in GitHub Desktop.
Backbone.Marionette - replaceElement
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{"title":"Backbone.Marionette - replaceElement","author":"trezy","pages":[{"pageName":"","sections":[{"type":"text","source":"My biggest gripe about Backbone.Marionette is that `Region`s require a wrapping element. Fortunately I've come up with a way to turn a Region's element into nothing but a placeholder so that it's removed when you use `Region.show()` to display a view. This will likely be in Marionette V3 but I don't want to wait that long so I've written this shim to implement the functionality today.\n\nFirst, we need to add a couple new methods to `Region`. `replaceEl()` will be called when we use `Region.show()` on an empty `Region` and `restoreEl()` will only be called when we use `Region.empty()` to make sure that we don't lose our `Region`'s position in the DOM."},{"type":"javascript","source":"Marionette.Region.prototype.replaceEl = function(view) {\n var parent;\n \n parent = this.el.parentNode;\n parent.replaceChild(view.el, this.el);\n this.replaced = true;\n};\n\nMarionette.Region.prototype.restoreEl = function() {\n var parent, view;\n \n view = this.currentView;\n parent = this.el.parentNode;\n parent.replaceChild(this.el, view.el);\n this.replaced = false;\n};"},{"type":"text","source":"Next we need to change a couple of `Region`'s current methods. [`attachHtml()`](https://github.com/marionettejs/backbone.marionette/blob/master/src/region.js#L196-L207) needs to be updated to use our new `replaceEl()` function if the `replaceElement` option is true. [`empty()`](https://github.com/marionettejs/backbone.marionette/blob/master/src/region.js#L211-L226) needs to be updated so that it will use our new `restoreEl()` function if the `Region`'s original element was replaced. Otherwise both of these methods remain largely unchanged."},{"type":"javascript","source":"Marionette.Region.prototype.attachHtml = function(view) {\n if (arguments[1]) {\n this.replaceEl(view);\n } else {\n this.$el.html('');\n this.el.appendChild(view.el);\n }\n};\n\nMarionette.Region.prototype.empty = function() {\n var view;\n \n view = this.currentView;\n \n if (!view) {\n return;\n }\n \n this.triggerMethod('before:empty', view);\n \n if (this.replaced) {\n this.restoreEl();\n }\n \n this._destroyView();\n this.triggerMethod('empty', view);\n delete this.currentView;\n \n return this;\n};"},{"type":"text","source":"Finally we need to update [`Region.show()`](https://github.com/marionettejs/backbone.marionette/blob/master/src/region.js#L40-L140). Again this method remains largely unchanged. All we need to do is add the pieces necessary for the `replaceElement` option. Here are the main pieces to concern yourself with:\n\n``` javascript\nvar replaceElement = !!showOptions.replaceElement;\n```\n\n``` javascript\nvar _shouldReplaceElement = replaceElement;\n```\n\n``` javascript\nthis.attachHtml(view, _shouldReplaceElement);\n```"},{"type":"javascript","source":"Marionette.Region.prototype.show = function(view, options){\n if (!this._ensureElement()) {\n return;\n }\n\n this._ensureViewIsIntact(view);\n\n var showOptions = options || {};\n var isDifferentView = view !== this.currentView;\n var preventDestroy = !!showOptions.preventDestroy;\n var forceShow = !!showOptions.forceShow;\n var replaceElement = !!showOptions.replaceElement;\n var isChangingView = !!this.currentView;\n var _shouldDestroyView = isDifferentView && !preventDestroy;\n var _shouldShowView = isDifferentView || forceShow;\n var _shouldReplaceElement = replaceElement;\n\n if (isChangingView) {\n this.triggerMethod('before:swapOut', this.currentView, this, options);\n }\n\n if (this.currentView) {\n delete this.currentView._parent;\n }\n\n if (_shouldDestroyView) {\n this.empty();\n\n } else if (isChangingView && _shouldShowView) {\n this.currentView.off('destroy', this.empty, this);\n }\n\n if (_shouldShowView) {\n view.once('destroy', this.empty, this);\n view.render();\n\n view._parent = this;\n\n if (isChangingView) {\n this.triggerMethod('before:swap', view, this, options);\n }\n\n this.triggerMethod('before:show', view, this, options);\n Marionette.triggerMethodOn(view, 'before:show', view, this, options);\n\n if (isChangingView) {\n this.triggerMethod('swapOut', this.currentView, this, options);\n }\n\n var attachedRegion = Marionette.isNodeAttached(this.el);\n\n var displayedViews = [];\n\n var triggerBeforeAttach = showOptions.triggerBeforeAttach || this.triggerBeforeAttach;\n var triggerAttach = showOptions.triggerAttach || this.triggerAttach;\n\n if (attachedRegion && triggerBeforeAttach) {\n displayedViews = this._displayedViews(view);\n this._triggerAttach(displayedViews, 'before:');\n }\n\n this.attachHtml(view, _shouldReplaceElement);\n this.currentView = view;\n\n if (attachedRegion && triggerAttach) {\n displayedViews = this._displayedViews(view);\n this._triggerAttach(displayedViews);\n }\n\n if (isChangingView) {\n this.triggerMethod('swap', view, this, options);\n }\n\n this.triggerMethod('show', view, this, options);\n Marionette.triggerMethodOn(view, 'show', view, this, options);\n\n return this;\n }\n\n return this;\n};"},{"type":"text","source":"And *voila*! You can grab the full shim [here](https://gist.github.com/trezy/978d241908060b2f902a). Just include the shim in your project *after* Marionette. Here's an example of it in use: "},{"type":"javascript","source":"var app, view;\n\napp = new Backbone.Marionette.Application({\n regions: {\n foo: '.foo'\n }\n});\n\nview = new Backbone.Marionette.ItemView;\n\napp.foo.show(view, { replaceElement: true });"}]}],"public":true} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment