(backbone) Events across Views

44 views
Skip to first unread message

Shell (Aridhia Informatics)

unread,
Mar 28, 2013, 1:01:56 PM3/28/13
to choru...@googlegroups.com
Hi guys,

A (probably simple) Backbone question within the context of OC

We have a new page which needs to be able to 'hide' elements of the UI that've been rendered by other views/templates. What is the best way to go about this? For example, say I want to hide the header on page X & display some other elements, how would I trigger this from postRender() from page X's view?

While I've found several Backbone examples, I'm not sure architecturally what the best approach is.

S.

Luke Winikates

unread,
Mar 28, 2013, 1:18:25 PM3/28/13
to choru...@googlegroups.com
Hi, Shell,

Are you trying to hide it always, or toggle visibility based on user input?

Shell (Aridhia Informatics)

unread,
Mar 28, 2013, 1:30:38 PM3/28/13
to choru...@googlegroups.com
Hides on page entry (slides away), a different element being displayed instead. User can click this new element to re-display the header. We have a rather customer header in our application, and need to have the header hidden in *some* contexts, but always allow the user to redisplay it if they want.

Luke Winikates

unread,
Mar 28, 2013, 3:02:18 PM3/28/13
to choru...@googlegroups.com
You can fire your hideHeader() method in postRender() on the page whose header you want to hide. 

In that header's page view, you can create a showHeader() method, and bind that to a click event using the view's events hash:

events: {
 
'click .show-header': 'showHeader'
},


showHeader
: function() {
 
// some jquery
}

Shell (Aridhia Informatics)

unread,
Mar 29, 2013, 12:50:08 PM3/29/13
to choru...@googlegroups.com
That makes sense, and is along the lines of my own experimentation. I am, however, having issues with using jquery to select elements of the UI to hide.

Our header contains two elements which need to be either displayed or not. Lets call these foo1 and foo2. On entering the page, foo1 slides out of the way and foo2 is displayed instead.

In my_index_page.js, I have added showSomething: function() { $(".foo1").hide(); }. This does not work. I can hide() the entire header like this: showSomething: function() { $( this.header.el ).hide(); } but I am unable to target foo1 or foo2. If, for example, I var foo1 = $( this.header.el ).find( ".foo1"); foo1.hide() or  var foo1 = $( ".foo1", this.header.el ); foo1.hide(); nothing happens.

I'm clearly missing something fundamental here!

S.

Luke Winikates

unread,
Mar 29, 2013, 1:16:28 PM3/29/13
to choru...@googlegroups.com

The basic problem seems to be that
$( this.header.el ).hide();
works, but
$(".foo1").hide(); 
does not.

You might be calling hide before the element matching your selector is inserted into the DOM. The only difference between those two lines is the selector, so it seems like the selector must be returning nothing. When is showSomething being called? If you throw a console.log or debugger line into showSomething, what is the value of var foo1?

-Luke Winikates & Laura Kogler


--
You received this message because you are subscribed to the Google Groups "chorus-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chorus-dev+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Joseph Palermo

unread,
Mar 29, 2013, 1:21:18 PM3/29/13
to choru...@googlegroups.com
Anytime you are trying to select elements from a view you should use this.$('.selector') rather than $('.selector').

The this.$ is scoped to the element owned by the view, so you won't find other elements in the DOM that might also match what you are looking for.

It will also work even if the view has not yet been attached to the DOM, which I think is the problem in your case.  $ only finds elements attached to the main window document.

Backbone has some notes on this:
as well as this.$el which we use less, but it is good to know about:


On Fri, Mar 29, 2013 at 9:50 AM, Shell (Aridhia Informatics) <shell...@gmail.com> wrote:
--

Shell (Aridhia Informatics)

unread,
Apr 1, 2013, 6:37:25 AM4/1/13
to choru...@googlegroups.com
Thanks. Yes, I figured out it was a scoping issue.

The problem is that 'page' view owns the 'header' view, and I need a view that is loaded into 'main-content' to tell the header to hide itself.

The header view renders a container element (<header>) containing two <sections>, .headerbar and .pulltab.

This morning I tried this...

In pages.js, added:

pulltab: function() { this.header.show_pulltab; }

In header.js, added:

show_pulltab: function() {
   
this.$(".headerbar").hide(); // does nothing
   
this.$(".pulltab").show();   // does nothing
    console
.log("This message gets displayed");
}

And in our new page view (that needs to trigger this behaviour):

postRender: function() {
   
this.show_pulltab();
}

The message is displayed, but the DOM doesn't get manipulated.

S.

Shell (Aridhia Informatics)

unread,
Apr 1, 2013, 11:10:03 AM4/1/13
to choru...@googlegroups.com
I discovered messaging. So here's my new attempt.

In header.js:

setup:function() {
   
...
   
this.subscribePageEvent("ui:pulltab", this.showPulltab);
   
...
}

then:

showPulltab:function() {
   
this.$(".headerbar").hide(); // does nothing!
   
this.$(".pulltab").show();   // does nothing!
}

Now, over in the view for our page we have:

postRender:function(){
   
chorus.PageEvents.broadcast("ui:pulltab",this);
}

The even listener is firing after our page loads, and I am getting debug messages. I'm unsure why our jQuery is working using this method (although it feels much cleaner now).

S.


On Friday, March 29, 2013 5:21:18 PM UTC, Joseph Palermo wrote:

Shell (Aridhia Informatics)

unread,
Apr 1, 2013, 11:14:55 AM4/1/13
to choru...@googlegroups.com
*not working, rather.

Luke Winikates

unread,
Apr 1, 2013, 12:44:30 PM4/1/13
to choru...@googlegroups.com
Shell-- 
Does $('.headerbar') return any elements if called inside of showPullTab? Are you able to call it directly using the browser's javascript console? 

Either showPullTab is not working (because it's being called before the view has rendered those elements), or it's working fine, but additional rendering is happening later and the header is getting put back into the DOM.

-Luke Winikates & Laura Kogler

Shell (Aridhia Informatics)

unread,
Apr 2, 2013, 5:21:47 AM4/2/13
to choru...@googlegroups.com
Calling...

chorus.page.header.showPulltab();

...from the console has the appropriate effect, suggesting, perhaps, that we are seeing additional render is being run :s

S.

Shell (Aridhia Informatics)

unread,
Apr 2, 2013, 11:15:53 AM4/2/13
to choru...@googlegroups.com
Given we're still having issues working with this, I'm wondering if we are taking the right architectural approach for achieving the UI we want.

We have 'pages' within the application that do not warrant the standard header or side bar. Our attempts to turn these off are failing, put perhaps we're looking at this the wrong way. So my question is, if you guys were attempting a similar task, how would you approach it?

S.


On Monday, April 1, 2013 5:44:30 PM UTC+1, Luke Winikates wrote:

Charles Hansen

unread,
Apr 2, 2013, 1:01:01 PM4/2/13
to choru...@googlegroups.com
It looks like you are running into one of our more common difficulties with Chorus.  Views render all the time and when they do, they lose state.  In the case of the header, it renders twice every time you go to a page, once when the model is loaded and once when the notifications are loaded.  You can put a 'console.log("rendering header")' in your header.js postRender function too see the calls.

We often solve this over-rendering by creating views that only render once and creating subviews that render often for the parts that need to update.  This is usually difficult, and probably not what you are looking for here.  

Depending on your structure, the simplest option is saving state in the view itself.


showPulltab:function() {
   this.showHeaderBar = false;  
}

additionalContext: function() {
   ....
   showHeaderBar = this.showHeaderBar
}


and then using that state in the handlebars:

{{#if showHeaderBar}}
    <div class="headerbar">.....</div>
{{else}}
    <div class="pulltab>.....</div>
{{/if}}


The other approach we might take in your case is to swap out header views on the page level.  You could include something in page.js that looks like

showPulltab:function() {
   this.fullHeader = this.header;
   this.header = this.pullTab;  //You'd need to initialize this too
   this.header.render();   
}

There are some memory leak side effects of swapping out like this, you can look at the 'showSidebar' method in workspace_dataset_show_page.js for a working example.

Charles



Shell (Aridhia Informatics)

unread,
Apr 3, 2013, 6:54:01 AM4/3/13
to choru...@googlegroups.com
Going with this solution:

showPulltab:function() {
   
this.showHeaderBar = false;  
}

...



additionalContext
: function() {
   
....
   showHeaderBar
= this.showHeaderBar
}

...

{{#if showHeaderBar}}
   
<div class="headerbar">.....</div>
{{else}}
   
<div class="pulltab>.....</div>
{{/if}}


...how would one turn back *on* the headerbar via user click on the pulltab? This is what I tried:

events:{
   
...
   
"click .pulltab": "hidePulltab"
   
...
}


... 

hidePulltab: function() {
   
this.showHeaderBar = true;
}

This doesn't regenerate the headerbar. So, I tried:

hidePulltab: function() {
   
this.showHeaderBar = true;
   
this.render();
}

No luck either.

S.
Reply all
Reply to author
Forward
0 new messages