In backbone marionette is there a way to tell if a view is already shown in a region?
Asked Answered
I

3

6

Given something like this:

View = Backbone.Marionette.ItemView.extend({ });

myView = new View();

//region already exists
myLayout.region.show(myView)

//some time later this gets called again:
myLayout.region.show(myView)

I can see currentView in the docs but this only seems to apply at initialisation. Once a view is shown can I query the region to see the view? Either the view instance or type would be helpful. Looking in Chrome's debugger I can't see any properties/methods on the region that would help.

The motive for wanting to do this is so I don't show a static item view in a region again if it is already displayed as this can (especially if images are involved) cause a slight flickering effect on the screen.

Thanks

--Justin Wyllie

Ic answered 13/8, 2013 at 11:43 Comment(0)
E
11

you can add a condition before calling show method:

if (myLayout.region.currentView != myView)
    myLayout.region.show(myView)

so if you'll try to call show with the same View it wont be shown.

if you want to call region.show(myView) once you can check in this way:

if (_.isUndefined(myLayout.region.currentView))
    myLayout.region.show(myView)
Earlap answered 13/8, 2013 at 11:55 Comment(6)
Thanks. That's what I was hoping to do. But on the region the only properties I see are el and options. No sign of a currentView property which I can check.Ic
What version of Marionette.js are using? The code I posted in my answer I'm using in my project.Earlap
Looks like 1.0.3. Alternatively is currentView something you are setting? Just possibly?Ic
No I do not set it manually. It sets by Region in method region.show(). You can check it in Marionette.Region.show()Earlap
Thanks. I see it now. (It is not set, naturally, until the first time show() is called which is why I missed it.). But I couldn't get the test for same view just using == to work. It was false even when it was the same view.Ic
== will return false until you compare variables that linked to the same instance. So if you have view1=new Marionette.ItemView() and view2=new Marionette.ItemView() view1 will not equal to view2 because it's different instances. But if you assign view3=view1 then they will be equal. In you case if you have different instances with equal content maybe comparing by view.$el.html() would be the best way. I'm not sure, more info needed.Earlap
G
7

You can check the isClosed and $el attributes of the view. Something like

if (myView.isClosed || _.isUndefined(myView.$el)) {
  myLayout.region.show(myView);
}

This is the same way the region checks to see if the view is closed or not:

show: function(view) {

  this.ensureEl();

  var isViewClosed = view.isClosed || _.isUndefined(view.$el);
  ...
Gadgetry answered 13/8, 2013 at 19:21 Comment(0)
A
0

I'm going out on a limb here and assuming that the OP's question is based on app behavior when navigating to different parts of the app via an anchor tag in the navigation or something similar.

This is how I found the question and I thought briefly that the answers would save my day. Although both answers so far are correct they do not quite solve the problem I was having. I wanted to display a persistent navigation bar. However, I did not want it to display on the login page. I was hopeful that detecting if a Region was already shown or not I'd be able to properly let the display logic take care of this.

As it turns out we were both on the right track to implement Regions as this provides granular control, but even after implementing the above I found that my nav bar would still "flicker" and essentially completely reload itself.

The answer is actually a bit ridiculous. Somehow in all the Backbone tutorials and research I've been doing the last two weeks I never came across the need to implement a javascript interface to interrupt normal link behavior. Whenever a navigation item was clicked the entire app was reloading. The routing was functioning so the content was correct, but the flicker was maddening.

I added the following to my app.js file right after the Backbone.history.start({pushState: true}); code:

// Holy crap this is SOOO important!
$(document).on("click", "a[href^='/']", function(event) {
  if (!event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey) {
    event.preventDefault();
    var url = $(event.currentTarget).attr("href").replace(/^\//, "");
    Backbone.history.navigate(url, { trigger: true });
  }
});

Check out this article for some explanation about the keyPress detection stuff. http://dev.tenfarms.com/posts/proper-link-handling

Boom! After adding this stuff in my app no longer completely reloads!

Disclaimer: I am very new to Backbone and the fact that the above was such a revelation for me makes me think that I may be doing something wrong elsewhere and this behavior should already exist in Backbone. If I've made a giant error here please comment and help me correct it.

Abusive answered 13/5, 2014 at 16:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.