asp.net - Update db from input and button inside a table - asp.net

I know this seems stupid but I can't find a way to make it work...
I generate a table from a db with this loop (simplified)
#foreach (var item in Model.Approvals)
{
<tr>
<td>#item.ApprovalReviewer</td>
.
.
.
.
<td>
<button asp-action="Approve" asp-route-id="#item.Key" asp-controller="Dashboard">Approve
</button>
</td>
<td><input asp-for="Approval.ChangeReviewer" value="#item.ChangeReviewer"/></td>
}
it looks like this, I can add a row and delete one, no issue there everything is working
so basically you enter a name in the reviewer input and when you press approve then that name is updated for the correct key. The issue I have is that I can't find a way to bind that input to the button.
[HttpPost]
public IActionResult Approve(int? key, Global obj)
{
var objToApprove = _db.ApprovalTable.Find(key);
objToApprove.ChangeApproved = true;
objToApprove.ChangeApprovalDate = DateTime.Now;
objToApprove.ChangeReviewer = obj.Approval.ChangeReviewer;
objToApprove.ChangeSigned = obj.Approval.ChangeReviewer;
_db.ApprovalTable.Update(objToApprove);
_db.SaveChanges();
return Redirect(Url.Action("ECR", new { id = obj.Approval.ECRNumber }) + "#2"); //TAB #2 FORM APPROVAL
}
what I need is the value of the input on the same row as the button... sounds easy...I guess not for me..

I don't know if this is the right way of doing it but I was able to solve my problem like this:
I replaced the Foreach loop to a regular loop so that each control would have its own index. Then I passed to the controller the index i so I could get the correct value in the controller.
So it looks like this:
#for (int i = 0; i < Model.Approvals.Count() - 1; i++)
{
The button where I pass the index i to the controller
<button class="---" asp-action="Approve" asp-route-key="#Model.Approvals[i].Key" asp-route-index="#i" asp-route-ecr="#Model.Approvals[i].ECRNumber" asp-controller="Dashboard">Approve</button>
and finally the controller where I can retrieve the variable
[HttpPost]
public IActionResult Approve(int? key, Global obj, int? ecr, int index)
{
var objToApprove = _db.ApprovalTable.Find(key);
objToApprove.ChangeApproved = true;
objToApprove.ChangeApprovalDate = DateTime.Now;
objToApprove.ChangeReviewer = obj.Approvals[index].ChangeReviewer;
objToApprove.ChangeSigned = obj.Approvals[index].ChangeReviewer;
_db.ApprovalTable.Update(objToApprove);
_db.SaveChanges();
return Redirect(Url.Action("ECR", new { id = ecr }) + "#2");
}
I have 2 weeks of experience in asp.net so it is hard to know if there is a much better and elegant way of doing this but it works. So it seems that after all I was not there for a "code writing service"...

Related

How can I send a list in BeginForm()?

Can someone please help me with this problem? At the bottom of my view just before the page loads I create an array of checkboxes like this:
foreach (var course in courses.Select((x, i) => new { Data = x, Index = i }))
{
int currentIndex = course.Index;
String selectedday = "";
String selectedteacher = "";
if (cnt++ % 4 == 0)
{
#: </tr> <tr>
}
#: <td >
<br /><br /><br />
<input type="checkbox" id="checkbox"
name="selectedCourses"
value="#course.Data.CourseID"
#(Html.Raw(course.Data.Assigned ? "checked=\"checked\"" : ""))
/>
I use the same loop to add the assigned state to a list like this:
bool theNewString=course.Data.Assigned ;
String a=theNewString.ToString();
assignedCourses.Add(a);
I defined a list variable at the top of the page so that it can be accessed by the form-wide like this:
#{List<String> assignedCourses =new List<String>(); }
Now I want to send that variable to the controller and this is where things get muddy. If I send a string like this it works fine:
Razor markup
String postedData = "literalString";
#using (Html.BeginForm("Action", "Controller", new { assigned = # postedData }))
Action
[HttpPost]
public ActionResult Edit(int id,List<String> assigned){}
Now if I try this:
#{List<String> assignedCourses =new List<String>(); }
#using (Html.BeginForm("Action", "Controller", new { assigned = #assignedCourses }))
And nothing comes through to the controller. It’s like the list is emptied just before posting. How can send my list to the controller?
I think the way you are trying to create the query string/postback url for the form using the list is wrong and will not produce a properly formatted string.
Maybe try something like this:
#{
List<string> ExampleList = new List<string>();
ExampleList.Add("True");
ExampleList.Add("False");
string param = string.Join("&", ExampleList.ToArray());
}
#using (Html.BeginForm("index", "home", new { #someparam = (new HtmlString(param)) })) { }
This would require you to split the single string up into an array when the action method receives it.
alternatively you can try using RouteValueDictionary instead of list, but this does not support duplicate keys.
Also for checkbox creation try using #Html.CheckBox() as this will automatically create a second hidden input set to false. HTML Forms don't post back checkbox values when they are unchecked, so the second hidden input with the same name will be posted back and you will know it has been unchecked or not checked. MVC will interpret values of "True, False" for the same form key/input name as True and False when just the hidden input with the "False" value is posted back.

ReportViewer resets parameters after submit

I'm showing a remote report in a ReportViewer control. The report loads with a few default parameters. So far everything is ok.
But when i change a few input values and hit View Report then the report simply shows the data with the default values. The parameters that i changed in the input fields are also reset.
All the code i have is this:
apsx
<rsweb:ReportViewer ID="ReportViewer1" runat="server" Font-Names="Verdana"
Font-Size="8pt" Height="642px" ProcessingMode="Remote" Width="100%">
<ServerReport ReportPath="http://server.com/Product/Dashboards/test.rdl"
ReportServerUrl="http://server.com/ReportServer" />
</rsweb:ReportViewer>
The CodeBehind is basically empty. All it has now is an empty Page_Load.
That is all my code.
But it feels like a ViewState issue? But I am not sure where to look.
Anyone any idea why the parameters are resrt when I press on the View Report button?
I solved this by setting the parameters myself in the Code Behind. So when the report is submitted, i then get all the entered data, put that in a ReportParameters collection.
But unfortunately this wasn't as easy and straight forward as one would think. At first you might think this is stored in: YourReport.ServerReport.GetParameters(). But that is not the case!
To get the submitted values from your report you can use the following code:
Get report submitted parameters
public ReportParameter[] GetCurrentParameters(Microsoft.Reporting.WebForms.ReportViewer viewer)
{
Control params1Area = FindParametersArea(viewer);
List<ReportParameter> params1 = new List<ReportParameter>();
FindParameters(params1Area, params1);
return params1.ToArray();
}
private Control FindParametersArea(Microsoft.Reporting.WebForms.ReportViewer viewer)
{
foreach (Control child in viewer.Controls)
{
if (child.GetType().Name == "ParametersArea")
return child;
}
return null;
}
private void FindParameters(Control parent, List<ReportParameter> params1)
{
Type _ParameterControlType = System.Reflection.Assembly.GetAssembly(typeof(Microsoft.Reporting.WebForms.ReportViewer)).GetType("Microsoft.Reporting.WebForms.BaseParameterInputControl");
ReportParameter param;
Microsoft.Reporting.WebForms.ReportParameterInfo paramInfo;
String[] paramValues;
foreach (Control child in parent.Controls)
{
if (_ParameterControlType.IsAssignableFrom(child.GetType()))
{
paramInfo = (Microsoft.Reporting.WebForms.ReportParameterInfo)GetPropertyValue(child, "ReportParameter");
if (paramInfo == null)
continue;
paramValues = (string[])GetPropertyValue(child, "CurrentValue");
if (paramValues != null && paramValues.Length > 0)
{
param = new ReportParameter();
param.Name = paramInfo.Name;
param.Values.AddRange(paramValues);
params1.Add(param);
}
}
FindParameters(child, params1);
}
}
public object GetPropertyValue(object target, string propertyName)
{
return target.GetType().GetProperty(propertyName, System.Reflection.BindingFlags.IgnoreCase | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public).GetValue(target, null);
}
Source: http://forums.asp.net/t/1057747.aspx/1 (Also Visual Basic examples)
You invoke those methods by just using the following line of code. Preferably in a if(IsPostBack) scope within your Page_Load for example.
ReportParameter[] reportParameters = GetCurrentParameters(ReportViewer1);
It is then possible to overwrite the submitted values if you also have custom textfields. You can easily do that like so:
reportParameters[4] = new ReportParameter("year", "2013", true);
You obviously have to know what param is stored at index 4. But you could also make an easy lookup function that searches for the reportParameter with a specific name. So in my case year.
Simple parameter lookup
protected void ChangeParameterValue(String name, String newValue, ref ReportParameter[] parameters)
{
foreach (ReportParameter param in parameters)
{
if (String.Equals(param.Name, name))
{
param.Values[0] = newValue;
break;
}
}
}
You use that like so:
ChangeParameterValue("year", "2013", ref reportParameters);
This way you don't have to worry about at what index a certain parameter is placed.

How can I populate the pull down menu using data from a database?

I keep on getting this error message.InvalidCastException was unhandled by the user, Unable to cast object of type 'System.Int32' to type 'System.String'.
I've been told the view data value for bloodtype is not correct. Just trying to figure out how to determine the value.
I'm new to asp.net therefore don't understand too much at the moment.
<select name="bloodtype">
<% List<Hospital.bloodtype> bloodtypeList = (List <Hospital.bloodtype>) ViewData["bloodtypeList"];
foreach (Hospital.bloodtype st in bloodtypeList)
{
%>
<option value="="<%= st.bloodcode%>"><% *if (st.bloodcode==(String) ViewData["bloodtype"])* Response.Write("Selected"); %><% Response.Write(st.meaning);%>></option>
<% } %>
<option value="0" <% if ((Int32) ViewData["bloodtype"]==0) Response.Write("Selected");%>>
</option>
public void HospitalInit()
{
hospitalSQLEntities db = new hospitalSQLEntities();
ViewData["bloodtypeList"] = db.bloodtypes.ToList();
ViewData["patientid"] = "";
ViewData["patientname"] = "";
ViewData["bloodtype"] = 0;
ViewData["junk"] = "";
ViewData["spam"] = "";
ViewData["comments"] = "";
ViewData["formmessage"] = "";
}
public ObjectSet<bloodtype> bloodtypes
{
get
{
if ((_bloodtypes == null))
{
_bloodtypes = base.CreateObjectSet<bloodtype>("bloodtypes");
}
return _bloodtypes;
}
}
The best way to do this is to define a list of bloodtypes in your code behind like:
private List<bloodtype> _bloodtypes = new list<bloodtype>();
Next, you can use an ASP.NET combobox control that you place on your page and to which you databind the specified list (also in the code behind), like so:
public void PageLoad(){
_bloodtypes = GetBloodTypes();
myCombobox.DataSource = _bloodtypes;
myCombobox.DataBind();
}
private IList<bloodtype> GetBloodTypes(){
// Get some bloodtypes
return new List<bloodtype>();
}
Of course, before databinding, you need to fill the list (as seen above).
Instead of casting use convert
Convert.ToInt32(ViewData["bloodtype"])

Using Html.DropDownListFor() with a SelectList

What is the correct way to populate a SelectList when using the Html.DropDownListFor helper in ASP.Net MVC 3?
I basically have a "Create" form which I want to specify the entry values on for a particular field. For example, it is a movie database and I want the ability to enter a Genre, but I don't want users to be able to enter what they like, so I assume a SelectList to be the best answer?
A way that works is to create a new class with a static method to return the SelectList:
public class Genres
{
public static List<string> GetGenres()
{
List<string> myGenres = new List<string>();
myGenres.Add("Comedy");
myGenres.Add("Romantic Comedy");
myGenres.Add("Sci-Fi");
myGenres.Add("Horror");
return myGenres;
}
}
Which can then be used like this:
<div class="editor-field">
#Html.DropDownListFor(model => model.Genre, new SelectList(OLL.Models.Genres.GetGenres()))
</div>
It just doesn't seem like the right/easiest way to do it? I think I'm missing something obvious here...
Thanks for any assistance you can provide.
This is a simple selectList style I use for drop downs all the time, hopefully you find this helpeful.
ViewBag.AlbumListDD = from c in db.Query<DatabaseEntities.VenuePhotoAlbum>("WHERE VenueId = #0", VenueId)
select new SelectListItem
{
Text = c.Name,
Value = c.Id.ToString()
};
Inside my view:
#Html.DropDownList("AlbumId", (IEnumerable<SelectListItem>)ViewBag.AlbumListDD, new { id = "ChangeAlbum" })
Hopefully you can find this useful as this is a database route to go. I typically like to have all of that sort of information in a database and that way users can dynamically add/remove and change these dropdown items at will. There is a bit of SQL work behind the scenes required when removing a type but it has proven to be very successful and fast for me at this point.
var og = (from s in DB.Products
select new SelectListItem
{
Text = s.ProductName,
Value = s.ProductID.ToString()
});
ViewBag.lstProducts = new SelectList(getproductname, "ProductID", "ProductName");
<p>
#Html.DropDownList("AlbumId", (IEnumerable<SelectListItem>)ViewBag.lstProducts, new { #id = "drp" });
</p>

enable html dropdown through controller in mvc

i have an scenario where i have to perform some action according to selection of the
dropdown .
for basic refrence you can use the example of country,state,city.
i am able to populate the country list at that time i have set the other two drop downs to
disable.
after the countries are populated i want to select the state.it is getting populated .
two problems
1) how to retain the state of country ddl as it is coming back to its orisnal state.
2) how to enable the drop down through my controller.
myview code
Country
<p>
<label>
State</label>
<%=Html.DropDownList("ddlState", ViewData["ddlState"] as SelectList, "--not selected--",new { onchange = "document.forms[0].submit()", disabled = "disabled" })%>
</p>
<p>
<label>
City</label>
<%=Html.DropDownList("ddlCities", ViewData["ddlCities"] as SelectList, "--not selected--", new { onchange = "document.forms[0].submit()", disabled = "disabled" })%>
</p>
my controller code
public ActionResult InsertData()
{
var customers = from c in objDetailEntity.Country
select new
{
c.Cid,
c.Cname
};
SelectList countriesList = new SelectList(customers.Take(100), "Cid", "Cname");
ViewData["ddlCountries"] = countriesList;
SelectList EmptyState = new SelectList(customers);
ViewData["ddlState"] = EmptyState;
ViewData["ddlCities"] = EmptyState;
Session["ddlSesCountry"] = countriesList;
return View();
}
//
// POST: /RegisTest/Create
[HttpPost]
public ActionResult InsertData(FormCollection collection)
{
try
{
CountryId = Convert.ToInt16(Request.Form["ddlCountries"]);
stateid = Convert.ToInt16(Request.Form["ddlState"]);
if (CountryId > 0 && stateid <= 0)
{
var stateslist = from c in objDetailEntity.State
where c.Country.Cid == CountryId
select new
{
c.Sid,
c.Sname
};
SelectList stateList = new SelectList(stateslist.Take(100), "Sid", "Sname");
ViewData["ddlState"] = stateList;
Session["StateList"] = stateList;
ViewData["ddlCities"] = stateList;
}
if (stateid > 0)
{
var citieslist = from c in objDetailEntity.City
where c.State.Sid == stateid
select new
{
c.Ctid,
c.Cityname
};
SelectList cityList = new SelectList(citieslist.Take(100), "Ctid", "Cityname");
ViewData["ddlCities"] = cityList;
ViewData["ddlState"] = Session["StateList"];
}
ViewData["ddlCountries"] = Session["ddlSesCountry"];
return View();
}
catch
{
return View();
}
}
My choice would be not to post back the form at all. I would write an action in the controller that takes a CountryID and returns a JsonResult holding a list of states. The onchange event could call a jQuery function that uses AJAX to call this action, loads the new list, and enables the second drop-down list.
However, if you stick with the postback, here's why it's not working:
The Country list isn't retaining its selected value because the view is being reloaded from scratch each time and you're setting it to "not selected." The SelectList constructor has an overload that takes a "SelectedItem" object as the fourth parameter. When you initialize your SelectList, you should pass the appropriate value to this parameter, and not force it in the View.
You need to write an "if" clause in your View to choose whether or not to enable the list based on some criteria. You could bind to a ViewModel that has a Boolean property like "EnableStates," or you could use something like the count of values in the StateList - if the count is greater than zero, enable it, for example.
A tricky thing to get used to when you move from Web Forms to MVC is that you don't have ViewState anymore - your application is stateless. There's nothing that "remembers" what value is selected in a drop-down for you, you have to set it each time you load the page.
I recommend using JSON & jQuery - like this posted answer.

Resources