From ba4c9d77c3c3dbaeec7c34507018d67c7083995e Mon Sep 17 00:00:00 2001 From: Paul Falgout Date: Thu, 1 Sep 2016 01:50:01 +0900 Subject: [PATCH 1/5] Make a public detachView This function removes the need for a `preventDestroy` option. Essentially if you want to `preventDestroy` just detach the view first. When you want to preventDestroy you already have to have a copy of the view.. and depending on what is doing the view emptying `preventDestroy` can become a round about API. What you really want is ```js const myView = myRegion.currentView; myRegion.detachView(); myOtherRegion.show(myView); ``` --- src/region.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/region.js b/src/region.js index 42c0652e49..5cd9ef5e98 100644 --- a/src/region.js +++ b/src/region.js @@ -245,6 +245,17 @@ const Region = MarionetteObject.extend({ } }, + detachView() { + const view = this.currentView; + + delete this.currentView; + + this._detachView(view); + delete view._parent; + + return this; + }, + _detachView(view) { const shouldTriggerDetach = !!view._isAttached; if (shouldTriggerDetach) { From 57eab1f931ee2c9626c07bb2d16c5acaa472eff9 Mon Sep 17 00:00:00 2001 From: Rafael De Leon Date: Sat, 3 Sep 2016 11:10:55 -0700 Subject: [PATCH 2/5] regions mixin detachView * falsy check Regions detachChildView --- src/mixins/regions.js | 4 ++++ src/region.js | 8 +++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/mixins/regions.js b/src/mixins/regions.js index 5342e06d46..e000234362 100644 --- a/src/mixins/regions.js +++ b/src/mixins/regions.js @@ -180,6 +180,10 @@ export default { return region.show(view, ...args); }, + detachChildView(name) { + return this.getRegion(name).detachView(); + }, + getChildView(name) { return this.getRegion(name).currentView; } diff --git a/src/region.js b/src/region.js index 5cd9ef5e98..45e1b847ec 100644 --- a/src/region.js +++ b/src/region.js @@ -248,12 +248,14 @@ const Region = MarionetteObject.extend({ detachView() { const view = this.currentView; - delete this.currentView; + if (!view) { + return; + } + delete this.currentView; this._detachView(view); delete view._parent; - - return this; + return view; }, _detachView(view) { From 59124d31136d0af937d14521f47408e04e87bd07 Mon Sep 17 00:00:00 2001 From: Rafael De Leon Date: Sun, 4 Sep 2016 09:33:09 -0700 Subject: [PATCH 3/5] [test] View detachChildView --- test/unit/view.child-views.spec.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/unit/view.child-views.spec.js b/test/unit/view.child-views.spec.js index 88ff7beaf5..e7bdf68aa2 100644 --- a/test/unit/view.child-views.spec.js +++ b/test/unit/view.child-views.spec.js @@ -315,6 +315,21 @@ describe('layoutView', function() { it('childViewEvents are triggered', function() { expect(this.childEventsHandler).to.have.been.calledOnce; }); + + describe('and the view is detached', function() { + beforeEach(function() { + this.detachedView = this.layoutView.detachChildView('regionOne'); + this.noDetachedView = this.layoutView.detachChildView('regionOne'); + }); + + it('should return the childView it was given', function() { + expect(this.detachedView).to.equal(this.childView); + }); + + it('should not return a childView if it was already detached', function() { + expect(this.noDetachedView).to.be.undefined; + }); + }); }); describe('when showing a layoutView via a region', function() { From 84ebc1d07e15a5ab854d16a03eb356484d2392a8 Mon Sep 17 00:00:00 2001 From: Rafael De Leon Date: Sun, 4 Sep 2016 11:32:24 -0700 Subject: [PATCH 4/5] [test] Region detachView --- test/unit/region.spec.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/unit/region.spec.js b/test/unit/region.spec.js index 8898ff9083..b8cb519aec 100644 --- a/test/unit/region.spec.js +++ b/test/unit/region.spec.js @@ -449,6 +449,20 @@ describe('region', function() { }); }); + describe('and the view is detached', function() { + beforeEach(function() { + this.detachedView = this.region.detachView(); + this.noDetachedView = this.region.detachView(); + }); + + it('should return the childView it was given', function() { + expect(this.detachedView).to.equal(this.view); + }); + + it('should not return a childView if it was already detached', function() { + expect(this.noDetachedView).to.be.undefined; + }); + }); }); describe('when showing nested views', function() { From 53a1611cfb8bba1c05e3d710a5e9df1e82e9faef Mon Sep 17 00:00:00 2001 From: Rafael De Leon Date: Sun, 4 Sep 2016 16:15:48 -0700 Subject: [PATCH 5/5] [documentation] Region#detachView [documentation] View#detachChildView --- docs/marionette.region.md | 18 ++++++++++++++++++ docs/marionette.view.md | 29 +++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/docs/marionette.region.md b/docs/marionette.region.md index 5f9389d645..e803888eda 100644 --- a/docs/marionette.region.md +++ b/docs/marionette.region.md @@ -18,6 +18,7 @@ managing regions throughout your application. * [Showing a View](#showing-a-view) * [Hiding a View](#hiding-a-view) * [Preserving Existing Views](#preserving-existing-views) + * [Detaching Existing Views](#detaching-existing-views) * [Checking whether a region is showing a view](#checking-whether-a-region-is-showing-a-view) * [`reset` A Region](#reset-a-region) @@ -219,6 +220,23 @@ mainRegion.empty({preventDestroy: true}); **NOTE** When using `preventDestroy: true` you must be careful to cleanup your old views manually to prevent memory leaks. +### Detaching Existing Views +If you want to detach an existing view from a region, use `detachView`. + +```javascript +var myView = new MyView(); + +var myOtherView = new MyView(); + +var childView = new MyChildView(); + +// render and display the view +myView.showChildView('main', childView); + +// ... somewhere down the line +myOtherView.showChildView('main', myView.getRegion('main').detachView()); +``` + ### Checking whether a region is showing a view If you wish to check whether a region has a view, you can use the `hasView` diff --git a/docs/marionette.view.md b/docs/marionette.view.md index 27815add19..e3628989a8 100644 --- a/docs/marionette.view.md +++ b/docs/marionette.view.md @@ -20,6 +20,7 @@ multiple views through the `regions` attribute. * [Managing Sub-views](#managing-sub-views) * [Showing a view](#showing-a-view) * [Accessing a child view](#accessing-a-child-view) + * [Detaching a child view](#detaching-a-child-view) * [Organizing your View](#organizing-your-view) * [Events](#events) * [onEvent Listeners](#onevent-listeners) @@ -198,6 +199,34 @@ var MyView = Mn.View.extend({ If no view is available, `getChildView` returns `null`. +#### Detaching a child view +You can detach a child view from a region through `detachChildView(region)` + +```javascript + +var Mn = require('backbone.marionette'); +var SubView = require('./subview'); + +var MyView = Mn.View.extend({ + template: '#tpl-view-with-regions', + + regions: { + firstRegion: '#first-region', + secondRegion: '#second-region' + }, + + onRender: function() { + this.showChildView('firstRegion', new SubView()); + }, + + onMoveView: function() { + var view = this.detachChildView('firstRegion'); + this.showChildView('secondRegion', view); + } +}); +``` +This is a proxy for [region.detachView()](./marionette.region.md#detaching-existing-views) + ### Region availability Any defined regions within a `View` will be available to the `View` or any calling code immediately after instantiating the `View`. This allows a View to