I'm developing a web page for clients to request exemptions from certain requirements. There is a list of 14 CheckBoxes, each with two subsequent Checkboxes. The code to check which of them are checked will be placed in the submit button. This method is in the code behind. Here's the code for that (so far)
[WebMethod]
public void SendForm(string email)
{
if (string.IsNullOrEmpty(email))
{
throw new Exception("You must supply an email address.");
}
else
{
if (IsValidEmailAddress(email))
{
bool[] desc = new bool[14];
bool[] local = new bool[14];
bool[] other = new bool[14];
for (int i = 1; i <= 14; i++)
{
desc[i] = ((CheckBox)Page.FindControl("chkDesc" + i.ToString())).Checked;
local[i] = ((CheckBox)Page.FindControl("chkLocal" + i.ToString())).Checked;
other[i] = ((CheckBox)Page.FindControl("chkOther" + i.ToString())).Checked;
/* Do stuff here */
}
}
else
{
throw new Exception("You must supply a valid email address.");
}
}
}
I get the error "An object reference iw required for the non-static field, method, or property..."
In the aspx page I have the button and the javascript/ajax that calls the button in the codebehind. Shown here:
<table width='750' align='center'>
<tr>
<td align='left'>
<label>Please Provide your email address:</label>
<asp:TextBox ID="txtEmail" runat="server"></asp:TextBox>
</td>
</tr>
<tr>
<td align='left'>
</td>
</tr>
<tr>
<td align='left'>
<fieldset id="Fieldset">
<button onclick="SendForm();">
Send</button>
<button onclick="CancelForm();">
Cancel</button>
</fieldset>
</td>
</tr>
</table>
</form>
<asp:ScriptManager ID="ScriptManager1" EnablePageMethods="true" EnablePartialRendering="true" runat="server" />
<script type="text/javascript">
function SendForm() {
var email = $get("txtEmail").value;
PageMethods.SendForm(email, OnSucceeded, OnFailed);
}
function OnSucceeded() {
$get("Fieldset").innerHTML = "<p>Thank you!</p>";
}
function OnFailed(error) {
alert(error.get_message());
}
</script>
As per my knowledge, you can't refer to the controls of a page in the static method until and unless you explicitly pass a reference of the "Page" object to the web method you have written.
Where you have the following code:
bool[] desc = new bool[14];
bool[] local = new bool[14];
bool[] other = new bool[14];
for (int i = 1; i <= 14; i++)
{
desc[i] = ((CheckBox)Page.FindControl("chkDesc" + i.ToString())).Checked;
local[i] = ((CheckBox)Page.FindControl("chkLocal" + i.ToString())).Checked;
other[i] = ((CheckBox)Page.FindControl("chkOther" + i.ToString())).Checked;
/* Do stuff here */
}
Why don't you have this validation code in a Class in your project.. is there a reason why you are trying to access the PageControls using this code
if (IsValidEmailAddress(email))
{
for (int i = 1; i <= count; i++)
{
CheckBox chkBox = chkDesc1.Checked;
}
}
Change your for loop and start i = 0 and change <= 14 to < 13 C# is 0 based
Place the whole method signature .. you are probably trying to call a non static method inside of your application either add the word static to the method or remove but I would rather see how you have the method created.. also where are you creating the instance of the WebMethod Class object..?
Related
I've got a page in my application that will allow users to run stored procedures against the database so that they can manage their data or make changes without using SSMS. Using the SqlCommandBuilder.DeriveParameters method, I was able to successfully fetch and display all stored procedures in a select tag as well as display their input & output parameters.
Here is the contract class:
public class DatabaseUpdateModel
{
public int ClientId { get; set; }
public string StoredProcedureName { get; set; }
public List<SelectListItem> StoredProcedureNames { get; set; }
public Dictionary<string, SqlParamCollection> StoredProcedures { get; set; }
public Dictionary<int, string> ParameterInputs { get; set; }
public DatabaseUpdateModel()
{
StoredProcedureNames = new List<SelectListItem>();
StoredProcedures = new Dictionary<string, SqlParamCollection>();
ParameterInputs = new Dictionary<int, string>();
}
}
I do this in two steps - step 1 happens on the controller's index loading to fetch the stored procedure names:
Service methods:
private DatabaseUpdateModel GetDatabaseUpdateStoredProcedureNames(string connectionString)
{
_logger.LogTrace("Begin GetDatabaseUpdateModel service method");
SqlConnection connection = new SqlConnection(connectionString);
DBConnectionSetter.SetDBConnection(_SqlHelper, connectionString);
DatabaseUpdateModel model = new DatabaseUpdateModel();
IDataReader reader = _SqlHelper.GetDataReader("SELECT name FROM sys.objects WHERE type = 'p' ORDER BY name ASC", CommandType.Text, _appSettings.CommandTimeoutInSeconds, out connection, null);
while (reader.Read())
{
SelectListItem storedProcedure = new SelectListItem
{
Value = ((string)reader["name"]).Trim(' '),
Text = (string)reader["name"]
};
model.StoredProcedureNames.Add(storedProcedure);
}
reader.Close();
return model;
}
Step 2 happens via Ajax when a stored procedure is selected
public DatabaseUpdateModel GetDatabaseUpdateProcedureParameters(string connectionString, string storedProcedureName)
{
_logger.LogTrace("Begin GetDatabaseUpdateProcedureParameters service method");
SqlConnection connection = new SqlConnection(connectionString);
DBConnectionSetter.SetDBConnection(_SqlHelper, connectionString);
DatabaseUpdateModel model = GetDatabaseUpdateStoredProcedureNames(connectionString);
connection.Open();
Contract.Shared.SqlParamCollection collection = new Contract.Shared.SqlParamCollection();
SqlCommand command = new SqlCommand();
command.Connection = connection;
command.CommandText = storedProcedureName;
command.CommandType = CommandType.StoredProcedure;
SqlCommandBuilder.DeriveParameters(command);
foreach (SqlParameter param in command.Parameters)
{
if (param.Direction == ParameterDirection.Input)
{
collection.InputParameters.Add($"{param.ParameterName} - {param.SqlDbType}");
collection.SqlParameters.Add(param);
}
else
{
collection.OutputParameters.Add($"{param.ParameterName} - {param.SqlDbType}");
}
}
model.StoredProcedures.Add(storedProcedureName, collection);
connection.Close();
return model;
}
What this leaves me with is this:
Now I've been following various articles and resources to get to this point but now I'm having issues correctly binding these inputs to a model to be submitted either by an action or via ajax. Here's my current code in the view (the commented out line is one of my latest attempts to get this working).
#model DatabaseUpdateModel
<form>
<table id="summaryTable" class="table">
<thead>
<tr>
<td>Input Parameters</td>
<td>Output Parameters</td>
</tr>
</thead>
<tbody>
<tr>
<td>
<ul>
#if (!string.IsNullOrEmpty(Model.StoredProcedureName))
{
for (int i = 0; i < Model.StoredProcedures[Model.StoredProcedureName].InputParameters.Count(); i++)
{
<li>
#Model.StoredProcedures[Model.StoredProcedureName].InputParameters[i].ToString()<br />
#*<input id="databaseUpdateParam[#i]" name="parameter[#i]" asp-for="#Model.ParameterInputs[#i]" type="text" />*#
<input id="databaseUpdateParam[#i]"type="text" />
</li>
}
}
</ul>
</td>
<td>
<ul>
#if (!string.IsNullOrEmpty(Model.StoredProcedureName))
{
foreach (var param in Model.StoredProcedures[Model.StoredProcedureName].OutputParameters)
{
<li>
#param
</li>
}
}
</ul>
</td>
</tr>
</tbody>
</table>
</form>
#if (Model.StoredProcedures[Model.StoredProcedureName].InputParameters.Count() > 0)
{
<button type="submit" asp-action="Foo">Submit</button>
}
Ajax function that runs when a value is selected:
function selectDatabaseUpdateStoredProcedure(clientId, storedProcedureName) {
var selected = $("#clientStoredProcedurePicker option:selected").val();
console.log(selected); // Selected Stored Procedure Name
$.ajax({
url: "/Process/GetDatabaseUpdateProcedureParameters?ClientId=" + clientId + "&StoredProcedureName=" + storedProcedureName,
success: function (data) {
console.log(data);
$("#summaryTableDiv").html(data);
}
});
}
My assumption, and everything that I read up to this point has said that I should be able to simply be able to use the name attribute to denote the dictionary's key and the value in the tag would correspond to the value entered upon form submission. However all of my attempts to achieve this are met with errors (for example that the index is not present in the dictionary).
How can this be done either through a controller action or ajax?
I wanted to have this question up so that if someone more knowledgeable happened upon it, I could maybe gain some insight to save myself even more hours of scratching my head. After reading through an article linked in this question I found that I was missing a key piece in how the HTML is rendered and came up with something like this that now correctly posts the values in the inputs. I still need to process and handle the other missing pieces from the model but at least this gets me what I need to move forward.
Here is the relevant code that allows this to work. Creating a hidden input to store the ID on its own and allowing the user to enter a string value seems to work exactly as I expect and want it to.
<td>
<ul>
#if (!string.IsNullOrEmpty(Model.StoredProcedureName))
{
for (int i = 0; i < Model.StoredProcedures[Model.StoredProcedureName].InputParameters.Count(); i++)
{
<li>
#Model.StoredProcedures[Model.StoredProcedureName].InputParameters[i].ToString()<br />
<input hidden id="databaseUpdateParamKey[#i]" name="ParameterInputs[#i].Key" value="#i" />
<input id="databaseUpdateParamValue[#i]" name="ParameterInputs[#i].Value" type="text" />
</li>
}
}
</ul>
</td>
I am using itextsharp library.I design an HTML page and convert to PDF .in that case some table are not split perfectly and row also not split correctly
table.keepTogether;
table.splitRows;
table.splitLate
I try this extension but it does not work correctly it mess my CSS and data in PDF. if you have method..answer me:)
finally i got it
public class TableProcessor : Table
{
const string NO_ROW_SPLIT = "no-row-split";
public override IList<IElement> End(IWorkerContext ctx, Tag tag, IList<IElement> currentContent)
{
IList<IElement> result = base.End(ctx, tag, currentContent);
var table = (PdfPTable)result[0];
if (tag.Attributes.ContainsKey(NO_ROW_SPLIT))
{
// if not set, table **may** be forwarded to next page
table.KeepTogether = false;
// next two properties keep <tr> together if possible
table.SplitRows = true;
table.SplitLate = true;
}
return new List<IElement>() { table };
}
}
use this class and
var tagfac = Tags.GetHtmlTagProcessorFactory();
tagfac.AddProcessor(new TableProcessor(), new string[] { HTML.Tag.TABLE });
htmlContext.SetTagFactory(tagfac);
integrate this method with htmlpipeline context
this method every time run when the tag hasno-row-split.if it contain key it will make kept by keep together keyword to make page breaking
html
<table no-row-split style="width:100%">
<tr>
<td>
</td>
</tr>
</table>
I'm trying to do some validation of some other fields on the page after the user clicks the upload button of the ajaxfileupload control. OnClientUploadStart is defined to fire before the upload starts. and it works. but I want to cancel the upload if the validation fails.
I tried doing "return false;" but that didn't work.
How can I cancel the upload?
if the validation fails then I want to cancel
function uploadStart(sender, args) {
var FileDescription = document.getElementById("FileDescription").value;
alert( FileDescription);
return false;
}
<ajaxToolkit:AjaxFileUpload ID="AjaxFileUpload1"
ThrobberID="myThrobber" OnUploadComplete="AjaxFileUpload1_UploadComplete"
ContextKeys="" OnClientUploadError="uploadError" OnClientUploadComplete="uploadComplete" OnClientUploadStart="uploadStart"
AllowedFileTypes="jpg,jpeg,doc,xls"
MaximumNumberOfFiles="1"
runat="server"/>
To start uploading manually you can use this script:
function startUpload(){
$get("<%= AjaxFileUpload1.ClientID %>_UploadOrCancelButton").click();
}
Cancel download large files (works only for browsers that support HTML5).
function uploadStartedAjax(sender, args) {
var maxFileSize = $('#MaxRequestLength').val();
for (var i = 0; i < sender._filesInQueue.length; i++) {
var file_size = sender._filesInQueue[i]._fileSize;
if (file_size > maxFileSize) {
sender._filesInQueue[i].setStatus("cancelled", Sys.Extended.UI.Resources.AjaxFileUpload_Canceled+' - too large(> ' + maxFileSize + ' byte)!');
sender._filesInQueue[i]._isUploaded = true;
} //End if
} //End for
return true;
}
<ajaxToolkit:AjaxFileUpload ID="AjaxFileUpload1" runat="server" MaximumNumberOfFiles="200" Width ="750px"
OnClientUploadStart="uploadStartedAjax" />
This is my first post here! :)
I have to return an array of my model from my controller class to the view page. I want to put the data into a text box and generate dynamic id's for each text box to use the data further via JavaScript (that's why I am looking for dynamic id's).
Model
public partial class BhBuyerChart
{
public string Date { get; set; }
public string Quantity { get; set; }
public BhBuyerChart(string n, string d)
{
Date = n;
Quantity = d;
}
}
Controller
public ActionResult test()
{
BhBuyerChart[] model = new BhBuyerChart[7];
DataTable dt = (DataTable)ExecuteDB(ERPTask.AG_GetAllShipmentRecord, CurrentUserId);
List<BhBuyerChart> ItemList = null;
ItemList = new List<BhBuyerChart>();
int i = 0;
foreach (DataRow dr in dt.Rows)
{
model[i] = new BhBuyerChart(dr["Shipmentdate"].ToString(), dr["ShipmentQuantity"].ToString());
i++;
};
return View(model);
}
View
1st Attempt
<div>
<% for (int i=0; i<2; i++) {%>
<%: Html.TextBoxFor(m => m[i].Quantity, new { id = "Quantity"})%> <%--value can assign from model but dnt know how to assing dynamic id --%>
<input type="text" value="<%= i %>" id="text<%=i %>"/> <%--dynamic id can be assinged dnt knw how to assing model value here in textbox --%>
<% } %>
</div>
2nd Attempt
<div>
<% int i = 0; %>
<% foreach (ERP.Domain.Model.BhBuyerChart user in Model) { %>
<% i++; %>
<input type="text"; id="textbox<% i %>" ; value="<% user.Quantity %>" />
<% } %>
</div>
I really appreciate everybody's attention and help and I look forward to your responses!
I think this should do it for you. Effectively what you're going to do is build a new method inside the controller so that you can POST back to the controller with the updated values. Further, you don't want the Quantity fields to have different names because they won't bind - and so each one you build will say Quantity in the name and id attribute when the HTML is generated.
If I've misunderstood your need please comment.
Controller
public ActionResult test()
{
BhBuyerChart[] model = new BhBuyerChart[7];
DataTable dt = (DataTable)ExecuteDB(ERPTask.AG_GetAllShipmentRecord, CurrentUserId);
List<BhBuyerChart> ItemList = null;
ItemList = new List<BhBuyerChart>();
int i = 0;
foreach (DataRow dr in dt.Rows)
{
model[i] = new BhBuyerChart(dr["Shipmentdate"].ToString(), dr["ShipmentQuantity"].ToString());
i++;
};
return View(model);
}
[HttpPost]
public ActionResult test(ICollection<BhBuyerChart> charts)
{
// This allows you to POST to the controller with the modified values
// Note that based on what you're collecting client side the charts
// will ONLY contain the Quantity value, but they will all have one.
// If you need the date you can either show a text box for that or
// even place the date inside a hidden field.
}
View
<form method="post" action="/{controllername}/test">
...
<div>
<% for (int i=0; i<2; i++) {%>
<!-- This line will both bind the value and allow you to POST -->
<!-- this form back to the controller with the new values -->
<!-- NOTE: each control is actually going to be named the same -->
<!-- but when it's posted will post in order to the collection -->
<%: Html.TextBoxFor(m => m[i].Quantity) %>
<!-- You may or may not want this here so that you can get the -->
<!-- value of the date back to the server during a POST -->
<%: Html.HiddenFor(m => m[i].Date) %>
<% } %>
</div>
...
</form>
JavaScript
Now in JavaScript what you can do is use jQuery to simply get a listing of all the elements named Quantity like this and use them from that array.
// with this ([0].Quantity) being the template
// we'll use a simple wildcard selector to find
// all of them that end with Quantity.
var elems = $("[name$=Quantity]")
// now you have a list of the elements that you
// can use to populate the other array with -
// getting the value with a statement like...
var val = elems[0].val();
You need the excellent extension made by Steven Sanderson called BeginCollectionItem. For each row in your Model, each inputs will inherit an unique guid that you can reuse for validation or other stuff.
For more information on how to use the extension step by step, please go see the article on Steven Sanderson's blog : Editing a variable length list, ASP.NET MVC 2-style
The article was made for MVC2 but it work in MVC3 too. It should work in MVC4 but i haven't tested yet.
View
<% foreach (var item in Model) {
<% using(Html.BeginCollectionItem("bhBuyerItem")) { %>
<%= Html.TextBoxFor(m => m.Quantity) %>
<%= Html.TextBoxFor(m => m.Date) %>
<% } %>
<% } %>
The extension method
public static class HtmlPrefixScopeExtensions
{
private const string idsToReuseKey = "__htmlPrefixScopeExtensions_IdsToReuse_";
public static IDisposable BeginCollectionItem(this HtmlHelper html, string collectionName)
{
var idsToReuse = GetIdsToReuse(html.ViewContext.HttpContext, collectionName);
string itemIndex = idsToReuse.Count > 0 ? idsToReuse.Dequeue() : Guid.NewGuid().ToString();
// autocomplete="off" is needed to work around a very annoying Chrome behaviour whereby it reuses old values after the user clicks "Back", which causes the xyz.index and xyz[...] values to get out of sync.
html.ViewContext.Writer.WriteLine(string.Format("<input type=\"hidden\" name=\"{0}.index\" autocomplete=\"off\" value=\"{1}\" />", collectionName, html.Encode(itemIndex)));
return BeginHtmlFieldPrefixScope(html, string.Format("{0}[{1}]", collectionName, itemIndex));
}
public static IDisposable BeginHtmlFieldPrefixScope(this HtmlHelper html, string htmlFieldPrefix)
{
return new HtmlFieldPrefixScope(html.ViewData.TemplateInfo, htmlFieldPrefix);
}
private static Queue<string> GetIdsToReuse(HttpContextBase httpContext, string collectionName)
{
// We need to use the same sequence of IDs following a server-side validation failure,
// otherwise the framework won't render the validation error messages next to each item.
string key = idsToReuseKey + collectionName;
var queue = (Queue<string>)httpContext.Items[key];
if (queue == null) {
httpContext.Items[key] = queue = new Queue<string>();
var previouslyUsedIds = httpContext.Request[collectionName + ".index"];
if (!string.IsNullOrEmpty(previouslyUsedIds))
foreach (string previouslyUsedId in previouslyUsedIds.Split(','))
queue.Enqueue(previouslyUsedId);
}
return queue;
}
private class HtmlFieldPrefixScope : IDisposable
{
private readonly TemplateInfo templateInfo;
private readonly string previousHtmlFieldPrefix;
public HtmlFieldPrefixScope(TemplateInfo templateInfo, string htmlFieldPrefix)
{
this.templateInfo = templateInfo;
previousHtmlFieldPrefix = templateInfo.HtmlFieldPrefix;
templateInfo.HtmlFieldPrefix = htmlFieldPrefix;
}
public void Dispose()
{
templateInfo.HtmlFieldPrefix = previousHtmlFieldPrefix;
}
}
}
well after several tries i guess i have able to make this
<%for (int i = 0; i <= 1; i++)%>
<% { %>
<div style="width:100%; float:left">
<%: Html.TextBoxFor(m => m[i].Date, new { id= i+500 })%>
<%: Html.TextBoxFor(m => m[i].Quantity, new { id = i })%>
<%: Html.TextBoxFor(m => m[i].Quantity) %>
</div>
<script type="text/javascript">
var val = [[], []];
for (k = 0; k <= 1; k++) {
val[k][0] = document.getElementById(k+300).value;
val[k][1] = parseInt(document.getElementById(k).value);
}
</script>
this gonna take dynamic data from model array and create dynamic id for each textbox and assign them into variable using dynamic id
"Only images or images wrapped in links are allowed in the slider div. Any other HTML will break the slider."
What would be the best way to programatically insert images from a database in c#?
I was using a label inside the div id="slider" tag but then realized the label would create the images within a span tag and therefore break the slider.
lblSlider.Text += "<img src=\"" + URL + "\" alt=\"" + address + "\" title=\"<a href='Featured/" + address" + address + ", " + city + "</a>\" />";
Use markup like this...
<img src='ImageHandler.ashx?ProductID=<%# Eval("ProductID")%>'
alt="<%# Eval("ProductName") %>" title="<%# Eval("ProductName") %>" />
... in conjunction with an image HttpHandler class like this (adapt for your own particular DB schema):
public class ImageHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
if (context.Request.QueryString["productID"] != null)
{
try
{
string ProductID = context.Request.QueryString["ProductID"];
if (Convert.ToInt32(ProductID) > 0)
{
const string CONN
= "Initial Catalog=xxx;Data Source=xxx;Integrated Security=SSPI;";
string selectQuery
= "SELECT Photo FROM dbo.Products WHERE dbo.Products.ProductID="
+ ProductID.ToString();
SqlConnection conn = new SqlConnection(CONN);
SqlCommand cmd = new SqlCommand(selectQuery, conn);
conn.Open();
SqlDataReader dr = cmd.ExecuteReader();
dr.Read();
context.Response.BinaryWrite((Byte[])dr[0]);
dr.Close();
conn.Dispose();
// context.Response.End();
// caused an "Abort thread" error
// - this is correct and is a special exception
}
}
catch (Exception ex)
{
ErrorReporting.LogError(ex);
}
}
else
throw new ArgumentException("No ProductID parameter specified");
}
public bool IsReusable
{
get
{
return true; // multiple images otherwise false
}
}
}
Okay, I haven't tried the other solution but I did this and it works:
Here are some global c# variables:
protected int count;
protected string[] arr = new string[20];
Then I assign values to the string array from my database in the Page_Load method.
And then I just write the nivo slider with javascript on my page:
<script type="text/javascript">
document.write("<div id='slider' class='nivoSlider'>");
var count = <%= count %>;
var myArray = <% = new JavaScriptSerializer().Serialize(arr) %>;
for(var i = 0; i < count; i++) {
document.write(myArray[i]);
}
document.write("</div>");
</script>
This solution seems easier to me, but if anyone thinks I should use the other solution over this one, let me know. Oh, and don't forget the namespace System.Web.Script.Serialization
I have same requirement and tried the below code to accomplish the dynamic loading of images basing on category. These image loaded from my database. I am new to ASP.Net please let me know if I did anything wrong or did any blunders :).
in ASP.Net file:
I am using nivo slider append method
<script type="text/javascript">
$(window).load(function() {
$('#slider').append('<img id="ad5" src=<%=__ad1ImageUrl %> />');
$('#slider').append('<img id="ad6" src=<%=__ad2ImageUrl %> />');
$('#slider').append('<img id="ad7" src=<%=__ad3ImageUrl %> />');
$('#slider').append('<img id="ad8" src=<%=__ad4ImageUrl %> />');
$('#slider').nivoSlider();
});
</script>
My table looks like this:
<table style="height: 183px; width: 100%" cellpadding="0" cellspacing="0" border="0">
<tr>
<td align="left">
<div id="wrapper">
<div class="slider-wrapper theme-default">
<div class="ribbon">
</div>
<div id="slider" class="nivoSlider">
<!-- note that no images added here -->
</div>
</div>
</div>
</td>
</tr>
</table>
In the code behind:
Use variable to store image url(s). You can now get the URL(s) from DB and get populated. In my code i have used these variables (can use array also) to capture url path. You can get the paths from any source like Database, Xml or ...
public string __ad1ImageUrl = "";
public string __ad2ImageUrl = "";
public string __ad3ImageUrl = "";
public string __ad4ImageUrl = "";
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
__ad1ImageUrl = "UserControls/Images/mainBanner1.jpg";
__ad2ImageUrl = "UserControls/Images/mainBanner2.jpg";
__ad3ImageUrl = "UserControls/Images/mainBanner3.jpg";
__ad4ImageUrl = "UserControls/Images/mainBanner4.jpg";
}
}