Skip to content

Instantly share code, notes, and snippets.

@rstormsf
Forked from trezy/gistbook.json
Created December 20, 2014 03:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rstormsf/a046dac7f28738d368d2 to your computer and use it in GitHub Desktop.
Save rstormsf/a046dac7f28738d368d2 to your computer and use it in GitHub Desktop.
Backbone.Marionette - replaceElement
{"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