ASP.NET Gridview: How do I stop a <span></span> within a Gridview from resetting when posting back? - asp.net

I have a Gridview which contains some controls which are updated from the server when the user makes a selection from a gridview.
After making their selection from a drop down list the user can enter a percentage into a textbox on a row and I have some javascript which then carries out some calculations and outputs to a span within an item template in the Gridview.
This all works but if the user then makes another drop down list selection on any row all the spans in the gridview are reset to blank (I've tried with various controls, both asp.net and html).
This is all inside an Update Panel.
Code:
<asp:GridView runat="server" ID="gdvIngredients" AutoGenerateColumns="false" CssClass="table table-stripped"
GridLines="None" Visible="false" ShowFooter="true" EnableViewState="true">
<Columns>
<asp:TemplateField Visible="false">
<ItemTemplate>
<asp:Label runat="server" ID="lblId" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Ingredient" ItemStyle-Width="12%">
<ItemTemplate>
<asp:DropDownList runat="server" ID="ddlName" AutoPostBack="true" OnSelectedIndexChanged="ddlName_SelectedIndexChanged"
ForeColor="Black" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="%" ItemStyle-Width="6%">
<ItemTemplate>
<asp:TextBox runat="server" Text="0" Width="50px" ID="txtPercentage" onkeyup="calculate(this);"
ForeColor="Black" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="kj" ItemStyle-Width="6%">
<ItemTemplate>
<asp:Label runat="server" ID="lblKj" CssClass="Kj" Style="display: none;" />
<span runat="server" id="spnKj" class="NewKj">0</span>
</ItemTemplate>

From your question what i have understood is that you are doing calculation in javascript and assigning it to span,but when next postback happens the value is not retained...If i am right i would suggest you to try the following steps.Use HiddenFields also to assign Values as HiddenFields Retain values during PostBacks.
Add Hidden field in Item Template
Set "calculate" function to Textbox from Codebehind(from rowdatabound event) & also pass the currosponding HiddenField Value to it as calculate(this,'HiddenFieldId');
protected void grd_RowDataBound(object sender,GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
HiddenField hdn = ((HiddenField)e.Row.FindControl("HiddenFieldID"));
TextBox txtPercentage = (TextBox)e.Row.FindControl("txtPercentage");
HtmlGenericControl spnKj=(HtmlGenericControl )e.Row.FindControl("spnKj");
txtPercentage.Attributes["onClick"]="calculate(this,'"+hdn .ClientID+"');"
spnKj.innerHTML=hdn.Value;
}
}
Javascript:
Assign Calculated Value to Hidden Field...
function calculate(hdnID)
{
var CalcValue=//do your Calculation
document.getElementByID(hdnID).Value=CalcValue;
}
3.In the DropDown PostBack Event Bind the GridView Again.
The above code should take care of the Issue You are facing.

You can use the "AutoPostBack" property to control the Postback event of some controls.

Have a look if your dropdown list selection do any PostBack.
If it does, then span values disappear, becuase Span is not ASP.NET webcontrol. After pages is postback, asp.net webcontrol values are restored from ViewState. So, spans doesn't have ViewState and no values are restored.
You can try to change your tag to
<span runat="server" id="spanIDHere">SomeValue here</span>
runat="server" makes span to be HtmlGenericControl and maintains its ViewState.
Span values would not be saved after postback if you update them using Javascript. You should call server-side function to update span values or try to use Hidden fields to store your values.

Related

Asp.net gridview edit without editbutton

I have regular asp.net gridview,and i want to enable editmode in each row,and also without editbutton (like excel grid).
Edited data i want to save to my database by clicking "Post" button outside the grid(one button for whole grid).
How can i reach it?
To achieve this, you are going to have to use ItemTemplates for each column with textboxes in them as the control..
ASP
<asp:TemplateField HeaderText="Heading Title" SortExpression="Heading Title">
<ItemTemplate>
<asp:TextBox ID="tbTextbox" runat="server" Width="65px" Text='<%# Bind("ColumnNameYouWantToView") %>'></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
After this is set up properly, you will want the post button. You can either put it in the grid or outside the grid. I use both, but here is the one inside the grid as a footer.
ASP
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="btnView" runat="server" Text="View" OnClick="btnView_Click" Width="40px" />
</ItemTemplate>
<FooterTemplate>
<asp:Button ValidationGroup="UPDATE" ID="btnUpdate" OnClick="btnUpdate_Click" runat="server" Text="Update" Width="50px"></asp:Button>
</FooterTemplate>
<FooterStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="50px" />
</asp:TemplateField>
So far, what I have found that works best is using a foreach statement in your button click. The biggest flaw with this idea is that it will update every single row. It works, but if you only change a single row at a time, it will update all of them. I have my pager set to 10, so 10 rows are always updated (unless you are just searching for a single record and update it, the only that single record is updated).
Code Behind C#
protected void btnUpdate_Click(object sender, EventArgs e)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["databaseConnection"].ConnectionString);
conn.Open();
//finds the controls within the gridview and updates them
foreach (GridViewRow gvr in gvGridViewName.Rows)
{
string ID = (gvr.FindControl("lblId") as Label).Text.Trim();//finds the control in the gridview
string anotherControl = ((TextBox)gvr.FindControl("tbTextBox")).Text.Trim();//finds the textbox in the gridview
//Your update or insert statements
}
This is how I do it. You can also look into Real World Grids but I haven't had much luck with this as I would always get an error if a textbox was empty. This however, is suppose to be "smart" enough to just update the rows that have been changed, but again, I didn't have much luck of doing it this way. Hope this helps!

Lost Focus Events for a Control Within GridView

I have multiple textboxes and dropdown lists within my GridView. For one particular textbox I need trigger a server event which gets data from the database and fills it in other columns of the Grid. Is there a simple way to do it or a slightly complicated way as detailed here
I have no problems implementing the above method or thinking of a work around but then thought that there is Cell Lost Focus in a grid control surprises me a little. Am I missing something ? Any help on this would appreciated.
You can set AutoPostBack to true and handle it's TextChanged event.
<asp:GridView ID="GridView1" runat="server" EmptyDataText="It's Empty.">
<Columns>
<asp:TemplateField HeaderText="Name">
<ItemTemplate>
<asp:TextBox ID="txtName"
runat="server"
Text='<%#Eval("Name") %>'
AutoPostBack="true"
OnTextChanged="NameChanged" >
</asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</GridView>
in codebehind:
protected void NameChanged(Object sender, EventArgs e)
{
var txtName = (TextBox) sender;
var row = (GridViewRow) txtName.NamingContainer;
// you could find other controls in this GridViewRow via
// row.FindControl("ControlID") in case of a TemplateField or
// row.Cells[0].Text (0 = index of column) in case of a BoundField
}

FindControl("someTextBox") in GridView not sending the updated value

Im populating a GridView from List so am forced to use TemplateField controls to allow editing. This requires displaying a TextBox populated with the original value when in edit mode and using FindControl to get the new value out on update submit.
Problem is foundTextBox.Text == "OriginalTextBoxValue"
<asp:TemplateField HeaderText="A Field">
<ItemTemplate>
<asp:Label ID="_theLabel" runat="server" Text='<%# Eval("AField") %>' />
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="_theTextBox" runat="server" Text='<%# Eval("AField") %>' />
</EditItemTemplate>
</asp:TemplateField>
And the code in my update event handler
TextBox newText = (TextBox)_myGridView.Rows[e.RowIndex].FindControl("_thTextBox");
//newText.Text == the old value of the text box
Is your gridview binded at every postback? This could explain why you never get the updated value, because the gridview is rebinded before reading the textbox.
Could you paste your complete update method?
You've got the code behind in the wrong event handler. Move it to the Editing event handler, so it will populate the textbox whenever the user clicks on the Edit command for a row.

ASP .Net Gridview bind to data only when clicking update

Here's how I want the control to work. Click edit on a row in gridview. There's a textbox in one of the columns, I would like it to be blank even though there's data in the database for that column, but when I click update I would like whatever new text the user entered to update the database for that column. It would be one-way databinding, but the other way?
Here's how I did it using an sql datasource with the select,update and delete methods generated.
First, you'll need to make any column that you want to edit like this a template field with an item template and and edit item template:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID" DataSourceID="SqlDataSource1"
onrowupdating="GridView1_RowUpdating">
<Columns>
<asp:TemplateField HeaderText="City" SortExpression="City">
<ItemTemplate>
<asp:Label runat="server" Text='<%# Eval("City") %>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox runat="server" ID="txtCityEdit" Text=""></asp:TextBox>
</EditItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Next handle the gridview's on update event:
protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
//find the value control who's value you want
TextBox tb = (TextBox)GridView1.Rows[e.RowIndex].FindControl("txtCityEdit");
//since we are not using a bound column for city we need to explicitly insert the value
//into the update parameter.
SqlDataSource1.UpdateParameters["City"].DefaultValue = tb.Text;
}
Even if you are using something other than an SQL Datasource this should be the basic solution.
// Find notes textbox
TextBox tb = (TextBox)MyActiveReferrals.Rows[e.RowIndex].FindControl("NotesTextBox");
e.NewValues.Add("Notes", tb.Text);
I used a linq data source.

How do I data bind a drop down list in a gridview from a database table using VB?

So in this gridview, there is a column for status and I want to have a drop down list with Pass, Pending, Fail appear when the edit button is clicked. These values are already in a table, so I need to somehow bind from this table to each ddl for every row.
Here is the column from the gridview. As you can see, I would like to just have a label showing when not in edit mode, and a ddl when the edit button is pressed
<asp:TemplateField HeaderText="During Production Status" SortExpression="DuringProductionStatus">
<EditItemTemplate>
<asp:DropDownList ID="ddlStatus" runat="server" datavaluefield="Name"
datatextfield="Name" DataSource="*What goes here?*"> />
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="lblStatus" runat="server"
Text='I don't understand how to get this from the ddl' />
</ItemTemplate>
</asp:TemplateField>
For clarity's sake, my table is named Status, and the database is named DirectImport
There's a few steps to go through here - none of them are particularly difficult, but they can be a bit fiddly (IMHO). The good news is once you've got this working once, it gets easier to do it again!
I'm assuming you've got a <asp:*DataSource> control on your page - my preference is for an ObjectDataSource but I don't think it matters, I think a SqlDataSource works equally well. I've never tried doing this with GridView.DataSource = MyDataSet in code-behind, so I don't know whether that would work or not, but my assumption is that it wouldn't as you wouldn't get the proper two-way binding that you want. This data source feeds your grid with your main data. The key point here is that your database query must return both the Status text field and the Status id.
So your gridview will now look something like:
<asp:objectdatasource runat="server" id="MainDataSource" ... />
<asp:gridview runat="server" id="MyGridView" DataSourceID="MainDataSource">
<Columns>
<asp:TemplateField HeaderText="During Production Status" SortExpression="DuringProductionStatus">
<ItemTemplate>
<asp:Label ID="lblStatus" runat="server"
Text="<%# Bind('Status') %>" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:gridview>
The Text="<%# Bind('Status') %>" is the bit you're missing to get the status text into the grid.
Now add a second data source into your markup that reads in the set of values from the Status table.
<asp:objectdatasource runat="server" id="StatusObjectDataSource" ... />
And add the EditItemTemplate into the GridView, which is bound to the Status DataSource.
<EditItemTemplate>
<asp:DropDownList ID="ddlStatus" runat="server" datavaluefield="StatusID"
datatextfield="Status" DataSourceID="StatusObjectDataSource"
SelectedValue="<%# Bind('StatusId') %>" />
</EditItemTemplate>
The SelectedValue="<%# Bind('StatusId') %>" is what connects up the two datasets so that when you flip a row into Edit mode, the dropdownlist has the correct item already selected, and when you then save it you've got the Status ID to put into your database.
And you're done.
I have used the RowDataBound event. Here is a small code snippet. HTH
you would have an ItemTemplate in your aspx/ascx
<asp:TemplateField HeaderText="Column Headings">
<ItemTemplate>
<asp:DropDownList ID="ddlName" runat="server" Width="150"></asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
and in your code behind, you will have
protected void grdDataMap_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DropDownList ddl = (DropDownList)e.Row.FindControl("ddlName");
ddl.DataSource = someList;//the source of your dropdown
ddl.DataBind();
}
}
so when you bind your grid with grdDataMap.Databind (assuming your grid id is grdDataMap), row databound event will be called for each row (including header/footer, and thats the reason you check RowType)
so you can probably decide what controls/columns to hide/show/bind inside this row databound event
In the winforms world I pull my objects from the DB into a List(Of Whatever) and use the list as the datasource.
This also lets me add extra "convenience" fields in the object so that I can populate it with stuff from other tables.
I don't know asp.net at all so if you can do something similar, it might help.
A really quick solution is to create a custom web control for the status dropdown. The control will always contain the same data. When it renders you populate the datasource. When it gets added to the gridview, the data will be in the drop down. Hope that helps!

Resources