Monday, March 05, 2007

Quick Tip: Collapse All In Embedded View

For all of the great things that embedded views offer us in terms of interface mechanisms, there are some gotchas which are a real pain in the (neck, ass, {insert body part of your choice here}). One of the more annoying ones is the inability to set an embedded view using "Show Single Category" to automatically collapse when the container document is opened. This is especially troubling if there is additional categorization in the view, since everything opens expanded.



There are several hacks and work arounds that people have come up with over the years to address this, some better than others. This tip is an enhancement to one of the hacks I found in the ND 4/5 forum on developerWorks. Originally posted by Andes Mygind, this technique opens the embedded view to the category in question, collapses all the entries, expands the first entry and then closes the window. The result is indeed successful, with the embedded view collapsing nicely, as seen in the figure below.



From a user interface perspective, this solution is less than perfect though, since the act of opening the view and performing the necessary actions can actually be seen by the users. It only takes a second or so, but it is visually jarring as the screen quickly changes. To address this UI problem, I decided to apply an old web trick to hide the "behind the scenes" stuff from the user. That is, I used a frameset with two frames, one of which is set to a height of 0. I then just needed to add one additional line to the code, setting the target frame in which all of the actions should occur. I set the properties of the form in question to open in the specified frameset.



Below is the code, which I have found works beautifully:

REM {I placed this code in the PostOpen event of the container form so that the embedded view is collapsed immediately}:

REM {We don't need to do anything if this is a new document...};
@If(@IsNewDoc;
@Return("");
"");

REM {First, set the target to the hidden frame...this is where all the action happens};
@SetTargetFrame("EmbeddedViewTarget");

REM {The first line opens the view to the value we are using in the Show Single Category option};
@Command([OpenView];"YourEmbeddedView"; txt_Key);
@Command([ViewCollapseAll]);
@Command([ViewExpand]);

REM {This is a call to an agent which doesn't really do anything. I have no idea why this is here really, but this technique doesn't work without it. This agent contains just a single line of code...@Success};
@Command([ToolsRunMacro];"(f9)")

Bonus Tip: When you are testing this in the client, make sure you close the form in design mode. If you don't, the embedded view will continue to stay open and the collapse will never work!

The other neat thing about this technique is that you don't have to place the code in the view's action bar. It can actually be on the container form, which opens up more possibilities for extending the code or for different formatting options.



Finally, in addition to "Collapse All", you can do an "Expand All" in the same way:

@SetTargetFrame("EmbeddedViewTarget");
@Command([OpenView];"YourEmbeddedView"; txt_Key);
@Command([ViewExpandAll]);
@Command([ToolsRunMacro];"(f9)")

If you have thoughts on this approach or ways to improve it, I welcome them in the comments. Cheers!

28 comments:

Anonymous said...

YYYYEEEESSSSS!!!

Anonymous said...

Fantastic! Thanks...

Nathan T. Freeman said...

I'm vague on something... is the target of "EmbeddedViewFrame" the label for your actual embedded view in the form? So you're setting that as the target frame from the "Collapse All" action you have there on the container form, right?

I ask because anything BESIDES the [OpenView] call isn't supposed to work. Which suggests that as long as you START with the [OpenView] then you can proceed from there.

Chris Blatnick said...

@Nathan...I probably didn't explain that too well. "EmbeddedViewFrame" is the name of the hidden frame that exists in the frameset the container form is opening in. If you remove that first line of code that sets the target frame, all the remaining code executes in a separate window. By using the hidden frame and targeting it, I'm just making it occur where the user can't see it. It doesn't seem like it should have any effect on the embedded view itself, but it does.

Kevin Pettitt said...

I understood that EmbeddedViewFrame was a hidden frame, but like Nathan I'm a bit surprised the code after the @Command(openview) worked without an @UpdateFormulaContext line.

I've been having some serious fun with @UpdateFormulaContext recently (if you call having two rows of view action buttons cool ;-) ). Stay tuned for that...

In any case, very cool tip. I think the f9 agent is simply a way to trigger a view refresh because it seems that running *any* agent in a certain context will refresh the view. I tested an agent with @Success and no matter what you call it, running it from a view refreshes that view. The f9 label is probably therefore just descriptive of the purpose. That may be something that @Updateformulacontext makes unnecessary.

Patrick Kwinten said...

You can collapse an embedded view BY DEFAULT via lotusscript, the same routine can be used for a expand / collapse function under a button:

http://quintessens.wordpress.com/2006/10/29/collapse-a-categorized-embedded-view-by-default/

Joel said...

One thing I have found using this is that, in a single category view, when I open the form it works with the default category (selected via default value in the combobox). If I change my category, it no longer works. However, if I change the category to *, showing all categories, it works again, but the "default" value will no longer work. The show single category formula in my embedded view is

@If(status = "All"; "*"; status)

Joel said...

One thing I have found using this is that, in a single category view, when I open the form the expand/collapse works with the default category (selected via default value in the combobox). If I change my category, it no longer works. However, if I change the category to *, showing all categories, it works again, but the "default" value will no longer work. The show single category formula in my embedded view is

@If(status = "All"; "*"; status)

dogu said...

Chris, I'm missing something. Let me describe what I tried that's not working and you can tell me where I went wrong.

Create a frameset - frmsetMine
Two frames
- frmTop, contains a view, vwMine
- frmBottom, contains the same view

Create a form.
Launch tab -
Auto frame
- Frameset frmsetMine
- Frame frmBottom
Form PostOpen code
REM {I placed this code in the PostOpen event of the container form so that the embedded view is collapsed immediately};

@If(@IsNewDoc;
@Return("");
"");

@SetTargetFrame("frmBottom");

REM {The first line opens the view to the value we are using in the Show Single Category option};
@Command([OpenView];"vwMine");
@Command([ViewCollapseAll]);
@Command([ViewExpand]);

@Command([ToolsRunMacro];"(f9)")

I left off the text key because the view is not single cat and I want to collapse the entire thing.

I did not hide frmTop just to see what happens.

I stuck a table with an embedded editor and an embedded view at the top of the form.

When I open the form, I see frmBottom beginning at about the middle of the page, goes all the way across, and fully expanded.
I pulled the @Command([ViewExpand]), no change.

The view is categorized and contans no event code.

What am I missing?

TIA.

Doug

dogu said...

Getting closer but no cigar.

I figured out that the frameset doesn't need anything in either frame so I make them both with no content.

I modified my test environment to include 2 categorized columns and then added an embedded single cat view so me test design looks more like yours.

I dropped the ..viewExpand.. command because I wanted to see the all sub cats on the single cat collapsed.

When the form with the embedded view and framset opens, the embedded view remains fully expanded. If I switch back to the view, the single cat is totally collapsed - the code is executing but the form isn't reflecting the update to the view.

???

The form is set to refresh automatically.

I'm still missing something. Any suggestions?

Thanks.

Doug

janeg said...

Chris, is there any chance you have a working demo of this anywhere. For the life of me, I can't get it to work; not sure what I'm missing.

Thanks

Chris Blatnick said...

@Jane...Yes, a sample database is on the way. I've had lots of requests from recent posts, so I'll probably do a "All Sample Databases" post soon. :-)

janeg said...

Great. Thanks Chris :)

dogu said...

I think I got the collapse view stuff working. Here are my notes on what is required. I have not been able to get Nathan's adaptation to run an agent on multiple selected docs to work.

Doug

The form with the embedded view includes postopen event code (from this blog) to collapse the embedded view.
CODE DOES NOT WORK IN EDIT MODE, WORKS IN READ MODE ONLY. I think this is the bit that was confusing me.

The launch tab on this form includes the frameset, with bottom frame set as frame to open.

Frameset includes top and bottom frames.
Top is set to be closed. Top frame can contain the view of interest or be empty.
Bottom contains this form with target for links set to nothing. The bottom frame does not need to contain anything.


Set TestField2
Code in hot spot:
@SetTargetFrame("frameTop");
@Command([OpenView];"vwEmbeddedSingleCat");
@Command([ToolsRunMacro];"(UpdateTestField2)")

Agent launch in hot spot does not work. (code based on Escape Velocity Acting on multiple docs in an embedded view) If anybody has suggestions for this one, let me know.

The agent is just an @SetField to see if I can get it working. I tried building a LS doc collection but the collection is always just 1.

Doug

Chris Blatnick said...

@Doug...mine works just fine whether I open the document in read mode or edit mode. As soon as I have a chance to put a sample together, you can take a look. Maybe there are some other events getting in the way of the collapse when the document is opened in edit mode. That's the problem with all these hacks...trying to get them just right! :-)

dogu said...

Chris,

Doc PostOpen:
@If(@IsNewDoc;@Return("");@Success);

@SetTargetFrame("frameTop");
@Command([OpenView];"vwEmbeddedSingleCat";"aaa");
@Command([ViewCollapseAll]);
@Command([ViewExpand]);
REM {This code opens the first category @Command([NavNext]); @Command([ViewExpand]); };
@Command([ToolsRunMacro];"(F9)")

That's it - no other form events.

There is one hotspot on the form (attempting to do the 'run code on multiple docs in an embedded view Nathan F. hack *) and one text field with no formulas.

Form is set to launch into a specific frameset frmsetSingleCat which contains frameTop.
Form is set to autorefresh.

What's interesting is that the code is actually executing in the frame. If I open the frame, I can see the right category expand and everything else collapse.
In fact, if I put the doc into edit mode, the embedded view expands completely. When I look at the 'hidden' frame, the categories are still properly collapsed/partially expanded. If I open them all up and run some hotspot code that is the same as the postopen code, they collapse up perfectly but the embedded view does nothing.

I'm running 6.5.4. if that makes a difference.

This isn't a huge deal for me (right now), I'm just trying to understand how to make this work so I can use it if needed.

Later.

Doug

* and that code is:
@SetTargetFrame("frameTop");
@Command([OpenView];"vwEmbeddedSingleCat");
@Command([ToolsRunMacro];"(UpdateTestField2)")

Chris Blatnick said...

A sample database will be going up later today...please keep an eye out for that. Cheers...Chris

Stefanie said...

Thanks for the demo Chris! Great job.

I'm still having a problem with the single category view example. I would like to be able to choose the first category via a field and have the 2nd category also be categorized but collapsed. Is this possible? It looks as though it is from the images in your original post...

I haven't been able to get this working by changing the sample db you provided either. All feedback and suggestions would be greatly appreciated. Many thanks!

PlugIn said...

For some reason this is not working in Lotus Notes 8 Beta 2. Hopefully this is only an issue with Beta. Just to let you know...

Chris Blatnick said...

@Stefanie: I'll look at my sample db and see if I can duplicate your problem. Also, feel free to send me a copy of your database (stripped down or whole) and I'll take a look if you'd like.

Richard said...

I'd like to know, how to collapse the 2 other embedded views (in a tabbed table like yours in the example => Financial, Forecast Accuracy) ?

Anonymous said...

Hello Everyone, wanted to know if there is a demo file on this topic?
Thanks.

Melissa said...

Just found this post - just what I was looking for! However needed to adjust it slightly as my requirement was that my embedded view then had 2 levels of sub-categories under the top category that the "show single category" was working on. What I wanted was the first 'sub' category (which looks like the first category to the user) to be open to the next level. My view had total columns so this means that the user gets a neat summary without having to manually close up all the sub-sub categories. Example: embedded view with top category : name (used in show single category based on @username), sub-cat 1: Sales Area, Sub-cat 2: Product category. Column showing value sold totalling at categories. The following code opens the embedded view so that the first sales area category is expanded to show the product categories collapsed underneath shwoing their totals...

REM {This code is the way in which we get the embedded view to only open at the first category };
REM {First, set the target to the hidden frame...this is where all the action happens};
@SetTargetFrame("temp");

REM {The first line opens the view to the value we are using in the Show Single Category option};
@Command([OpenView];"(Homepage \\ Utilisation)"; Name);
@Command([ViewCollapseAll]);
@Command([ViewExpand]);
@Command( [NavNext]);
@Command([ViewExpand]);

REM {This is a call to an agent which doesn't really do anything. I have no idea why this is here really, but this technique doesn't work without it. This agent contains just a single line of code...@Success};
@Command([ToolsRunMacro];"(f9)")

Thanks!

melissa.snell@lan2lan.com

Nico said...

Chris ,

This article is really
but i have a challenge ...

I try to make it working for an embedded calendar without any success ?

My need is to jump to a date using @command([CalendarGoto]; Date) in the embedded view using an hotspot.

Help will be much appreciated ..
nicolas

Svetlana Sokolova said...

Hello, Chris.
Thank you for this example. But... How can I collapse view, what is embedded from other DataBase?

P.S. Sorry for my English

Nickolay Golomysov said...

Did anyone get it solved in Notes 8 ? I'm using 8.0.1 and it seems not working :(

Nickolay Golomysov said...

While this solution doesn't work under Notes 8, I tried emulation of keyboard pressing. I.e. to collapse view go to the top (Ctrl+Home) then collapse (-) and move down for each top-level category.

I used
Declare Sub keybd_event Lib "user32.dll" (Byval bVk As Integer, Byval bScan As Integer, Byval dwFlags As Integer,Byval dwExtraInfo As Integer)

Of course, this works only for Windows.

Anonymous said...

Instead of agent a subform could be used.
1) Create subform with postopen event with code:
dim ws as new notesuiworkspace
call ws.viewrefresh
2) Insert subform in Your form, where embedded view resides
Event hronology:
1) Primary form post event executes with formula
2) Then executes post open event in subform, which refreshes/rerenders form views