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

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.

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.

How can I hide/unhide a form?

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.

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.

Make Sectioned Page Content

This question is pretty difficult for me to phrase well, so please bear with me.
In VS Express I'm creating a series of web pages. On each page I want there to be a series of functions, relevant to a given user role. I want all my html code on a single aspx page, but with only certain sections appearing (hopefully asynchronously) as determined by the url which will be linked to via a drop down menu in the navbar.
I would like to use Rerouting (I think it's called) to keep my urls nice and more malleable so I can change them later without breaking bookmarks and such.
As a user, in a given role, I would mouse over the drop-down menu and see only the functions which I am allowed to perform. Upon clicking on one, it would update the url something like domain.com/form1 and would only show the block of code (in the aspx page, and again, preferably asynchronously) relevant to that action.
I'm thinking to use divs and the css "display:none;" property. I'm not not sure by what mechanism to toggle between the "views," if you will, of the various functions. Should I use Javascript of ASP.NET?
I'm so sorry for such a convoluted question. I spent over 20 minutes and this is the best way I could figure to ask. Does this even many any sense? If so, am I going about this all wrong or am I on the right track? I appreciate any stabs at this.
Cheers ;)
PLEASE READ: I originally wanted to accomplish this with the urls, but I found that using the "MultiView" ASP.NET control is was a much better solution to my dilemma. I just wanted to clear up any presumed discrepancy between my original question and my answer. Like I said, it was a difficult question to figure out how to ask at the time. :)
It's actually called URL rewriting. There is a few way to achieve that, the easier might be the wizard in IIS.
As for all your html in a single page, you could use panels and change their visibility when needed.
Being somewhat new to .NET and especially ASP.NET, I'm learning new things everyday, literally. I've recently discovered the "Multiview" control, which is amazing. I've used it for creating multiple menu bars (I know this seems wierd, but it's to simulate different user "modes" or user groups, etc), as well as the combining of content onto a single page as I mentioned in my original question. I then added a secondary control for toggling between the menus. Here is some sample code for how I implemented the control for my multi-menubar :P
<asp:MultiView ID="MenuView" runat="server">
<!-- ADMIN GROUP -->
<asp:View ID="View0" runat="server">
<asp:Menu ID="adminNav" runat="server" CssClass="menu" IncludeStyleBlock="False" Orientation="Horizontal"><DynamicMenuItemStyle />
<Items>
<asp:MenuItem NavigateUrl="~/Reports.aspx" Text="View Reports" />
<asp:MenuItem NavigateUrl="~/Approve.aspx" Text="Compliment hard-working employees" />
<asp:MenuItem NavigateUrl="~/Promote.aspx" Text="Promote the qualified employees :)" />
<asp:MenuItem NavigateUrl="~/Fire.aspx" Text="Send underlings home to starving children" />
</Items>
</asp:Menu>
</asp:View>
<asp:View ID="View1" runat="server">
<!-- USERS -->
<asp:Menu ID="userNav" runat="server" CssClass="menu" IncludeStyleBlock="False"
Orientation="Horizontal"><DynamicMenuItemStyle />
<Items>
<asp:MenuItem NavigateUrl="~/Work.aspx" Text="Look productive" />
<asp:MenuItem NavigateUrl="~/Complain.aspx" Text="Complain about boss" />
<asp:MenuItem NavigateUrl="~/Praise.aspx" Text="Show appreciation for your awesome boss" />
</Items>
</asp:Menu>
</asp:View>
</asp:MultiView>
<!-- MODE MENU -->
<asp:DropDownList ID="modeMenu" runat="server" AutoPostBack="True"
ViewStateMode="Inherit" CssClass="modeMenu" EnableViewState="True">
<asp:ListItem>Admin</asp:ListItem>
<asp:ListItem>User</asp:ListItem>
</asp:DropDownList>
Code Behind for controlling "MenuView" with "modeMenu" dropdown which I have as "position:fixed; left:5px; top:5px;" in my CSS to keep it out of the way.
Protected Sub mode(ByVal sender As Object, ByVal e As System.EventArgs) Handles modeMenu.Load, modeMenu.SelectedIndexChanged
Session.Add("mode", modeMenu.SelectedValue) //I use a session variable to maintain the state of the menu.
Select Case (modeMenu.SelectedValue)
Case "Admin"
MenuView.ActiveViewIndex = 0
Case "User"
MenuView.ActiveViewIndex = 1
End Select
End Sub
There you have it. I hope someone else finds this useful. Cheers ;)

Categories

Resources