I propose my case studies:I am developing a table in ASP.NET in which the fields taken from the DB are displayed (in this case Nome, Cognome, Azienda, Provincia) I find myself managing three functions: add, delete and update.
The first two solved without problems, but I'm having problems with the update.To manage it I developed a function in the back end (subsequently called by an AJAX on the client side) that does nothing but use a SELECT query to select the row taken into consideration (based on the ID) and check if it is present on the DB through a reader. Once this was done I thought I would retrieve the values of the fields of that row and insert them in the corresponding text areas.
I can't find a solution to complete the function. I tried with name.InnerHTML (regarding the name field) but it says the name field has no reference.
C# code:
[WebMethod]
public static void Popoladati(string ch)
{
int chiavInt = Convert.ToInt32(ch);
string queryString = "SELECT * FROM Elenco WHERE Id_Identificazione = #chiavInt";
int i = 0;
using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["coso"].ConnectionString))
{
connection.Open();
using (SqlCommand command = new SqlCommand(queryString, connection))
{
SqlParameter parameter = new SqlParameter("chiavInt" , chiavInt);
command.Parameters.Add(parameter);
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
i++;
}
reader.Close();
}
}
AJAX request:
function edit(chiav) {
let param = { ch: chiav };
$.ajax({
type: "POST",
url: "Update.aspx/Popoladati",
data: JSON.stringify(param),
contentType: "application/json; charset=utf-8",
dataType: "json",
global: false,
async: false,
function(a) {
return a.d;
}
});
window.location.href = "Update.aspx?Id_Identificazione=" + chiav;
}
I do not know if I have been clear, in case let me know that I will try to explain myself better
Well, you first should show how you displaying that table.
You can use gridview, listview, or a repeater. I HIGH recommend you use one of these for the display of data (since then you can with relative ease send the edited data back to the database).
So here is a example - I used listview. I dragged listview on the page. clicked on the listview, and used the builder to build the database query and connection.
I then delete the edit template, alternating template, and also delete the data source control that will be dropped on the page. (and REMOVE the data source setting in the list view control property sheet. I do this since this generates all the markup for me, and thus only takes less then 5 minutes of time.
so, now we have this mark up:
<asp:ListView ID="ListView1" runat="server" DataKeyNames="ID">
<ItemTemplate>
<tr style="">
<td><asp:TextBox ID="FirstName" runat="server" Text='<%# Eval("FirstName") %>' /></td>
<td><asp:TextBox ID="LastName" runat="server" Text='<%# Eval("LastName") %>' /></td>
<td><asp:TextBox ID="HotelName" runat="server" Text='<%# Eval("HotelName") %>' /></td>
<td><asp:TextBox ID="City" runat="server" Text='<%# Eval("City") %>' /></td>
<td><asp:CheckBox ID="Active" runat="server" Checked='<%# Eval("Active") %>' /></td>
</tr>
</ItemTemplate>
<LayoutTemplate>
<table id="itemPlaceholderContainer" runat="server" border="0" style="">
<tr runat="server" style="">
<th runat="server">FirstName</th>
<th runat="server">LastName</th>
<th runat="server">HotelName</th>
<th runat="server">City</th>
<th runat="server">Active</th>
</tr>
<tr id="itemPlaceholder" runat="server"></tr>
</table>
</LayoutTemplate>
</asp:ListView>
<br />
<asp:Button ID="cmdSave" runat="server" Text="Save" />
Ok, not much markup. The code to fill this view? We have this:
private DataTable rstTable = new DataTable();
protected void Page_Load(object sender, System.EventArgs e)
{
if (IsPostBack == false)
{
LoadGrid();
ViewState("MyTable") = rstTable;
}
else
rstTable = ViewState("MyTable");
}
public void LoadGrid()
{
string strSQL;
strSQL = "SELECT ID, FirstName, LastName, HotelName, City, Active from tblHotels ORDER BY HotelName";
using (SqlCommand cmdSQL = new SqlCommand(strSQL,
new SqlConnection(My.Settings.TEST3)))
{
cmdSQL.Connection.Open();
rstTable.Load(cmdSQL.ExecuteReader);
ListView1.DataSource = rstTable;
ListView1.DataBind();
}
}
}
Note careful how we have a class (form level) table variable - and we persist it in view state (you could also use session().
Ok, now, so far VERY VERY little code. When we run the above, we get this:
Ok, so now we need the code for the save button. The user can edit, change - in fact tab quite much around almost like a spreadsheet. To save the edits, then the user can hit the save button. The code for the save button is thus now this:
protected void cmdSave_Click(object sender, EventArgs e)
{
// move values from list view back to table.
foreach (ListViewDataItem vRow in ListView1.Items)
{
var OneRow = rstTable(vRow.DataItemIndex);
OneRow("FirstName") = (TextBox)vRow.FindControl("FirstName").Text;
OneRow("LastName") = (TextBox)vRow.FindControl("LastName").Text;
OneRow("HotelName") = (TextBox)vRow.FindControl("HotelName").Text;
OneRow("City") = (TextBox)vRow.FindControl("City").Text;
OneRow("Active") = (CheckBox)vRow.FindControl("Active").Checked;
}
// now send table chagnes back to database
using (SqlCommand cmdSQL = new SqlCommand("SELECT ID, FirstName, LastName, HotelName, City, Active from tblHotels where ID = 0", new SqlConnection(My.Settings.TEST3)))
{
SqlDataAdapter da = new SqlDataAdapter(cmdSQL);
SqlCommandBuilder sqlBuild = new SqlCommandBuilder(da);
da.Update(rstTable);
}
}
So what we do is pull the changes back from the list view into the table, and then use a data adaptor "update" command to save all of the changes back to the database in ONE shot!
You can of course toss in say a un-do button - that would simply just call load grid again, and thus un-do any edits.
So, as this point, you really don't need ajax, and you don't actually need MUCH code at all.
Also the above approach works equal well for a gridview, or Repater control.
I tend to like the listview - it does generate more mark-up out of the box, but I just go on a quite delete markup party for the list view. I prefer the listview since you do NOT need to wrap each standard .net control inside of a "template control" over and over - which I find a pain.
So the above concept?
You create a data table. Pull the data you want to edit into that table. You then bind the table to the gridview/listview/repeater for display (and this allows editing).
to save?
You pull data back from the data repeating item to the table. And then use the data adaptor to update ALL changes in ONE shot - this is not only faster, less code, less hassle, but the data adaptor is smart, and for rows not changed, then no update sql is generated behind the scenes.
The total code we write? VERY little, and we thus now have a data editing system that allows you to edit such data - and it behaves darn near like a spreadsheet, and you can even tab around to move the cursor.
So, this approach not only saves world poverty in terms of the amount of code, but it also means that you can edit the whole grid, and save the whole grid in one simple operation.
Related
I know the title might make my question look like a duplicate so please read the complete question first.
I have 3 dropdowns in my webform and based on those parameters the data is retrieved from the database and my gridview is populated. What I need is that once a result is displayed, if the user changes the parameters, the new retrieved data should be displayed below the old data. But currently my gridview is refreshing entirely and only the data based on new parameters is displayed.
I have read that one way is to use viewstate but I dont understand what it is. Can someone please help? Thank you.
Ok, so this is a difficult question. It is rather easy to filter, and have a cumulative filter.
So, say we have this screen:
And lots more rows.
So, I can say lets filter by a city.
So this:
Note how we do allow multiple city in the multi-select drop down.
So, I now have this:
Now, lets select those ONLY with a description.
So this:
And then say only active ones. So, this:
So, above is quite easy to setup. Note how any option NOT selected is left out of the critera.
but, a BIG problem exists in the above.
What happens if I want Active from say B.C. but NOT active from Alberta???
I can't do that, and hence your problem.
What we could do however is add a button to above to SAVE the resulting filter, and put the "list" of filters say into a list box or collection.
we then have a search button to search on our collection of filters.
Let me see if this can work - I'll add to above a "box" or collection of each filter.
I would think a union query with distinct row for each filter would do the trick.
So, above example is not too hard - a "cumulative" filter. In fact, the code patter for 2 or 15 filters is quite easy to do here.
However, adding up separate filter requests and combine them? That is somewhat difficult to do.
Edit: Multiple filters
so, while in above, I could say filter by city and get all active, but THEN I want to filter by another city, and get all NON active!!!
That's the problem here.
So, we would have to add code to SAVE the filter. And the HUGE problem with that is how then do we save each filter to "add up" each filter set we want?
We could try and save the raw SQL, but such SQL would be subject to sql injection, and we want to always use parameters.
So, we can and could adopt a design in which we SAVE the resulting SqlCommand object. And then merge the results.
So, now our UI becomes like this:
Lets grab and filter all those from city Edmonton, but Active,
so, this:
We now hit save filter and this:
And now we filter by say City = Banff, but don't care about active or not.
So we have this:
We then save that filter - and now we have this:
I now hit the filter button below the list of filters, and we get this:
So, how does this code work?
Well, I simple saved the Sqlcommand object to a collection (list), and thus combine the results.
So, first our markup at the top for the filter stuff.
<h4>Filters</h4>
<div style="float:left">
<asp:Label ID="Label1" runat="server" Text="Search Hotel"></asp:Label>
<br />
<asp:TextBox ID="txtHotel" runat="server"></asp:TextBox>
</div>
<div style="float:left;margin-left:20px">
<asp:Label ID="Label2" runat="server" Text="Search City"></asp:Label>
<br />
<asp:TextBox ID="txtCity" runat="server"></asp:TextBox>
</div>
<div style="float:left;margin-left:20px">
<asp:Label ID="Label3" runat="server" Text="Must Have Description"></asp:Label>
<br />
<asp:CheckBox ID="chkDescripiton" runat="server" />
</div>
<div style="float:left;margin-left:20px">
<asp:Label ID="Label4" runat="server" Text="Show only Active Hotels"></asp:Label>
<br />
<asp:CheckBox ID="chkActiveOnly" runat="server" />
</div>
<div style="float:left;margin-left:20px">
<asp:Button ID="cmdSearch" runat="server" Text="Search" CssClass="btn" OnClick="cmdSearch_Click"/>
</div>
<div style="float:left;margin-left:20px">
<asp:Button ID="cmdClear" runat="server" Text="Clear Fitler" CssClass="btn" OnClick="cmdClear_Click"/>
</div>
<div style="float:left;margin-left:20px">
<asp:Button ID="cmdTest" runat="server" Text="Save Filter"
CssClass="btn" OnClick="cmdTest_Click"
OnClientClick="return myfilterprompt()"
/>
<asp:HiddenField ID="HFilterName" runat="server" ClientIDMode="Static"/>
<script>
function myfilterprompt() {
sFilter = ""
sFilter = prompt('Enter name for filter ')
if ( (sFilter === null) || (sFilter === "") ){
return false
}
$('#HFilterName').val(sFilter)
return true
}
</script>
</div>
<div style="float:left;margin-left:30px;width:190px">
<asp:ListBox ID="lstFilters" runat="server" Width="100%" Height="100px"
DataTextField="sFilterName" >
</asp:ListBox>
<asp:Button ID="cmdMultiFilter" runat="server" Text="Filter"
CssClass="btn" OnClick="cmdMultiFilter_Click" style="float:left" />
<asp:Button ID="cmdMultiClear" runat="server" Text="Clear"
CssClass="btn" OnClick="cmdMultiClear_Click" style="float:right"/>
</div>
then below above is our grid:
<asp:GridView ID="GridView1" runat="server"
AutoGenerateColumns="False" DataKeyNames="ID"
CssClass="table" Width="60%" ShowHeaderWhenEmpty="true">
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" />
<asp:BoundField DataField="City" HeaderText="City" />
<asp:BoundField DataField="Province" HeaderText="Province" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:BoundField DataField="Active" HeaderText="Active" />
</Columns>
</asp:GridView>
So, code to load:
List<MyFilter> MyFilters = new List<MyFilter>();
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack == false)
{
SqlCommand cmdSQL = new
SqlCommand("SELECT * FROM tblHotels WHERE ID = 0");
LoadGrid(cmdSQL);
Session["MyFilters"] = MyFilters;
}
else
MyFilters = (List<MyFilter>)Session["MyFilters"];
}
public void LoadGrid(SqlCommand cmdSQL)
{
DataTable rstData = MyRstP(cmdSQL);
GridView1.DataSource = rstData;
GridView1.DataBind();
}
And now our search button:
protected void cmdSearch_Click(object sender, EventArgs e)
{
SqlCommand cmdSQL = GetMyCommand();
LoadGrid(cmdSQL);
}
SqlCommand GetMyCommand()
{
string strSQL = "SELECT * FROM tblHotels ";
string strORDER = " ORDER BY HotelName";
string strFilter = "";
SqlCommand cmdSQL = new SqlCommand();
if (txtHotel.Text != "")
{
strFilter = "(HotelName like #HotelName + '%')";
cmdSQL.Parameters.Add("#HotelName", SqlDbType.NVarChar).Value = txtHotel.Text;
}
if (txtCity.Text != "")
{
if (strFilter != "") strFilter += " AND ";
strFilter += "(City Like #City + '%') ";
cmdSQL.Parameters.Add("#City", SqlDbType.NVarChar).Value = txtCity.Text;
}
if (chkActiveOnly.Checked)
{
if (strFilter != "") strFilter += " AND ";
strFilter += "(Active = 1)";
}
if (chkDescripiton.Checked)
{
if (strFilter != "") strFilter += " AND ";
strFilter += "(Description is not null)";
}
if (strFilter != "") strSQL += " WHERE " + strFilter;
strSQL += strORDER;
cmdSQL.CommandText = strSQL;
return cmdSQL;
}
And now our save the filter button code:
protected void cmdTest_Click(object sender, EventArgs e)
{
MyFilter OneFilter = new MyFilter();
OneFilter.sFilterName = HFilterName.Value;
OneFilter.cmdSQL = GetMyCommand();
MyFilters.Add(OneFilter);
lstFilters.DataSource = MyFilters;
lstFilters.DataBind();
}
public class MyFilter
{
public string sFilterName { get; set; }
public SqlCommand cmdSQL = new SqlCommand();
}
And our multi-filter code button.
Now, for large data sets - not a great idea, but a start:
protected void cmdMultiFilter_Click(object sender, EventArgs e)
{
List<DataTable> MyTables = new List<DataTable>();
foreach (MyFilter OneFilter in MyFilters)
{
DataTable rstDT = MyRstP(OneFilter.cmdSQL);
MyTables.Add(rstDT);
}
DataTable rstData = MyTables[0];
for (int i = 1;i < MyTables.Count;i++)
{
rstData.Merge(MyTables[i]);
}
GridView1.DataSource = rstData;
GridView1.DataBind();
}
so, you can build list up of "filters" and display them in a listbox and then have a filter button that merges all of the filtering.
And one more helper routine I used:
public DataTable MyRstP(SqlCommand cmdSQL)
{
DataTable rstData = new DataTable();
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (cmdSQL)
{
cmdSQL.Connection = conn;
conn.Open();
rstData.Load(cmdSQL.ExecuteReader());
}
}
return rstData;
}
These systems can be really nice. Often a group of managers will say, lets grab all customers from west coast. Yuk - too many. Ok, only those with purchases in last 2 months - ah, that's nice.
then they say, lets get all customers who never purchased anything, but from the south - and add those to the list - but only active on our mailing list.
So, this type of slice and dice - get some of those, and then get some of these, and then combine them?
This type of business query system and being able to combine these, and those, and them, and then toss in a few more? Often they will keep going say until such time they get say 10,000 results (which happens to be how many catalogs they have left they would like to send out).
So, I solved my problem by using a little outside the box thinking. I am posting it here for anyone visiting this question or having a same problem in the future could see this:
So what I did is that I extracted the data from the database based on the parameters selected by the user from the dropdowns. In the database, I had created a temp table to store the extracted temporarily. So I inserted the data into that temporary table and used that table to populate the gridview. I had to add a reset button, when the user clicked it the all the data is deleted from the temp table and also the page reset to its default with gridview not visible and dropdowns having no selection.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I am making a Canteen Management System using ASP.NET Forms.
So I want a Pop-Up window or box which will take input from dropdown list and textbox to implement Filter option.
So how to make it and how to access collected data from code behind?
Any tutorials links or suggestion are all welcome. Thanks for helping :)
There are quite a few ways to do this. If you using the AjaxControlToolKit, they have a fantastic pop up extender, and it takes no JavaScript.
However, probably the best choice is to use jQuery.UI. It is without a doubt your site and application has jQuery, so, I would add jQuery.UI. You can use nueget to install it, or simply go to the jquery site and download the jQuery.UI files. They are common.
So, the way we do this is you create (usually) a "div" on the page that is a popup. This works great since is responds to a "click" very fast (you don't even have to hit the server for the dialog to pop-up. However, the form you pop up might be to edit data.
The next consideration is that popup form cannot have post-backs. (well, ok, it can have one). So if the form you popup is to have some rich verification code, or code that requires some server side event code to run? You tend to be out of luck. So, you can easy pop a form, the user can edit (or enter data), but then you only allowed ONE post-back button event (say "ok - save"). So in most cases such a popup form is fine, but do keep in mind this limitation. If you do need some things to respond in that dialog, then you in most cases have to write ajax calls - that is extra pain and workload for the developer.
So, lets assume we want to pop up a dialog to filter a grid. The popup will allow the user to type in the first few characters of the hotel name OR WE can select a city from a drop down list to filter the grid by city.
and we toss in a show only "active" records with a check box.
So, how would this work, and look? (and keeping the above considerations in mind (only one post-back allowed in the pop dialog).
Well, we first build the grid. But, we need to add some buttons to the heading. So I have to drop a few of the databound fields, and use a template for that one column. This lets us setup the header with a button, or whatever we feel like.
And I did the same for the city heading.
So, we have this markup:
<div id="HotelGrid" runat="server" style="width:50%">
<asp:GridView ID="GHotels" runat="server" AutoGenerateColumns="False" DataKeyNames="ID" CssClass="table table-hover"
style="vertical-align:middle" ShowHeaderWhenEmpty="true">
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:TemplateField>
<HeaderTemplate>
<asp:LinkButton ID="btnSearchCity"
runat="server"
CssClass="btn-default btn-sm"
>City
<span aria-hidden="true" class="glyphicon glyphicon-search"></span>
</asp:LinkButton>
</HeaderTemplate>
<ItemTemplate>
<asp:Label ID="lblCity" runat="server" Text='<%# Eval("City") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Province" HeaderText="Province" />
<asp:TemplateField HeaderStyle-Width="200px">
<HeaderTemplate>
<asp:LinkButton ID="cmdSearchHotel"
runat="server"
CssClass="btn-default btn-sm"
OnClientClick="return mysearch(this);"
OnClick="cmdSearchHotel_Click"
>Hotel
<span aria-hidden="true" class="glyphicon glyphicon-search"></span>
</asp:LinkButton>
</HeaderTemplate>
<ItemTemplate>
<asp:Label ID="lblHotel" runat="server" Text='<%# Eval("HotelName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Description"HeaderText="Description" />
<asp:TemplateField HeaderText="Active" ItemStyle-HorizontalAlign="Center" >
<ItemTemplate>
<asp:CheckBox ID="chkActive" runat="server" Checked='<%# Eval("Active") %>' />
</ItemTemplate>
<ItemStyle HorizontalAlign="Center"></ItemStyle</asp:TemplateField>
<asp:TemplateField HeaderText="Edit">
<ItemTemplate>
<asp:Button ID="cmdEdit" runat="server" Text="Edit"class="btn" OnClick="cmdEdit_Click"/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Now, you can see in above, the markup starts to grow - that's due to gridview requiring "template" around each set of controls. (I often suggest using a listview, since you don't need the template(s). But no big deal.
Ok, so we have the above markup.
My page load code to load the grid? Well, we want the heading to dispaly, so we do it this way:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
GHotels.DataSource = MyRst("select * from tblHotels where id = 0")
GHotels.DataBind()
' load the city combo box
cboCity.DataSource = MyRst("SELECT City from tblCity ORDER BY City")
cboCity.DataBind()
cboCity.Items.Insert(0, "") ' allow blank selection
End If
End Sub
Public Function MyRst(strSQL As String) As DataTable
Dim rstData As New DataTable
Using MyCon As SqlConnection = New SqlConnection(My.Settings.TEST3)
Using cmdSQL As New SqlCommand(strSQL, MyCon)
cmdSQL.Connection.Open()
rstData.Load(cmdSQL.ExecuteReader)
End Using
End Using
Return rstData
End Function
Ok, so we now see/have this:
Now, the two buttions in the grid heading will have TWO parts.
The part to pop the dialog (jQuery.UI), and then the standard code server side.
Ok so, we have to create a div to hold our pop up.
It will be rather simple, and just combo box (for city), a text box for hotel anme, and a check box for "active only" filter.
so, that div is quite simple. and note when we happy with the div layout, we add display:none to hide the div.
so we have this:
<div id="mysearchdiv" style="border:solid;width:300px;text-align:right;padding:15px;font-size:large;display:NONE">
<p>Select City
<asp:DropDownList ID="cboCity" runat="server" width="150px"
DataTextField="City"
DataValueField="City"
></asp:DropDownList>
</p>
<p>
Hotel Name
<asp:TextBox ID="txtSearchHotel" runat="server" Width="150" Height="25"></asp:TextBox>
</p>
<p>
Include Only Active
<asp:CheckBox ID="chkActiveOnly" runat="server" />
</p>
<asp:HiddenField ID="cmdOption" runat="server" ClientIDMode="Static"/>
</div>
Really very simple markup.
Ok, now the hard part, the jQuery UI is a java script routine, and it is this:
<script>
var searchok = false
function mysearch(btn) {
if (searchok) {
return true
}
var myDialog = $("#mysearchdiv");
myDialog.dialog({
title:"Search For Hotels",
modal: true,
width: "320px",
resizable: false,
appendTo: "form",
autoOpen: true,
buttons: {
Ok: function ()
{
searchok = true
btn.click()
},
Clear: function () {
searchok = true
$('#cmdOption').val('c')
btn.click()
},
Cancel: function () {
myDialog.dialog('close')
}
}
});
return false
}
</script>
So, it is a bit of code, but what jQuery.UI is "grabs" that div, and converts it into a nice dialog. So the end result is this:
Now, either the c# tag was added after I started typing this, or I missed it.
but, the c# code is much the same. The first page load code is this:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
GHotels.DataSource = MyRst("select * from tblHotels where id = 0");
GHotels.DataBind();
// load our search combo box
cboCity.DataSource = MyRst("SELECT City from tblCity ORDER BY City");
cboCity.DataBind();
cboCity.Items.Insert(0,new ListItem("",""));
}
}
public DataTable MyRst(string strSQL)
{
DataTable rstData = new DataTable();
using (SqlCommand cmdSQL = new SqlCommand(strSQL,
new SqlConnection(Properties.Settings.Default.TEST3)))
{
cmdSQL.Connection.Open();
rstData.Load(cmdSQL.ExecuteReader());
}
return rstData;
}
So above will load up the grid (we send it a blank row, since we using the header for searching.
and the buttion click? Well, we pop a jquery dialog. And if it returns true, or false - that determines if the server side buttion will fire.
So, we have this:
<asp:TemplateField HeaderStyle-Width="200px">
<HeaderTemplate>
<asp:LinkButton ID="cmdSearchHotel"
runat="server"
CssClass="btn-default btn-sm"
OnClientClick="return mysearch(this);"
OnClick="cmdSearchHotel_Click"
>Hotel
<span aria-hidden="true" class="glyphicon glyphicon-search"></span>
</asp:LinkButton>
</HeaderTemplate>
<ItemTemplate>
<asp:Label ID="lblHotel" runat="server" Text='<%# Eval("HotelName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
Note very carefull how we have the jQuery search routine return true ,or false.
Ok, so now it is a simple matter to write that code to filter/search the grid based on that popup.
The code is quite simple, and we "cumulative" add up each search option, or simple skip the options if no value in the search box is entered.
And, we added that hidden field, since as you can see, we can now add more buttons to that dialog, but not have to create new code server side - but just use the one button click to handle all options for that dialog.
And the c# code for this filtering is thus:
protected void cmdSearchHotel_Click(object sender, EventArgs e)
{
if (cmdOption.Value == "c")
{
// clear the search option
cboCity.Text = "";
txtSearchHotel.Text = "";
chkActiveOnly.Checked = false;
cmdOption.Value = "";
GHotels.DataSource = MyRst("select * from tblHotels where id = 0");
GHotels.DataBind();
return;
}
// filter the grid
string strWhere = "";
using (SqlConnection con = new SqlConnection(Properties.Settings.Default.TEST3))
using (SqlCommand cmdSQL = new SqlCommand("SELECT * FROM tblHotels",con))
{
if (cboCity.Text != "")
{
strWhere += "City = #City";
cmdSQL.Parameters.Add("#City", SqlDbType.NVarChar).Value = cboCity.Text;
}
if (txtSearchHotel.Text != "")
{
if (strWhere != "")
strWhere += " AND ";
strWhere += "HotelName like #Hotel + '%'";
cmdSQL.Parameters.Add("#Hotel", SqlDbType.NVarChar).Value = txtSearchHotel.Text;
}
if (chkActiveOnly.Checked)
{
if (strWhere != "")
strWhere += " AND ";
strWhere += "Active = 1";
}
if (strWhere != "")
cmdSQL.CommandText += " WHERE " + strWhere;
cmdSQL.CommandText += " ORDER BY HotelName";
con.Open();
GHotels.DataSource = cmdSQL.ExecuteReader();
GHotels.DataBind();
}
So, all in all:
A absoulte min of code.
Not really much more markup then a typical grid.
And I shared a LONG time super cool trick that VERY VERY VERY few have used. That is how to get the one jQuery.UI dialog to NOT fire the server side button if we don't want to. And thus we don't need multiple routines in java, and we don't need multiple routines server side. We simply have the one button call the dialog, and it returns true, or false. But it STILL is running asyncrious as all and most JavaScript widgets should be. (no blocking code allowed!!!).
You can create fied position DIV and show it using JS,JQuery, ... whenever you want to show the dialog.
then you can read input data.
How to generate a simple popup using jQuery
I have a datalist which is populated with values from a database. When the user clicks a checkbox, I want to loop through all of the datalist items and hide all of the items that have the property isActive = false (which is displayed as "Disabled" in a text label). The item template consists of a table that contains multiple other items, buttons etc, which have not been included below. I therefore want to hide all elements that are found under the itemtemplate of a specific item.
My idea was to just hide the entire table by accessing its id, and then setting the table's visible property to false. This is currently not doing anything when I run the code. Any help will
appreciated!
<asp:CheckBox runat="server" Text="Filter by active postings" OnCheckedChanged="filterByActive"/>
<asp:DataList ID="postingsDataList" runat="server" OnItemCommand="itemCommand" >
<ItemTemplate>
<div class="postingRow">
<table class="postingTable" id="posting">
<tr>
<td>
<asp:Label ID="lblActive" runat="server" Text=<%#Eval("isActive").ToString().Equals("True") ? "Active ✅" : "Disabled ❌"%>/>
</td>
</tr>
</table>
</div>
</ItemTemplate>
</asp:DataList>
Code Behind:
protected void filterByActive (object sender, EventArgs e)
{
int count = postingsDataList.Items.Count;
CheckBox check = (CheckBox)sender;
if (check.Checked == true)
{
for (int i = 0; i < count; i++)
{
Label lblActive = postingsDataList.Items[i].FindControl("lblActive") as Label;
string isActive = lblActive.Text.ToString();
if (isActive.Equals("Disabled ❌"))
{
Table tbl = postingsDataList.Items[i].FindControl("posting") as Table;
tbl.Visible = false;
}
}
}
else
{
for (int i = 0; i < count; i++)
{
Label lblActive = postingsDataList.Items[i].FindControl("lblActive") as Label;
string isActive = lblActive.Text.ToString();
if (isActive.Equals("Active ✅"))
{
Table tbl = postingsDataList.Items[i].FindControl("posting") as Table;
tbl.Visible = true;
}
}
}
}
}
Ok, I suggest you do this:
Persist your table - thus you don't have to hit sql server again. (but, you could - not the end of the world).
I don't have your data, but I have a simple list of hotels - and there is a Active column for the Hotel. So, lets filter the data based on checking the check box, not have to hit the database server again. And EVEN BETTER is if we un-check the box, we can display all records we had.
We assume of course this is not a lot of data.
Ok, so we have this for our markup:
(really does not matter a whole lot)
<asp:DataList ID="DataList1" runat="server" DataKeyField="ID" RepeatColumns="4" RepeatDirection="Horizontal" >
<ItemTemplate>
<div style="border-style:solid;color:black;width:300px;">
<div style="padding:5px;text-align:right">
<p>Hotel Name: <asp:TextBox ID="HotelName" runat="server" Text ='<%# Eval("HotelName") %>' /></p>
<p>First Name: <asp:TextBox ID="FirstName" runat="server" Text ='<%# Eval("FirstName") %>' /></p>
<p>Last Name: <asp:TextBox ID="LastName" runat="server" Text ='<%# Eval("LastName") %>' /></p>
<p>City: <asp:TextBox ID="City" runat="server" Text ='<%# Eval("City") %>' /></p>
<p>Province: <asp:TextBox ID="Province" runat="server" Text ='<%# Eval("Province") %>' /></p>
Active: <asp:CheckBox ID="Active" runat="server" Checked = '<%# Eval("Active") %>'/>
</div>
</div>
</ItemTemplate>
</asp:DataList>
Now, our code to load could be this:
DataTable rstData = new DataTable();
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
LoadData();
ViewState["MyData"] = rstData;
}
else
rstData = (DataTable)ViewState["MyData"];
}
void LoadData()
{
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
string strSQL = "SELECT top 10 * from tblHotels ORDER BY HotelName";
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
conn.Open();
rstData.Load(cmdSQL.ExecuteReader());
DataList1.DataSource = rstData;
DataList1.DataBind();
}
}
}
And now we have this:
Now, our filter show/hide becomes JUST this:
protected void ckFilter_CheckedChanged(object sender, EventArgs e)
{
// filter based on check box
if (ckFilter.Checked)
rstData.DefaultView.RowFilter = "Active = 1";
else
rstData.DefaultView.RowFilter = "";
DataList1.DataSource = rstData;
DataList1.DataBind();
}
And BETTER is if I un-check the check box, all the data is re-displayed. And we don't have to re-hit the database to do this!!!
Now, we COULD also just hide/show each row, and then un-hide if for some reason you don't want to persist the data table as I did per above.
Checking on the box filters to this:
As noted, if I un-check the box, then I get all the data back - all without hitting the database again.
Edit:=========================================
Note that if you NOT using the above horizontal across, but just rows down?
Then you can just as well format to hide/show the rows, and you do NOT have to persist the data table.
You can apply formatting say by doing this:
protected void ckFilter_CheckedChanged(object sender, EventArgs e)
{
foreach (DataListItem gRow in DataList1.Items)
{
// get checkbox
CheckBox ckActive = (CheckBox)gRow.FindControl("Active");
// get div
HtmlGenericControl Myiv = (HtmlGenericControl)gRow.FindControl("myrow");
string MyFormat = "normal";
if (ckFilter2.Checked)
{
// only show active ones
if (ckActive.Checked)
MyFormat = "normal";
else
MyFormat = "none";
}
Myiv.Style["display"] = MyFormat;
}
}
So the above does work fine. BUT the restriction is that you can't have a set of horizontal across data items like my original screen shot
(it actually still works but in fact hide each panel with a blank space).
So, if your as noted using vertical layout (and it looks to be that you are).
Note for above, I added a simple ID to the "div", and runat server like this:
<ItemTemplate>
<div id="myrow" runat="server"
style="border-style:solid;color:black;width:300px;">
Then skip my first example. You can loop the data list rows, and hide, or un-hide. And even more amazing is that if you un-hide - then the rows all do re-appear and persist correct.
I had pulled a working example - but I was trying to figure out why I had to persist the data - the reason was the "horizontail" across settings.
But, as above shows, no real need to persist the data source table - you can process the data list rows, and hide/show each one conditionals, and you can do this without a data re-bind.
I usually deal with Repeater to generate tables in my asp.net pages, but now I need to handle dynamic columns in my table, so I wonder if there is a common approach to solve this issue using web controls.
I've never used GridView, so I don't know if this is better to render tables with dynamic columns? Can you suggest me wich is the more appropriate approach? Is there a way to achieve this using Repeater?
You could a GridView with AutoGenerateColumns set to true. It would inspect and add the columns in your DataSource
<asp:sqldatasource id="CustomersSource"
selectcommand="SELECT CustomerID, CompanyName, FirstName, LastName FROM SalesLT.Customer"
connectionstring="<%$ ConnectionStrings:AWLTConnectionString %>"
runat="server"/>
<asp:gridview id="CustomersGridView"
datasourceid="CustomersSource"
autogeneratecolumns="True"
emptydatatext="No data available."
allowpaging="True"
runat="server" DataKeyNames="CustomerID">
</asp:gridview>
It is very important to know how you want to handle the situation.
Situation 1:
You have an existing table and from time to time you add columns (which is not very practical though) you can straight away go for the GridView and set the AutoGenerateColumns binding property to true.
Situation 2
You can create your own HTmlHelper Class for handling the tables.
For this you can visit the following post:
How to create MVC HtmlHelper table from list of objects
if you are using MVC.
Here's a quick hack to do this if you must use Repeater:
In the .aspx:
<asp:Repeater ID='rptr' runat='server'>
<HeaderTemplate>
<table>
<thead>
<tr>
<th>
Always visible header col
</th>
<th id='thHidable' runat='server' class='hideable'>
Hideable header col
</th>
</tr>
</thead>
<tbody>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
Repeated col
</td>
<td id='tdHideable' runat='server' class='hideable'>
Hideable repeated col
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</tbody></table>
</FooterTemplate>
</asp:Repeater>
In the code behind (assuming C# used):
protected override void Page_Init()
{
this.rptr.ItemDataBound += new RepeaterItemEventHandler(rptr_ItemDataBound);
}
void rptr_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
RepeaterItem item = (RepeaterItem)e.Item;
if (item.ItemType == ListItemType.Header)
{
HtmlTableCell thHidable = (HtmlTableCell)item.FindControl("thHidable");
if (hideCondition)
{
// thHidable.Visible = false; // do not render, not usable by client script (use this approach to prevent data from being sent to client)
thHidable.Style["display"] = "none"; // rendered hidden, can be dynamically shown/hidden by client script
}
}
else if (item.ItemType == ListItemType.Item || item.ItemType == ListItemType.AlternatingItem)
{
HtmlTableCell tdHideable = (HtmlTableCell)item.FindControl("tdHideable");
if (hideCondition)
{
// tdHideable.Visible = false; // do not render, not usable by client script (use this approach to prevent data from being sent to client)
tdHideable.Style["display"] = "none"; // rendered hidden, can be dynamically shown/hidden by client script
}
}
}
(optional) If you want to dynamically show column on client side (assuming it was rendered), using jQuery (for brevity):
$(".hideable").show();
This is my first attempt at asp.net and webforms, windowsforms, all of it. I originally populated data in a listbox, but I could only get one column and thought the listView sounded like it would do what I wanted.
The most promising solution I found was this:
DataSet listData = new DataSet();
CancellationsControls cancelCtrl = new CancellationsControls();
listData = cancelCtrl.GetScheduledReleaseDataSet();
DataTable dtable = listData.Tables[0];
scheduledReleasesTag.Items.Clear();
foreach (DataRow row in dtable.Rows)
{
string[] ar = Array.ConvertAll(row.ItemArray, p => p.ToString());
scheduledReleasesTag.Items.Add(new ListViewDataItem(ar));
}
The dtable is a custom table of a query joining a number of tables.
in the foreach loop the ar string array succesfully shows the colums of data that I want, but the ListViewDataItem requires two int arguments instead of a string array like the example I pulled this from.
I've tried to figure out more about how the listView control works, but this is as close as I have been able to get to getting anything. Any help with explanations would be very appreciated.
Thank you :)
I'm pretty beginner in asp, but to bind ListView control with data, smth like this should work:
DataSet listData = new DataSet();
CancellationsControls cancelCtrl = new CancellationsControls();
listData = cancelCtrl.GetScheduledReleaseDataSet();
DataTable dtable = listData.Tables[0];
ListView1.DataSource = dtable;
ListView1.DataBind();
Now we have to create an ItemTemplate. Your ListView control should look like:
<asp:ListView ID="ListView1" runat="server">
<ItemTemplate>
<tr id="Tr1" class="item" runat="server">
<td>
<asp:Label ID="column_name" runat="server" Text='<%# Eval("column_name") %>' />
</td>
</tr>
<tr id="Tr2" class="item" runat="server">
<td>
<asp:Label ID="another_column_name" runat="server" Text='<%# Eval("another_column_name") %>' />
</td>
</tr>
</ItemTemplate>
</asp:ListView>
Just replace markers(column_name,another_column_name) with names of columns, that contains data you want to display. This template displays pairs of rows values from two columns one by one.