YUI Styled 'Tip of the Day' Dialog using the PopupControl, DynamicPopulate and DragPanel Extender Controls
The web application I am currently developing has a fair number of popup windows. Some are modal, some aren't. All open new browser windows and this annoys more than a few of our users (I hate popup's too, so I guess it shouldn't be that surprising). So as a team we are looking into replacing our popup windows with the ModalPopupExtender and PopupExtender AjaxControlToolkit controls. This is just fine by me - I have worked with the toolkit's popup controls on other projects and they worked quite well (It also saves me the pain of writing custom JavaScript for communicating between browser windows).
Live Demo (IE6, IE7, FF) | Download (Uses Toolkit Version 1.0.10920.0)
So as an R&D task, I created a page that implements a simple 'Tip of the Day' popup control. The functionality is basic - you click a button and the Tip of the Day panel is displayed. Once displayed, you can click that 'Next Tip' button to fetch the next tip and display it to the user. While the next tip is being retrieved, I fade out the text and display an animated gif in the center of the panel. Here is a quick screen shot of what the panel looks like while the next tip is being fetched.
I styled the control based on the YUI Panel control. It includes the following features:
- You can move the panel by clicking and dragging on the 'Tip of the Day' header
- Clicking the 'Next Tip' button will dynamically update the Tip text by using the AjaxControlToolkit's DyanmicPopulateExtender control
- A progress indicator is rendered over the Panel while the contents is being updated
- A shaded border is applied to the panel (IE7 only)
I am still working on these additional features as well
- Resizing with the ResizableControl
- Replacing the shadow with the DropShadow
Here is the markup for what I have done so far. Inside the pnlPopup, I have 2 div's, one (class=overlay) for the contents and the other (class=underlay) for the shadow around the border. Within the overlay div I have the a panel for the header text and close button, a panel for the body and another div for the footer contents (the Next Tip and Close buttons). Each of these elements has a CssClass defined where I am specifying the background-image along with the other style rules.
<%// The panel that is popped %> <asp:Panel ID="pnlPopup" runat="server" CssClass="frame" style="display:none"> <div class="overlay"> <asp:Panel ID="pnlHeader" runat="server" CssClass="header"> <asp:Label runat="server" CssClass="msg" Text="Tip of the Day" /> <asp:LinkButton runat="server" CssClass="close" OnClientClick="$find('popup').hidePopup(); return false;" /> </asp:Panel> <asp:Panel ID="pnlBody" runat="server" CssClass="body"> <%= NextTip() %> </asp:Panel> <div class="footer"> <asp:Button ID="btnNextTip" runat="server" Text="Next Tip" OnClientClick="return false;" /> <asp:Button runat="server" Text="Close" OnClientClick="$find('popup').hidePopup(); return false;" /> </div> </div> <div class="underlay"></div> </asp:Panel>
Next, I added 3 toolkit extender controls that supplied some additional behavior. I included the PopupControlExtender to handle displaying and positioning the pnlPopup control. The DynamicPopulateExtender for interfacing with a PageMethod that I created to return the next Tip of the Day. And finally, I added a DragPanelExtender so the user can drag the panel around the page. The DyanmicPopulateExtender is the most interesting of the controls. This control allows you to replace the contents of a control with the string result of a web service or page method ...
So for my Tip of the Day sample, I configure the control to populate the invoke the NextTip PageMethod when the user clicks the btnNextTip button. While this call is be made, the DynamicPopulateExtender applies the updating css class to the pnlBody HTML element and removes it after the call completes. Below is the markup for the DyanmicPopulateControl as well as the other two controls.
<%// The extender that displays and positions the panel %> <ajaxToolkit:PopupControlExtender runat="server" BehaviorID="popup" TargetControlID="btnPopup" Position="Right" PopupControlID="pnlPopup" /> <%// The extender that populates the tip %> <ajaxToolkit:DynamicPopulateExtender runat="server" ClearContentsDuringUpdate="false" PopulateTriggerControlID="btnNextTip" TargetControlID="pnlBody" UpdatingCssClass="updating" ServiceMethod="NextTip" /> <%// The extender that provides drag and drop behavior %> <ajaxToolkit:DragPanelExtender runat="server" DragHandleID="pnlHeader" TargetControlID="pnlPopup" />
Using PageMethod's requires you to add the ScriptMethod and WebMethod attributes to your PageMethod's signature. Here is what my 'NextTip' method looks like. If you are using PageMethods, make sure you mark the method static (I noticed the documentation here is missing this)
As far as implementation details, that's about it. I will say that building this sample took longer than I had initially estimated. Here are a couple of the gotcha's I encountered along the way ...
1. In IE (works fine in FF), the DragPanelExtender display's the 'Copy' and not the 'Move' icon. I half way corrected this (and the DragPanelExtender page does this too) by setting the cursor style on my header element to move.
2. You should be aware that the DynamicPopulateExtender replaces the existing class with the one you specify using the UpdatingCssClass. So it might make sense to apply the same style to both like I have done here. And also define the custom updating style separately.
3. When I was creating this sample, I didn't have much content on my page and the div that contained all of the content was only a few pixels high by a few pixels wide. When trying to drag and drop I kept getting this weird behavior where I would drag the panel and sometimes it would move fine and other times it would revert back to the ordinal location. It turns out the DragDrop script cancels the move if there is not drop target (element to drop onto). You can checked this out here. Try moving the panel outside of the blue box ...
4. There are a handful of slight differences between the ModalPopupExtender and the PopupExtender. The one that got me right away was the minor difference of client side API's for showing and hiding (modalPopup.show() and modalPopup.hide() versus popup.showPopup() and popup.hidePopup()).
That's it. Enjoy!
Comments
Everytime i see a new feed on your blog I get excited. Your topics and attention to detail is perfect! Great Job Matt! Keep the yui stuff coming.
hey matt, it is me again, from brazil.
another cool sample, great job!
i'm get addicted to your blog!
thanks a lot, matt!
Hi Matt:
Your blog is very impressive. You bring about very nice articles on AJAX. Keep up the good job
Regards,
Swami
Great site with working examples and full explanation has helped a lot.
Keep looking on your blog daily for new ajax examples.....wondering if will ever see a gridview inside a modal window.
cheers and keep up the good work, I'm trying to remember how i came across your examples in the first place!!! And how do you get the time to do this.
Richard
As always GOOD stuff.
Thanks Matt, v useful
Another great post as usual. Quck question though - does it bother anyone else that doing something like this with asp.net ajax and the control toolkit requires such a large (KB) of js? I mean your example requires 149KB of javascript alone and 13 different JS files.
Howdy, nice blog though I wonder if you've tested the library of my employer?
http://ajaxwidgets.com
An alternative to ASP.NET AJAX who's USP is exactly that developers don't need to write custom JavaScript themselves.
BTW (to Richard) we have a working example of a DataGrid inside a Window, to make it modal is just a switch on one of the properties of the Gaia Ajax Window object.
Thomas
Hi Matt,,
After surfing this blog everyday for 3 days now,, its really amazing the job you are doing, and the articles samples are greate !!!
thanks for your effort ..
dose it for jsp??
Hey Matt! Great Blog! I had a difficult time getting the ajax ModalPopupExtender to play nice with this panel.
I added a ModalPopupExtender with this set as the style:
.modalBackground {
background-color:Gray;
filter:alpha(opacity=70); opacity:0.7;}
Sorry, please disregard my last post. I was able to use one of your other examples to get a working modal. THANKS!!!
Hi Matt,
Your articles are very useful for me. Thank you very much
When I run you sample (from your site), and resize the browser to be much narrower, the help tip correctly repositions to the left some so as to show up on the page. However, when I download and run this code on my box, it is always 'fixed' to the right of the button. Any idea why my dynamic positioning isn't working?
This is one of the best article i have read on using the AJAX Control Toolkit. It has changed the way i see toolkit and its uses. I was using the ajax roadmap webpage for communicating to webservices. This article changed everything. Thank you ever so much.
Rain Man ALex
Sweet. I used the PopupControlExtender and the DynamicPopulateExtender on the same panel. I already had the PopupControlExtender working using the DynamicServiceMethod property, but there is no UpdatingCssClass property for the PopupControlExtender!!! Why is this? What am I missing? So, I used the DynamicPopulateExtender simply for the UpdatingCssClass property.
Thanks for your blog. It helped me out...Troy