I have about 20 div's in an aspx page. At any time, only one of them will be visible. I need to decide which div to show depending on the Query String.
http://...?mode=<ModeName>
The easy way would be to start with all div's invisible, then just put the QueryString in switch and write out cases for all the possible ModeNames (or get it in a big if-else structure)
I dont really like hard coding things because if in future if I add/remove any div then I need to "remember" to do the necessary changes in the places that toggle divs.
I was thinking of creating an enum with all names and passing that enum to the function so I can iterate through all enums and set visibility accordingly. This way I only need to add the div name in the top enum declaration. But it did not quite work out that way (probably I'm too fiddly to get it to work)
Is Switch block my only way out of this? Does anyone have a better way to do this?
Thanks in advance!
I would do some or all of the following:
Define the various modes of your window in an enumeration (public enum ModeNames {View, Edit, Create, Summary ...}). Make this enumeration generic but descriptive.
Expose a property DisplayMode that parses the QueryString into the enum value. You should have control of the ModeNames added to the QueryString, but since it is the query string and thus the client can type in whatever they like, I'd put in some error-checking that will show a "default" view mode if the QueryString is not one of the expected values.
Give the divs a runat=server and an ID attribute (I'm guessing you already have since you want to do this in C# and not JavaScript), and in your Page_PreRender handler, set the Visible property of each div (referenced by its ID as an object) to an expression evaluating whether the current DisplayMode is one of the modes in which this div should be visible (e.g. thisDiv.Visible = new[]{ModeNames.Create, ModeNames.Edit}.Contains(DisplayMode)).
Alternately, instead of the second step, you can do this in the markup, either by specifying the Visible property of the div (as a server-side object) using a similar inline expression evaluating DisplayMode, or by including an OnLoad JavaScript handler for the div (which no longer has to be server-side) that sets the visibility using the DOM, based on the same inline C# expression.
I suggest to set a relation between the data passed at querystring and the names(and ids) of the divs you want to handle.
The rest you should know, use an scriptmanager to execute Javascript code to hide/show proper divs depending of what you read from querystring,
Hope that helps,
Related
I'm trying to build a very specific search page for a project and I'm having lot of trouble dealing with multiple postbacks invoked by dynamically-generated controls on a single page.
The page has to work like this:
There is a single checkbox, "Detailed search", that causes a postback on checking/unchecking.
When detailed search is not active, a simple grid with contents and buttons is displayed. Nothing special.
When detailed search is active, N checkboxes must be generated from some dynamic data, that represent the sections where you want the search to happen. Below the checkboxes, an AJAX-enabled tab control will appear, initially with no tab pages.
When checking one of the section checkboxes, a postback will occur. After the postback, data will be searched in the section selected by the user, then a new tab page containing a grid view of results and the name of the section will be added to the tab control. If the checkbox is unchecked, the tab page will disappear from the control, again, after a postback.
Now, the issue is that pretty much everything has to be generated dynamically, and that pretty much everything is connected to something else.
First issue: dealing with the "Detailed search" checkbox. Sounds easy, doesn't it? My initial idea was to set Page.Viewstate["DetailedSearchEnabled"] to true or false during the check/uncheck event handler, then create controls dynamically checking the value of DetailedSearchEnabled during Page_Load.
Nope. The postback event-handling happens between Page_Load and Page_LoadComplete. It would take an additional refresh for things to work as intended.
<< Then I'll just generate the controls on Page_LoadComplete! >>
Nope. Those controls need event handling as well, and if they're generated after Page_Load they will not be wired up correctly.
A possible solution would be generating everything in advance, on Page_Load, and only hiding/showing controls on Page_LoadComplete. But that is inefficient, and one important point of this search page is that only the minimum amount of controls should be generated.
The difficulty of this task seems to come from the way event wiring and the page life cycle work.
Surely there must be a better way of approaching this problem.
First issue: dealing with the "Detailed search" check box.
The correct approach (if you want to use page post-backs) is as follows:
In the CheckChanged event handler, save the value of the Checked property to ViewState["DetailedSearchEnabled"]. If the value is true, add the dynamic check boxes to the page. If the value is false, find and remove them.
Override LoadViewState. After calling base.LoadViewState, re-create the dynamic check boxes and wire up their events if ViewState["DetailedSearchEnabled"] is true. Note that neither Page_Load nor Page_LoadComplete is the appropriate place to do this.
Yes, you should create the dynamic check boxes at two points in the page life cycle. I recommend a helper method.
In general, your event handlers should add or remove just the dynamic controls (if any) affected by those particular events, but LoadViewState should re-create all dynamic controls that existed from the previous page request. You must store enough information in view state for LoadViewState to do so.
My answer to this other question demonstrates how to add and remove dynamic controls. You may want to use it as a reference.
Sounds to me like you should be using a CheckBoxList control to handle your dynamic checkboxes. You can add an remove items to the CheckBoxList during your post back and not have to worry about dynamically adding/removing actual controls/events to the form.
Here is a link to the msdn:
https://msdn.microsoft.com/en-us/library/14atsyf5(v=vs.85).aspx
Here is some sample code:
Protected void Button1_Click (object sender, System.EventArgs e)
{
CheckBoxList.Items.Add(new ListItem("TextValue1", "Value1"));
CheckBoxList.Items.Add(new ListItem("TextValue2", "Value2"));
}
If all else fails, you could still fall back on the quick-and-dirty old-fashioned ASP way.
Use Response.Write or <%...%> to generate your dynamic controls as plain old HTML (simple form fields, e.g. <input type="checkbox" name="foo" value="1" />).
Make sure you have a form field for every piece of information you may need after the postback(s). If necessary, use hidden form fields to 're-post' values across subsequent postbacks.
After postback, retrieve the values of the controls with the Request object.
Use those values to adjust the generation of controls as you see fit.
You should be able to do all of this in Page_Load. The advantage is total freedom. The disadvantage is total freedom to make a big mess of your aspx. So you may want to migrate all this dirty code out of your aspx, and into a custom-made control, which you can then add to your aspx.
When generating your own HTML, be careful not to introduce XSS vulnerabilities. Use HtmlEncode where necessary.
As you suggested yourself, there is a better way to tackle it.
If I was in the same situation, I would create web methods for interacting with the page, and use client side to do the UI. I'm currently working mostly with angular JS, although it does come with a learning curve. You could use ng-hide/ng-show to bind to the checkbox event to display the detailed search. When the n number of checkboxes needs to be displayed, you can then just fill them in with ng-repeat, for each of the items you need to display, after a check/uncheck you can dynamically populate new controls etc. through web method calls if extra data is needed.
Pure ASP postbacks are quite clunky from my experience, and not really suited for building a maintainable dynamic UI.
Instead of making so many postbacks, it would be better to use jquery and ajax calls to load the controls as needed and then attach events to it or you can even use UpdatePnael for that. Help Links:
https://www.simple-talk.com/dotnet/asp.net/ajax-basics-with-jquery-in-asp.net/
http://encosia.com/using-jquery-to-directly-call-aspnet-ajax-page-methods/
How can I get my CheckBoxList to have three possible states ? More precisely, is there a way to have three possible states for each checkbox : checked, unchecked, undefined (in most GUIs this is represented as a full square).
Alternatively, do you recommend another control that would meet these needs ?
UPDATE : Ok, given that HTML does not support tri-state checkboxes, I'm looking for a way to 'CSS' (color fill, highlight, etc...) the checkboxes of the items that are in that 'undefined' state from my server point of view.
Not all GUIs represent undefined as a full square. That's why it's going to be clearer to use one of the following:
1. Radio boxes
2. Dropdown
3. ListBox
Any asp.net control you use will ultimately need to be rendered as an html checkbox, which can only be checked or unchecked. You could use a data- attribute to keep track of extra state behind the scenes, but that wouldn't be reflected in the UI.
I suppose you could also implement a client-side solution using JavaScript and CSS as well.
You could just extend or derive from the CheckBoxList and create your own custom control from it.
Here is an example of this.
Custom CheckBoxList
I have decided to use CheckBoxList anyway, since I need two states accessible by the user, and a third one not accessible by the user but to display inconsistencies.
The way I have solved this is through Javascript + CSS. Some bits of ideas here: http://css-tricks.com/indeterminate-checkboxes/
My plan is to create a a two-pane page using ASP MVC 3. The left pane should be a small filter pane and the right the main content, showing a list of objects (say products).
Initially all products will be shown since no filter is applied. When selecting "only red", only red products are shown in the list. When further selecting a price range, only products in that price range will be shown.
Functionally the plan is to implement the filtering pane as a treeview with checkboxes (to be able to drill down to more and more specific filtering options), graphically it will probably be enhanced in some way to improve usability.
What is the best way to implement the coupling between the filter pane and the main list? Everything should work server side, but should of course use javascript (jQuery) when possible for direct feedback.
The simplest way is probably to make it closely coupled solution, calling a specific Asp MVC action using a custom-built javascript (with fallback to a form post). Doable enough, sure, but how to make the solution reusable? Also it would be nice to not loose all filtering data when navigating forward and back, i suppose GET arguments is the only decent way to do that?
Are there any best practices, any guidelines or anything to base this on to make a nice modular structure for filtering.
Victor, I recently had to solved this same problem. I'm not promising it's the best way but it's pretty clear and should even work well in case JavaScript is disabled (who even does that anymore?).
Create a that calls the action with all the field-selectable search options like "only red".
To that same form, add empty, hidden value for the things not directly as fields (paging, sorting...)
Setup your form with the excellent and very easy to use JQuery.Forms (http://www.malsup.com/jquery/form/) to make you form submit via JQuery (all your form values will be passed as JSON on form submit).
Make your back/next/paging/sorting links pass their individual values via query (no-JS fallback) and use JQuery to capture their click events. The JQuery click events on those links should assign the value of the value passed by the link (page number, sort column name...) to the corresponding hidden field in the form and call submit (with thanks to Jquery.Forms will submit via AJAX).
When you configure JQuery.Forms, you can define a callback method. In the callback method take the result (the HTML returned by your action that should contained your filtered+sorted+paged result) and replace the document (or DIV if you used a partial action + view) with that.
The result is a JQuery solution that works when JS is off. You also have very minimal JS code to write other than wiring the event handlers.
I'm not sure if it will be helpful but in MVC 3 you have access to a property called IsAjax from the view so you can do specific things to server a slightly different view when called from AJAX.
Cheers
I think the question may seem a little weird, but here's the details.
The Goal : To retrieve a set of pairs (text, value) for various reasons. one example for that of them is retrieving the alphabet, each letter will be used as an anchor or a LinkButton, the text value will be the letter and the click event will take the value part of the pair and place it in a stringFormat() to form a "Parametrized URL"
I've used two approaches for this goal but I don't know which is better!
1. Using a Repeater
A repeater that will have a LinkButton in it's ItemTemplate and through this blocks and will set the text to the 'text' and using eval and the 'value' to create the QueryString.
2. Using StringBuilder
Create an instance of StringBuilder
Use a loop with a counter equal to the total pairs to be retrieved. and append a certain string format that will build a long string with all the needed anchors for navigation using some code like this
Links_strngBuilder.Append(string.Format("<a href='/data.aspx?page={0}'>{0}</a>", chrctr))
and finally convert the String Builder instance to a string and assign it to a label
Note: the chrctr text and value fields will be retrieved as you suggest [in each loop from the database] or [loaded in an array/arrayList/List<> to store the values and save all those connections to the db]
Where i work we will never use a stringbuild becouse of the designer. We dont want the designer in the codebehind if he has to make a simple change. so keep the markup in the view and codebehind in the codebehind.
Edit
Other advantage of repeater is the change of cycle is much easier. No need to recompile and perhaps redeploy the tweak the UI, just edit the ASPX template, save and refresh.
I don't know anything about how these two approaches perform (in terms of memory usage and speed) comparing to each other but I'd definitely go for Repeater because:
The code is much easier to understand & support
Using a StringBuilder reminds me the days of the classic ASP when the Response.Write was used widely.
You can't use any of the benefits of the Visual Designer with a StringBuilder.
-- Pavel
I think building the output fits more in client side(e.g. when you do an ajax call and want to show the results in html) than server side except when your build a custom server control.
In addition, if you use the repeater you have the extensibility option whenever requirements changed, and you have more control and facilities(like event handling and styling with css and so forth).
I have an Asp.Net repeater, which contains a textbox and a checkbox. I need to add client-side validation that verifies that when the checkbox is checked, the textbox can only accept a value of zero or blank.
I would like to use one or more of Asp.Net's validator controls to accomplish this, to provide a consistent display for client side errors (server-side errors are handled by another subsystem).
The Asp:CompareValidator doesn't seem to be flexible enough to perform this kind of complex comparison, so I'm left looking at the Asp:CustomValidator.
The problem I'm running into is that there doesn't seem to be any way to pass custom information into the validation function. This is an issue because the ClientIds of the checkbox and the textbox are unknown to me at runtime (as they're part of a Repeater).
So... My options seem to be:
Pass the textbox and checkbox to the CustomValidator somehow (doesn't seem to be possible).
Find the TextBox through JavaScript based on the arguments passed in by the CustomValidator. Is this even possible, what with the ClientId being ambiguous?
Forget validation entirely, and emit custom JavaScript (allowing me to pass both ClientIds to a custom function).
Any ideas on what might be a better way of implementing this?
I think the best way would be to inherit BaseValidator in a new class, and pass those IDs to your control as attributes. You should be able to resolve the IDs within your validator, without knowing the full client side ID that is generated at runtime. You should get the data validating on the server first, and on the client second.
Can you not put the CustomValidator inside the repeater? If not, you can create it dynamically when the repeater is bound and user FindControl()
protected MyDataBound(object sender, RepeaterItemEventArgs e) {
(CheckBox)cb = (CheckBox)e.Item.FindControl("myCheckboxName");
(TextBox)tb = (TextBox)e.Item.FindControl("myTextBox");
}
...or something like that. I did the code off the top of my head.