How can I hide/unhide a form? - javascript

I'm playing around with jquery and made a form that submits information without a page refresh but in the tutorial I followed it must first display a form for people to edit but what I want to do is slightly different.
I want to display a users profile page and then have a little edit link beside each item which causes a text field to appear if they click edit. I believe I can submit the form without a refresh but how can I have a form appear when the 'edit' button is clicked without refreshing?
Any idea of how I can accomplish this or even better what should I be searching to learn how to do this? I went through the sample items on jquery site and none of them seemed to hide/unhide by clicking.

Here is a quick example of how I'd handle the concept, I'd follow it up with posting and validation and all else a little server-side scripting etc, but this can act as your stepping stone overall. Pretty much all you got to remember is javascript/jquery is all smoke and mirrors since its all handled client-side you essentially need to work with what you have on screen be it hidden or otherwise.
In this case you have 2 elements one showing by default while the other hides, you make a logic that hides one over the other when one is chosen, and do what you need to respectively with either.
<div id="wrapper">
<div id="container">
<div id="storedvalue"><span>Hello</span> [edit]</div>
<div id="altervalue" style="display:none;"><input type="text" name="changevalue" id="changevalue" value="Hello"> [save]</div>
</div>
</div>
<script type="text/javascript">
$('#editvalue').click(function(e){$('#storedvalue').hide();$('#altervalue').show();});
$('#savevalue').click(function(e){
var showNew = $('#changevalue').val();
$('#altervalue').hide();
$('#storedvalue').show();
$('#storedvalue span').text(showNew);
});
</script>
DEMO

A HTML form cannot be submitted without refreshing the page. However, JavaScript (and by extension, jQuery) can be used to submit similar GET or POST requests. You can also use jQuery's .append method to insert the necessary markup to create inputs on-the-fly. jQuery can also be used to access the values that have been inputted to the field (usually done by id).
Something I am working on simmilar to what you need:
(this particular code takes some input from a visible form, and aggregates it into an invisible one for later use)
jQuery('#submitButton').click(function(){
jQuery('#prev_request').append('<input type="hidden" name="sort_order" value="'+jQuery("input[#name=sort_order]:checked").val()+'" />');
jQuery('#prev_request').append('<input type="hidden" name="sort_by" value="'+ jQuery("#sort_by option:selected").val() +'" />');
});

I think the simplest thing to do would be something like this:
HTML
<form id="form1" style="display: none;">
</form>
<a id="editButton" href="javascript:void(0)">Edit</a>
<a id="closeButton" href="javascript:void(0)" style="display: none;">Close</a>
JavaScript (be sure to include jQuery on your page)
$(function() {
$("#editButton").click(function() {
$("#form1").show();
$("#editButton").hide();
$("#closeButton").show();
});
$("#closeButton").click(function() {
$("#form1").hide();
$("#editButton").show();
$("#closeButton").hide();
});
});
It's also easy to add an expanding transition effect with the show() and hide() methods. Simply pass the desired transition duration to the function (in milliseconds) like this:
$("#form1").show(500);

Lostsoul,
I would utilize an asp DataGrid inside of an UpdatePanel control:
.ascx:
<asp:UpdatePanel ID="yourUPpanel" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:DataGrid ID="yourDG" runat="server" AutoGenerateColumns="False" CellPadding="2" AllowSorting="False" AllowPaging="False" EnableViewState="false" onItemCommand="yourDG_CellClick">
<FooterStyle CssClass="cssFooter"></FooterStyle>
<AlternatingItemStyle CssClass="CssAltItem"></AlternatingItemStyle>
<ItemStyle CssClass="cssGridItem"></ItemStyle>
<HeaderStyle CssClass="GridHeader"></HeaderStyle>
</asp:DataGrid>
<asp:Panel ID="yourAdditionalStuff" runat="server" Visible="false">
<table>
<tr>
<td>
<asp:TextBox ID="yourTXT" runat="server" Width="100px"/>
</td>
</tr>
</table>
</asp:Panel>
</ContentTemplate>
</asp:UpdatePanel>
.vb
Public Sub yourUPpanel_Load(ByVal sender As Object, ByVal e As EventArgs) Handles yourUPpanel.Load
If cnADO Is Nothing Then blahblah.getConnection("yourserver", cnADO) 'whatever the case may be here
Try
Dim da As SqlDataAdapter
Dim cmd3 As New SqlCommand
cmd3.Connection = cnADO
cmd3.CommandType = CommandType.StoredProcedure
cmd3.CommandText = "SP to populate GRID" 'whatever the case may be here
daPeople = New SqlClient.SqlDataAdapter
daPeople.SelectCommand = cmd3
If yourDG.Columns.Count <= 0 Then
Dim btnc As New ButtonColumn
btnc.ButtonType = ButtonColumnType.LinkButton
btnc.HeaderText = "Edit"
btnc.DataTextField = "primarykey"
btnc.DataTextFormatString = "<img border='0' src=" & ResolveUrl("~/images/edit.gif") & ">" 'whatever the case may be here
btnc.CommandName = "Edit"
btnc.ItemStyle.HorizontalAlign = HorizontalAlign.Center
yourDG.Columns.Add(btnc)
Dim bc As New BoundColumn
bc = New BoundColumn
bc.DataField = "sqlColumnName"
bc.HeaderText = "First"
yourDG.Columns.Add(bc)
End If
Dim dt As New DataTable
yourDG.Fill(dt)
yourDG.DataSource = dt
yourDG.DataBind()
'lbtnEditAddPerson.Visible = True
Catch ex As Exception
Finally
If Not cnADO Is Nothing Then
If cnADO.State = ConnectionState.Open Then
cnADO.Close()
End If
End If
End Try
End Sub
Protected Sub yourDG_CellClick(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs)
Dim cmd As String = e.CommandName.ToString.ToUpper
If cmd.ToUpper = "EDIT" Then
Using cnADO As SqlConnection = New SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings("yourserver").ToString) 'whatever the case may be here
Using scmd As New SqlCommand("", cnADO)
scmd.CommandText = "YOURTEXTHERE"
Using dr As SqlDataReader = scmd.ExecuteReader()
If dr.Read Then
'fill textbox for load
End If
End Using
End Using
End Using
yourAdditionalStuff.Visible = True
ElseIf cmd.ToUpper = "ANOTHERCOMMAND" Then 'if you want to...allows for extensibility (would need another column tho)
End If
End Sub
Note that this is a framework, but should be very close to what you need (or at least give you things to search on). I've actually used this approach, so I can confirm that it does work. If you aren't using a database (i.e. if you won't need to save/load what the user puts in your appearing textbox) then it should simplify down. This should get you Googling though. Hope it helps!
-sf
EDIT: Per Chris' comment, I think:
function hideOnClick(){
var d = document.getElementById('<% =yourtextbox.ClientID %>');
if(d.style.display == "none"){
d.style.display = "inline";
}else{
d.style.display = "none";
}
}
might help you if all you need is the client-side javascript to toggle show/hide. All you'd need to do is attach it to your edit button.

Related

asp:GridView allow Edit button, but remove Update and Cancel buttons

This one is pretty straightforward. The asp:GridView automatically adds an Edit hyperlink to the left of every column like this:
which is fine because I need that functionality anyways. However, I've made it so clicking the Edit hyperlink brings up a new panel that allows the user to edit more properties than are shown in the GridView, so I don't want the Update and Cancel buttons to appear after clicking Edit.
Ive added the Edit functionality by implementing an event handler that Handles GridView.RowCommand when e.CommandName = "Edit". I would like to just keep the Edit hyperlink there, or maybe programatically click Cancel, or really anything that will keep the Update and Cancel hyperlinks from showing when the user finishes working with the Edit panel. I've tried calling the event handler and sending in args with e.CommandName = "Cancel" but that didn't work.
Another option I'm willing to explore is removing the Edit button entirely and making my event handler handle a different event, but I haven't found any good resources for that either. Mostly it's people trying to disable an Edit button that they've manually created on certain rows. I didn't create this Edit hyperlink, though, and I can't get it to go away.
Well, since you popping up a panel? Then just dump the whole template and auto editing system. Really, for quick and dirty - those built in GV events are great to get you up and running.
But, it turns out once you REALLY get the hang of how all this works? You can just pure code your way though this, and you even wind up with LESS code and LESS markup, and less hassle!!!
In fact, you can even dump the whole GV "row" handler - as it does not really again do you much of any favors here.
in fact, even better? Just drop in a plane jane edit button - even a asp.net one. You don't really need anything much more! - and you wind up often with even LESS confusing code. And REALLY great? Well, each button you add to the GV has its own click event - is it own nice button click with its own button click - quite much like any other control or button you just drop into the GV.
In fact, if the queston was how to tab around and edit the gv like Excel, I can post a really short, easy solution, and NONE of it uses the built in events of the GV.
but, lets outline how this can work, and work with a "min" of code.
You don't mention what kind of "dialog" you using here (and there are lot of them, ranging from jquery.UI (which I will use), or even the dialog from the ajaxtoolkit is also very nice.
So, I will say I do NOT like to suggest introduction of "just one more" JavaScript library. However, almost for sure, you have jQuery installed by default. So, adding jquery.UI is not all that big of deal.
So, our goals:
Dump the messy GV event model.
STILL use + write as much as possible easy server side code.
Write and use a absolute min of JavaScript code.
Now, I am going to use a few helper routines I wrote in vb.net. They are short, and easy to use. I became VERY fast tired of writing the same code over and over to:
Shuffle data from data table to some controls for edit
Shuffle data from controls back to table, and then save table to database.
However, even without the above "shuffle to/from" routines, you see that this code is MUCH less hassle by actually dumping the GV events.
Ok, So, lets assume a simple grid of hotels. And on each row, we want a edit button.
So, the first easy part, here is our grid:
<div style="width:40%">
<asp:GridView ID="GHotels" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID" CssClass="table">
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:TemplateField HeaderText="Edit">
<ItemTemplate>
<asp:Button ID="cmdEdit" runat="server" Text="Edit" CssClass="btn" OnClick="cmdEdit_Click" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
A few FYI: Yes, to save time, I did use the wizards to create above. I then blow out the datasource1, and data source setting of the gv. and I removed the "ID" from display for each row. NOTE VERY careful - the PK row "id" setting is now this:
DataKeyNames="ID"
This is great feature, since it will maintain, use, and allow you to easy get the PK row id, but NOT have to expose it in the markup - less code, better to never show the PK stuff to users.
And note how I set CssClass="table". Don't worry about that, but doing so will bootstrap the GV - and it looks WAY WAY nicer. (and it also auto expands/grows to the div width size - do try this - since bootstrap is installed by default).
And now our code is this:
(don't worry - I'll include all code used here).
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadGrid
End If
End Sub
Sub LoadGrid()
Dim cmdSQL As New SqlCommand("SELECT * FROM tblHotelsA ORDER BY HotelName")
GHotels.DataSource = MyrstP(cmdSQL)
GHotels.DataBind()
End Sub
and now we have this:
So far, really easy.
Now, it not clear what you used for editing (your popup), but we need "some kind" of popup system. So, I'll pick jquery.UI. It work rather well - far better then trying to get a bootstrap dialog to work.
So, after the GV, we need to layout + make a "one row" editor. (and place it in a div). so, this looks quite nice for this purpose: (and during development, I do NOT set display:none, but once you have it looking ok, then set display:none for the div style - that hides it (jquery.ui then takes care of this).
Ok, not too much to our "edit detals div". I dropped htis right after the GV.
So, we have this:
<div id="EditRecord" runat="server" style="float:left;display: none">
<style>
.iForm label {display:inline-block;width:90px}
.iForm input {border-radius:8px;border-width:1px;margin-bottom:10px}
.iForm textarea {border-radius:8px;border-width:1px;margin-bottom:10px}
.iForm input[type=checkbox] {margin-right:8px}
</style>
<div style="float:left" class="iForm">
<label>HotelName</label><asp:TextBox ID="txtHotel" runat="server" f="HOtelName" width="280"></asp:TextBox> <br />
<label>First Name</label><asp:TextBox ID="tFN" runat="server" f="FirstName" Width="140"></asp:TextBox> <br />
<label>Last Name</label><asp:TextBox ID="tLN" runat="server" f="LastName" Width="140"></asp:TextBox> <br />
<label>City</label><asp:TextBox ID="tCity" runat="server" f="City" Width="140"></asp:TextBox> <br />
<label>Province</label><asp:TextBox ID="tProvince" runat="server" f="Province" Width="75"></asp:TextBox> <br />
</div>
<div style="float:left;margin-left:20px" class="iForm">
<label>Description</label> <br />
<asp:TextBox ID="txtNotes" runat="server" Width="400" TextMode="MultiLine"
Height="150px" f="Description" ></asp:TextBox> <br />
<asp:CheckBox ID="chkActive" f="Active" Text=" Active" runat="server" TextAlign="Right" />
<asp:CheckBox ID="chkBalcony" f="Balcony" Text=" Has Balcony" runat="server" TextAlign="Right" />
</div>
<div style="clear:both"></div>
<button id="cmdSave" runat="server" class="btn" onserverclick="cmdSave_ServerClick" >
<span aria-hidden="true" class="glyphicon glyphicon-floppy-saved"> Save</span>
</button>
<button id="cmdCancel" runat="server" class="btn" style="margin-left:15px">
<span aria-hidden="true" class="glyphicon glyphicon-arrow-left"> Back/Cancel</span>
</button>
<button id="cmdDelete" runat="server" class="btn" style="margin-left:15px">
<span aria-hidden="true" class="glyphicon glyphicon-trash"> Delete</span>
</button>
</div>
And now our ONE bit of JavaScript - but this is ALL we have to write:
Drop this right after the above div:
<script>
function PopEdit() {
var myDialog = $("#EditRecord");
myDialog.dialog({
title: "Edit Hotel Information",
modal: true,
width: 860,
appendTo: "form"
});
}
</script>
Ok, that is quite much it.
Now, we have that row button click. As noted, this is just a plane jane asp.net button, or whatever you like.
That button in the GV was this:
<asp:TemplateField HeaderText="Edit">
<ItemTemplate>
<asp:Button ID="cmdEdit" runat="server" Text="Edit" CssClass="btn" OnClick="cmdEdit_Click" />
</ItemTemplate>
</asp:TemplateField>
And the code for this button:
Protected Sub cmdEdit_Click(sender As Object, e As EventArgs)
Dim btn As Button = sender
Dim gRow As GridViewRow = btn.NamingContainer
Dim pkID = GHotels.DataKeys(gRow.RowIndex).Item("ID")
Dim cmdSQL As New SqlCommand("SELECT * from tblHotelsA where ID = #ID")
cmdSQL.Parameters.Add("#ID", SqlDbType.Int).Value = pkID
Dim rstData As DataTable = MyrstP(cmdSQL)
Call fLoader(Me.EditRecord, rstData.Rows(0))
ViewState("rstData") = rstData
ClientScript.RegisterStartupScript(Page.GetType(), "PopEditKey", "PopEdit()", True)
End Sub
Not a lot of code. We simple load up our "div", and then pop it with that one lone jquery.UI bit of code.
And the result is Now this:
Ok, so now we need the save button code. That is this:
Protected Sub cmdSave_ServerClick(sender As Object, e As EventArgs)
Dim rstData As DataTable = ViewState("rstData")
Call fWriterW(EditRecord, rstData.Rows(0))
Call SaveTable(rstData, "tblHotelsA")
LoadGrid()
End Sub
And the cancel/back button? Well as we know ANY post-back will collopse the dialog, so it actually does not need much code. And if you wish, I can post the code for the delete button (and we probably should provide a nice looking "confirm" delete prompt - and we can use a jQuery.Ui dialog for that - but again, use 90% server side clean vb code for the delete button.
Ok, so now the helper routines I used for above.
I have 3
MyRstP - this just accepts a sql command - retruns a table.
Public Function MyrstP(sqlCmd As SqlCommand) As DataTable
Dim rstData As New DataTable
Using sqlCmd
Using conn = New SqlConnection(My.Settings.TEST4)
conn.Open()
sqlCmd.Connection = conn
rstData.Load(sqlCmd.ExecuteReader)
End Using
End Using
Return rstData
End Function
above just saves the hassle of "over and over" having to write query code.
Then we have a routine called "fLoader". Once again, it became OH so tiring to write code over and over that just takes a data row, and shoves it out to controls on the form. So, for each control in a "div", I just make up my own "tag". I use f="data base column name goes here"
So, inside of a given div, then you see this for hotel name:
<label>HotelName</label><asp:TextBox ID="txtHotel" runat="server" f="HotelName" width="280"></asp:TextBox> <br />
<label>First Name</label><asp:TextBox ID="tFN" runat="server" f="FirstName" Width="140"></asp:TextBox> <br />
So, for each control, I kind of cooked up my own binding - saves you have to write that code over and over.
So, floader looks like this (I just added a module1 to mycode). and thus all forms and routines can use this code. All it does is take the rstData (row(0), and move the database columns to the controls that have a tag f="column name". It is a bit of code, but after having written it, it sure makes shoving data out to controls rather easy.
Public Sub fLoader(F As HtmlGenericControl, rst As DataRow)
For Each c As System.Web.UI.Control In F.Controls
Select Case c.GetType
Case GetType(TextBox)
Dim ctlC As TextBox = c
If Not ctlC.Attributes("f") Is Nothing Then
If rst.Table.Columns.Contains(ctlC.Attributes("f")) Then
ctlC.Text = IIf(IsDBNull(rst(ctlC.Attributes("f"))), "", rst(ctlC.Attributes("f")))
End If
End If
Case GetType(Label)
Dim ctlC As Label = c
If Not ctlC.Attributes("f") Is Nothing Then
If rst.Table.Columns.Contains(ctlC.Attributes("f")) Then
ctlC.Text = IIf(IsDBNull(rst(ctlC.Attributes("f"))), "", rst(ctlC.Attributes("f")))
End If
End If
Case GetType(DropDownList)
Dim ctlC As DropDownList = c
If Not ctlC.Attributes("f") Is Nothing Then
If rst.Table.Columns.Contains(ctlC.Attributes("f")) Then
ctlC.Text = IIf(IsDBNull(rst(ctlC.Attributes("f"))), "", rst(ctlC.Attributes("f")))
End If
End If
Case GetType(CheckBox)
Dim ctlC As CheckBox = c
If Not ctlC.Attributes("f") Is Nothing Then
If rst.Table.Columns.Contains(ctlC.Attributes("f")) Then
ctlC.Checked = rst(ctlC.Attributes("f"))
End If
End If
Case GetType(RadioButtonList)
Dim ctlC As RadioButtonList = c
If Not ctlC.Attributes("f") Is Nothing Then
If rst.Table.Columns.Contains(ctlC.Attributes("f")) Then
ctlC.SelectedValue = rst(ctlC.Attributes("f"))
End If
End If
End Select
Next
End Sub
And then I have the reverse. Take from controls -> back into the rstData (data row, but from the datatable).
It really is the above code in "reverse" and takes values from controls and shoves then back into the rstData.
Public Sub fWriterW(f As HtmlGenericControl, rst As DataRow)
For Each c As System.Web.UI.Control In f.Controls
Select Case c.GetType
Case GetType(TextBox)
Dim ctlC As TextBox = c
If Not ctlC.Attributes("f") Is Nothing Then
If rst.Table.Columns.Contains(ctlC.Attributes("f")) Then
rst(ctlC.Attributes("f")) = IIf(ctlC.Text = "", DBNull.Value, ctlC.Text)
End If
End If
Case GetType(Label)
Dim ctlC As Label = c
If Not ctlC.Attributes("f") Is Nothing Then
If rst.Table.Columns.Contains(ctlC.Attributes("f")) Then
rst(ctlC.Attributes("f")) = IIf(ctlC.Text = "", DBNull.Value, ctlC.Text)
End If
End If
Case GetType(DropDownList)
Dim ctlC As DropDownList = c
If Not ctlC.Attributes("f") Is Nothing Then
If rst.Table.Columns.Contains(ctlC.Attributes("f")) Then
rst(ctlC.Attributes("f")) = IIf(ctlC.Text = "", DBNull.Value, ctlC.Text)
End If
End If
Case GetType(CheckBox)
Dim ctlC As CheckBox = c
If Not ctlC.Attributes("f") Is Nothing Then
If rst.Table.Columns.Contains(ctlC.Attributes("f")) Then
rst(ctlC.Attributes("f")) = ctlC.Checked
End If
End If
Case GetType(RadioButtonList)
Dim ctlC As RadioButtonList = c
If Not ctlC.Attributes("f") Is Nothing Then
If rst.Table.Columns.Contains(ctlC.Attributes("f")) Then
rst(ctlC.Attributes("f")) = ctlC.SelectedValue
End If
End If
End Select
Next
End Sub
and then one more routine - this routine just saves the database table BACK to the database. Hence you pass it the rstData, and table name.
Sub SaveTable(rstData As DataTable, strTable As String)
Using conn As New SqlConnection(My.Settings.TEST4)
Using cmdSQL As New SqlCommand("select * FROM " & strTable, conn)
Dim da As New SqlDataAdapter(cmdSQL)
Dim daU As New SqlCommandBuilder(da)
conn.Open()
da.Update(rstData)
End Using
End Using
End Sub
So, those little helper routines - I just place in a plane jane Module, and thus all my code can use it. It really nice since you really don't' mess with much sql, and NEVER have to mess with a boatload of parameters.
To be fair, I could have posted the ONE grid row button code. Note how it is a simple regular button - and does NOT use the GV events - but is a plane jane "click" event for server side code. And do look at the code close - note how it picks up the row clicked on, and also how it picked up the PK ID.

Figure out which HTML table rows in ASP Repeater are Hidden

I have a bootstrap modal that displays a list of titles with a delete button for each title. I created a little sketch to make it clear what I am talking about.
The table is created with a Repeater:
<asp:Repeater ID="rpRelated" runat="server" OnItemDataBound="rpRelated_ItemDataBound">
<HeaderTemplate>
<table class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th style="width: 20%">Title</th>
<th style="width: 10%">Delete</i></th>
</tr>
</thead>
</HeaderTemplate>
<ItemTemplate>
<tr runat="server" id="related">
<td>
<asp:HiddenField runat="server" ID="titleRelatedID" Value='<%# DataBinder.Eval(Container.DataItem , "ID")%>' />
<asp:TextBox runat="server" ID="relatedTitle" Text='<%# DataBinder.Eval(Container.DataItem , "Title")%>' CssClass="form-control" />
</td>
<td>
<a class="my-red-button" href='javascript:hideRelated(<%# DataBinder.Eval(Container.DataItem , "ID")%>);'>Delete</i></a>
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
I set the related <tr> ID in the Repeater's ItemDataBound method in order to make it dynamic so that I can tell which row to hide (Source of the Idea):
protected void rpRelated_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Title title = (Title)e.Item.DataItem;
var row = e.Item.FindControl("related");
row.ClientIDMode = ClientIDMode.Static;
row.ID = "related" + title.ID;
}
}
When one of the delete buttons (links) is pressed, the following JS function is called:
function hideRelated(num) {
document.getElementById('related' + num).style.display = 'none';
}
This function hides the row temporarily, yet doesn't actually delete the title.
I don't want any of the titles to actually get deleted until the SAVE button on the bottom is pressed. When the SAVE button is clicked, the following Click Event is called in the CodeBehind, and this is where I am getting stuck:
protected void btnSaveRelated_Click(object sender, EventArgs e)
{
foreach (RepeaterItem item in rpRelated.Items)
{
int ID = Convert.ToInt32(((HiddenField)item.FindControl("titleRelatedID")).Value);
var a = item.FindControl("related" + ID); //returns null
if (???title row is hidden???)
{
//code to actually delete the Title goes here
}
}
}
As I iterate through the Repeater Items, how can I figure out if the corresponding <tr> has the display:none attribute?
I tried accessing the item's row by doing item.FindControl("related" + ID);, yet this doesn't seem to work since it is always returning null (possibly because the ClientIDMode is Static). I though of using a HiddenField like I did with titleRelatedID, yet I couldn't figure out how to update the correct value in the JavaScript code when one of the buttons is clicked. I also though of possibly using Visible=false instead of display:none yet I couldn't either figure out how to work this method in JavaScript.
I would love to get my current method to work, yet I am open to completely different approaches to accomplish my task which is:
Hide a row when the row's delete button or link is clicked
When the save button is pressed, figure out which rows or IDs are missing so I know which Titles need to be deleted
One approach is to use another HiddenField control that tracks the IDs of deleted titles:
<!-- before/after (not inside) the Repeater -->
<asp:HiddenField runat="server" ID="deletedRelatedIDs" />
In the hideRelated JavaScript function, append the argument to the hidden field:
document.getElementById('deletedRelatedIDs').value += num + ' ';
In the btnSaveRelated_Click method, read the value of the hidden field:
foreach (string id in this.deletedRelatedIDs.Value.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries))
{
// Delete the title with this ID.
}
Security Note: The user can easily tamper with the contents of the hidden field. If necessary, the btnSaveRelated_Click method should validate that each ID is valid and that the user has permission to delete the title.
Q&A
As I iterate through the Repeater Items, how can I figure out if the corresponding <tr> has the display:none attribute?
You can't. When the browser submits the form to the server, the server doesn't receive the values of CSS attributes.
Why does item.FindControl("related" + ID) always return null?
Unlike most ASP.NET server control properties, the ID property is not backed by view state, so changes to the ID property aren't preserved across postbacks. Instead, the ID reverts to the value specified in the markup ("related").

Change image inside web user control (setting up onmouseover programmatically)

Okay, so I'm fairly new to web development (but not programming), and am trying to figure out the best way to implement a mouse over image swap inside a user control.
I've tried several solutions to similar problems on SO already, but my problem appears to be unique to User Controls. I have a (user control) NavigationNenu with 4 (user control) NavigationItems on them, and essentially the NavigationItem is this:
<div class="div_navImage">
<asp:Image ID="navImage" runat="server" ImageUrl="<%this.DefaultImageUrl %>" CssClass="image_navImage" />
<div id="divIconText" runat="server"/>
</div>
with this code behind:
Private ReadOnly Property NavImageElementId As String
Get
Return navImage.GetUniqueIDRelativeTo(Me.Parent.Parent).ToString().Replace("$"c, "_"c)
End Get
End Property
<PersistenceMode(PersistenceMode.InnerProperty)>
Public Property DefaultImageUrl As String
<PersistenceMode(PersistenceMode.InnerProperty)>
Public Property HoverImageUrl As String
<PersistenceMode(PersistenceMode.InnerProperty)>
Public Property IconText As String
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
navImage.Attributes.Add("onmouseover", "updateImageToHover(" + NavImageElementId + ")")
navImage.Attributes.Add("onmouseout", "updateImageToDefault(" + NavImageElementId + ")")
navImage.ImageUrl = "~\" & DefaultImageUrl
divIconText.InnerText = IconText
End Sub
and the html for the nav menu:
<%# Control Language="vb" AutoEventWireup="false" CodeBehind="NavigationMenu.ascx.vb" Inherits="[internal stuff]" %>
<%# Register Src="~/UserControls/Common/NavigationItem.ascx" TagName="navItem" TagPrefix="ucNavItem" %>
<ucNavItem:navItem ID="home" DefaultImageUrl="Resources/home_default.png" HoverImageUrl="Resources/home_hover.png" IconText="home" runat="server" />
<ucNavItem:navItem ID="ideas" DefaultImageUrl="Resources/ideas_default.png" HoverImageUrl="Resources/ideas_hover.png" IconText="ideas" runat="server" />
<ucNavItem:navItem ID="data" DefaultImageUrl="Resources/data_default.png" HoverImageUrl="Resources/data_hover.png" IconText="data" runat="server" />
<ucNavItem:navItem ID="solutions" DefaultImageUrl="Resources/solutions_default.png" HoverImageUrl="Resources/solutions_hover.png" IconText="solutions" runat="server" />
The javascript has fluctuated a bit and I don't really have a working copy right now, but the best result I was able to achieve so far was on mouse over the icon would change to the proper image, but only of the last item in the navigation menu (ie item 1 would change to the hover over icon for item 4 when moused over), so it feels like some kind of scoping or instance issue (though I'm not entirely sure that those kind of issues exist in asp.net/JS/html land).
So, is there something different that needs done when working with JS and a repeated user control? Is there some other way I should be going about what I'm attempting to achieve? I've tried a bit of jquery also, but the samples I've worked with haven't really done anything, so I'm probably setting something up incorrectly there.
Any advice to point me in the right direction?
Thanks in advance.
EDIT:
forgot to point out - the reason I'm not doing a simple swap in the page load on:
navImage.Attributes.Add("onmouseover", "updateImageToHover(" + NavImageElementId + ")")
is because I want the image to change when the text is rolled over as well, and after I implement the JS swap, I will apply the solution to the text as well (but a solution which applies to the outer div would be most welcome as well).
EDIT 2:
JS that produces bad results:
function updateImageToHover(fullName) {
var hoverImageUrl = '<%= HoverImageUrl%>';
var navImage = document.getElementById(fullName.id);
navImage.src = hoverImageUrl;
}

Returning "full" clientID in code behind (asp.net VB)

So I have an issue with accessing the correct clientID attributes of an ASP.NET user control.
My main question is that I'm trying to return the full ClientID field of a control using VB code-behind. the expected value for my control (and what shows up in browser) is:
ctl00_ContentPlaceHolder1_ctl05_txtAnswer
But I'm only getting "txtAnswer" in code-behind.
I've found something similar on SO here:
ASP.Net: ClientID not correct in code-behind of a user control
This post suggests adding the onClick event during onPreRender or onPageLoad, etc, But I have other circumstances:
My user control (text box) is designed to 'pre-load' values from a database (if the same user has previously tried to access the form), or if isPostBack == true.
Because I'm reading from a DB for answers, and because there JS function (which uses the getElementByID() JS function) the control needs to access user data ...
Currently the control has a member function loadQuestions(key parameters) that loads specific questions from the database.
More context: I'm updating some older code that had hard-coded (in client ASPX file) control elements, but now the controls are being built dynamically at runtime (i.e., inserted into a placeholder in client page).
I've tried messing around with different ClientIDMode settings (per http://msdn.microsoft.com/en-us/library/system.web.ui.clientidmode.aspx) but no dice so far... I'm using .NET 4.0, so I understand I can directly edit the ClientID via "Static" clientIDmode, and I haven't tried that yet though...
Right now I'm thinking I should "front-load" all of the content-defining stuff into a constructor for the object, which would then apply all the content-defining stuff, and then establish the onClick attribute after the control's data have been populated?
For reference:
Here is the ASP markup for the Control:
<%# Control Language="VB" AutoEventWireup="false" CodeFile="RBHorizWithText.ascx.vb" Inherits="Apps_Controls_RBHorizWithText" %>
<%# Register Assembly="txtBoxLengthValidator" Namespace="txtBoxLengthValidator" TagPrefix="cc1" %>
<asp:Panel ID="pnlPreamble" runat="server">
<div id="divPreamble" runat="server" style="padding-bottom:15px"></div>
</asp:Panel>
<asp:Panel ID="pnlQuestion" runat="server">
<div id="divQuestion1" runat="server"></div>
<div id="divRBL" runat="server" style="padding-left: 20px">
<asp:Table ID="tblAnswers" runat="server" CellPadding="0" CellSpacing="0">
</asp:Table>
</div>
<div id="divQuestion2" runat="server" style="padding-left: 20px; padding-top: 10px"></div>
<div id="divAnswer2" runat="server" style="padding-left:20px; padding-top: 5px; text-align: left" align="left">
<div>
<cc1:TextBoxLengthValidator
ID="tblvAnswer"
ControlToValidate="txtAnswer"
runat="server"
ErrorMessage="Maximum length is 255 Characters"
MaximumLength="255"
Display="Dynamic"
ForeColor="Red">
</cc1:TextBoxLengthValidator>
</div>
<div><asp:TextBox ClientIDMode = "Predictable" ID = "txtAnswer" runat="server" Width="600px" Rows="3" TextMode="MultiLine"></asp:TextBox></div>
</div>
</asp:Panel>
And here is the function from the VB Code-behind (edited for brevity) that calls the JS function...
Public Sub LoadQuestions(ByVal objQRBL As Question, ByVal objQText As Question, ByVal dicAnswers As Dictionary(Of Integer, QuestionAnswer), ByVal LoadAnswers As Boolean)
'This is a function from RBHorizWithText user control that has two member controls: a radio button and a text box (first 2 params).
'dicAnswers are the user's answers stored either in HttpContext.Current, or as global memory objects...
_lstRadioButtons = New List(Of RadioButton)
Me.tblAnswers.Rows.Clear()
'txtAnswer is a member control of type textBox...
Me.txtAnswer.Text = String.Empty
'.
'Stuff to build out <tr> and <td> question display elements to format/store control...
'.
Dim trw As New TableRow
Dim iCount As Integer = 0
For Each objA As QuestionAnswer In objQRBL.AnswerList
Dim objRB As New RadioButton
objRB.ID = objA.QuestID & ";" & objA.AnswerID
objRB.GroupName = "rb" & objA.QuestID
objRB.Text = objA.AnswerText
'This is the main area where I'm having trouble:
' At runtime, Me.txtAnswer.ClientID should evaluate to: "ctl00_ContentPlaceHolder1_ctl05_txtAnswer"
' Instead I'm getting: "txtAnswer"
If objQText.ParentReqResponseCode.IndexOf(";" & objA.ResponseCode & ";") <> -1 Then
objRB.Attributes.Add("onclick", "txtBoxEnable('" & Me.txtAnswer.ClientID & "');")
Else
objRB.Attributes.Add("onclick", "txtBoxDisable('" & Me.txtAnswer.ClientID & "','" & objQText.InnerText & "');")
End If
tcl.Controls.Add(objRB)
trw.Cells.Add(tcl)
_lstRadioButtons.Add(objRB)
iCount += 1
Next
'Other stuff to handle formatting and behavior of other controls...
End Sub
and here are the JS functions, which exist on the master page for the project:
function txtBoxEnable(elID) {
var el = document.getElementById(elID);
el.style.backgroundColor = '#f4df8d';
el.value = '';
el.disabled = '';
}
function txtBoxDisable(elID, innerText) {
var el = document.getElementById(elID);
el.value = innerText;
el.style.backgroundColor = '#ffffff';
el.disabled = 'disabled';
}
Thanks Very Much!
-Lewis
I've tried messing around with different ClientIDMode settings (per
http://msdn.microsoft.com/en-us/library/system.web.ui.clientidmode.aspx)
but no dice so far... I'm using .NET 4.0, so I understand I can
directly edit the ClientID via "Static" clientIDmode, and I haven't
tried that yet though...
Try it, it will solve your issue completely. Whatever ID you assign it on the markup will be the ID you retrieve on the server side. No extra garbage prepended to the ID.

asp.net get html controls in code behind

If I alter the html on a page using JavaScript, how can I access those changes in my ASP.NET code behind?
I found some dhtml "drag and drop" code online (http://www.dhtmlgoodies.com/scripts/drag-drop-nodes/drag-drop-nodes-demo2.html), but after moving list items from one control to another, I don't know how to "access" each control in the code behind so I can save the list items in each control.
I tried using the HTML Agility pack, but it seems like I'm only able to access the unaltered html - meaning all the controls are empty.
Any help/suggestions are appreciated. Or any suggestions as to a better way of accomplishing this are welcome (jQuery? Ajax Toolkit?).
EDIT:
Here's some code. I'm able to populate an ASP Label control (_saveContent), from the JavaScript function saveDragDropNodes, with the "ul" ID and the corresponding "li" controls that I've dragged and dropped. When clicking the save button however, my Label control no longer contains any Text...
function saveDragDropNodes() {
var saveString = "";
var uls = dragDropTopContainer.getElementsByTagName('UL');
for (var no = 1; no < uls.length; no++) { // LOoping through all <ul>
var lis = uls[no].getElementsByTagName('LI');
for (var no2 = 0; no2 < lis.length; no2++) {
if (saveString.length > 0) saveString = saveString + ";";
saveString = saveString + uls[no].id + '|' + lis[no2].id;
}
}
document.getElementById("<%=_saveContent.ClientID %>").innerHTML = saveString.replace(/;/g, ';<br>');
}
<div id="dhtmlgoodies_dragDropContainer">
<div id="dhtmlgoodies_listOfItems">
<div>
<p>
Available Items</p>
<ul id="allItems" runat="server">
</ul>
</div>
</div>
<div id="dhtmlgoodies_mainContainer">
<div>
<p>
Group 1</p>
<ul id="_ul1">
</ul>
</div>
<div>
<p>
Group 2</p>
<ul id="_ul2">
</ul>
</div>
</div>
<asp:Label ID="_lSave" runat="server" ForeColor="Red" EnableViewState="false" />
</div>
<div id="footer">
<span onmouseover="saveDragDropNodes()">
<asp:Button ID="_btnSave" runat="server" Text="Save Groups" OnClick="_btnSave_OnClick" /></span>
</div>
<ul id="dragContent">
</ul>
<div id="dragDropIndicator"></div>
<asp:Label ID="_saveContent" runat="server" />
Code Behind:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
If Not Page.IsPostBack Then
GetItems()
End If
End Sub
Private Sub GetItems()
Dim dt As DataTable = DbHelper.GetDataTableForSP("GetListOptions")
Dim index As Integer = 1
For Each _row As DataRow In dt.Rows
Dim _li As New HtmlGenericControl("li")
_li.ID = _row("ClassId")
_li.Attributes.Add("runat", "server")
_li.InnerHtml = String.Format("{0}) {1} {2}", index, _row("ClassId"), _row("ClassDescription1"))
allItems.Controls.Add(_li)
index += 1
Next
End Sub
Private Sub SaveGroups()
Dim str As String = _saveContent.Text /*No text here */
_lSave.Text = "Groups Saved!"
GetItems()
End Sub
The only content posted back to the server are values from form fields. See: Form submission.
You have two options:
Make use of ajax to pass the HTML from the client to the server.
Use a hidden input field to store the HTML just before the page posts back.
Here is an example of the latter:
Markup
<div id="content"></div>
<asp:HiddenField ID="hiddenContentField" runat="server" />
<asp:Button ID="button1" runat="server" Text="Post back" OnClick="button1_Click" OnClientClick="storeContent();" />
Script
function storeContent() {
$('#<%= hiddenContentField.ClientID %>').val($('#content').html());
}
Any changes made in the content element will then be stored in the hidden input element and sent up to the server on postback.
Then in the code behind you can access the HTML passed up like so:
protected void button1_Click(object sender, EventArgs e)
{
string html = hiddenContentField.Value;
}
Hope this helps.
First of all, HTML code changes will not posted to Server by default. To achieve the drag-n-drop element, please follow the steps below
Uniquely name(id) the Container panels and child elements in it.
Using jQuery/JavaScript track the child element movements from on container panel to another and store the id of element's old parent panel and new parent in json/dictionary object.
While clicking on save button post the tracked dictionary object to server.
On server-side, get the posted json object using Page.Request.
Using the id's stored in json object, Save the list items.
Hope this will helps.
Specify runat="server" on the controls you need to access from code-behind. Also, remember to use ClientID to reference server controls in JavaSript:
var el = document.getElementById("<%=MyElement.ClientID%>");
First, add the jQuery lib to your page header. Add it from the Google CDN, as most of your users should have it cached.
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
Then, after the JS has modified the HTML, call sendToServer and it will post the html you select to the servlet you enter.
function sendToServer(){
var myhtml = document.getElementById('theIdOfTheContainer').innerHTML;
$.post("http://yoururlhere.com",myhtml,function(responseFromServer){
//some code to handle the response from the server on the client.
});
}
$('#buttonid').click(sendToServer);
I am having you use jQuery for this, as it is a very powerful AJAX library. jQuery does three things extremely well, and one of them is AJAX. Inside the post method, the third parameter is an anonymous function. That is the function that gets called once the data has successfully been sent to the server. So, yeah. Try it out, let me know.

Categories

Resources