mvc3 html.Dropdownlist() and html.beginform() - asp.net

Hi guys I have a dropdownlist and a submit button in my view.
I want the user to be able to select an item in the dropdownlist that calls an action method in the controller that gets data from the database.
I also have a button and I want the user to be able to select a checkbox in a grid and click the submit button to pass the value of the checkbox to an action method in the controller.
The problem is when I select an item from the dropdownlist it calls the action method for the submit button "DiscontinueProduct" and
not the action method for the dropdownlist ("GetProductByID"), can someone please tell me what I'm doing wrong?
Here is a my code.
Thanks in advance.
=============
view
<div>
#Using Html.BeginForm("GetProductByID", "Product")
#Html.DropDownList("CategoryID", DirectCast(ViewData("Categories"), SelectList), " -- Choose One -- ", New With {Key .onchange = "$('form').submit();"})
End Using
</div>
#Using Html.BeginForm("DiscontinueProduct", "Product")
#<text>
<table>
<tr>
<th></th>
<th>ProductName</th>
<th>SupplierID</th>
<th>CategoryID</th>
<th>Discontinued</th>
</tr>
#For Each item In Model
#<tr>
<td>
#Html.ActionLink("Edit", "Edit", New With {.id = item.ProductID}) |
#Html.ActionLink("Details", "Details", New With {.id = item.ProductID}) |
#Html.ActionLink("Delete", "Delete", New With {.id = item.ProductID})
</td>
<td>#item.ProductName</td>
<td>#item.SupplierID</td>
<td>#item.CategoryID
<input type="checkbox" name="task" id="isTaskSelected" value=" #item.CategoryID.ToString() " />
</td>
<td>#item.Discontinued</td>
</tr>
Next
</table>
<div id="btncomplete" style="display: none">
<input type="submit" value="Discontinue" />
</div>
</text>
End Using
=====================
Controller
Function GetProductByID(ByVal id As Integer) As ActionResult
Dim cquery2 = From product In db.Products
Where product.CategoryID = id
viewmodel.ProductList = cquery2.ToList()
Return PartialView("Products", viewmodel.ProductList)
Return PartialView("Products", viewmodel.ProductList)
End Function
<HttpPost()> _
Function DiscontinueProduct(ByVal collection As FormCollection) As ActionResult
Try
' Code to update product field as discontinue.
Return RedirectToAction("Index")
Catch
Return View()
End Try
End Function

It seems that you have to prevent the SUBMIT action for your drop-down list. Have a look here How to prevent buttons from submitting forms

Related

ASP.NET Editable Grid: Update register

I've been struggling with this for a while now. I'm constructing this view:
But when I hit the 'Update' button after do some changes the web refreshes to show the original values.
About the view: I get this view using an IEnumerable and looping thru each item in the model inside a form. Then, inside the form, there is a table that contains only 1 row. I do this in order to wrap all the items of the record in one form. This is part of code:
#foreach (var item in Model)
{
<form asp-action="Test" asp-route-id="#item.Id">
<table class="table">
<tbody>
<tr>
<td>
<input type="hidden" asp-for="#item.Id" />
<div class="form-group">
<div class="col-md-10">
<input asp-for="#item.MchName" readonly class="form-control" />
<span asp-validation-for="#item.MchName" class="text-danger"></span>
</div>
</div>
</td>
//more fields
<td>
<input type="submit" value="Update" class="btn btn-default" />
</td>
</tr>
</tbody>
</table>
</form>}
I declare an asp-action and a asp-route-id:
<form asp-action="Test" asp-route-id="#item.Id">
Question: Is this good enough? Is there something missing?
This is the Get Method:
public async Task<IActionResult> Test()
{
PopulateMachineTypeDropDownListStore();
return View(await _context.Machines.AsNoTracking().ToListAsync());
}
Question: I'm not passing any argument to the controller, yet the view will list the items following the given structure using an IEnumerable. Should I pass anything to the Get Method or is it fine as it is?
This is the Post Method:
#model IEnumerable<Application.Models.Machine>
[HttpPost, ActionName("Test")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> TestPost(int? id)
{
if (id == null)
{
return NotFound();
}
var machinetoUpdate = await _context.Machines
.SingleOrDefaultAsync(s => s.Id == id);
if (await TryUpdateModelAsync(
machinetoUpdate,
"",
s => s.MchName, s => s.StoreID, s => s.PUnit, s => s.Status))
{
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateException)
{
ModelState.AddModelError("", "Unable to save changes. " +
"Try again, and if the problem persists, " +
"see your system administrator.");
}
return RedirectToAction("Test");
}
PopulateMachineTypeDropDownListStore();
return View(await _context.Machines.AsNoTracking().ToListAsync());
}
Question: I don't know if because the entity I retrieve the id from (and that I use to update the model thru TryUpdateModelAsync()) is also being used to compare to the model that thru the view this might not been working properly.
Thanks in advance for any help.

How to use Hidden fields in HTML5 asp.net mvc 4?

I am working on a MVC 4 asp.net application(vb.net project)
<table>
<tr><td>Billable item</td><td>#Html.DropDownList("RteBillableItem") </td><td>Quantity</td><td>#Html.TextBox("Quantity")</td></tr>
<tr><td>Doctor Fee</td><td>#Html.TextBox("DoctorFee")</td><td>Hospital Fee</td>
<td>#Html.TextBox("HospitalFee")</td></tr>
<tr><td></td><td></td><td></td><td><input type="submit" id="AddItem" value="Add Item" /></td></tr>
</table>
As seen in the image, i will be selecting an item from the drop down list, enter some data in the text boxes, and click on the button "Add Item", the form will do a post back.
The code in post back controller is :
HttpPost()
Function Index(ByVal Collection As FormCollection, ByVal Hidden As HiddenField) As ActionResult
Dim Test As New TestModel
Test.Update(CodeFactory(item), CInt(Collection("Quantity")),CInt(Collection("DoctorFee")), CInt(Collection("HospitalFee")))
//This will add the Item in a dictionary which i have used in my ModelTest
Return View(Test)
End Function
After adding the Item into my dictionary, i will send this model to "View", where i have to list the values in a table, picking the values from Dictionary of TestModel. The code for listing the values in View is:
#For Each item In Model
Dim currentItem = item
#<tr>
<td>
#Html.DisplayFor(Function(modelItem) currentItem.BillableItemId)
</td>
<td>
#Html.DisplayFor(Function(modelItem) currentItem.BillableItemName)
</td>
<td>
#Html.ActionLink("Edit", "Edit", New With {.id = currentItem.OpBillId}) |
#Html.ActionLink("Details", "Details", New With {.id = currentItem.OpBillId}) |
#Html.ActionLink("Delete", "Delete", New With {.id = currentItem.OpBillId})
</td>
</tr>
next
</table>
But the thing is , whenever i do a post back, all the previous data which i have added in the dictionary of TestModel is lost. I know that i am re-initializing my Test object of the model, TestModel.
I think i have to use Hidden fields, to retain the old data of TestModel, even after PostBack.
But i do not know how to do it, please give your valuable suggestions.

ASP.NET MVC: on button click, call display multiple ActionResults in different windows

I have a form that has a drop-down list of values and a submit button.
Currently, when you click on the submit button, a stored procedure is called and then the application generates a url and then the ActionResult is a Redirect to a new window. The url is based on the currently selected value in the dropdown list.
Our client wants another button that when clicked, will basically do the same thing, but FOR ALL VALUES in the drop down list.
Basically, on click, multiple windows will be opened, whose urls each based on a value in the drop down list.
I just started working with MVC and research confused me even more. I'm hoping someone can point me in the right direction.
Should I handle this via some sort of loop in javascript? How? Can you give some examples, please?
ASPX Portion:
<div id="MyContainer" class="select-report">
<%
using (Html.BeginForm(MyManager.Query.Actions.GenerateReport(null), FormMethod.Post, new{target="_blank"}))
{%>
<select name="SearchText" class="my-values-select">
<% foreach (var cc in Model.MyCentresList)
{%>
<option value="<%=Html.Encode(cc.Name) %>">
<%=Html.Encode(cc.Name) %></option>
<% } %>
</select>
<input type="hidden" name="SearchType" value="MyCentre" />
<input type="submit" value="Generate" name="EntityName" />
<% } %>
</div>
Code-Behind:
public virtual ActionResult GenerateReport(GenerateReportOperation operation)
{
string entityName = operation.SearchText;
int entityType = (int)operation.SearchType;
string requestID1 = <code here that calls a stored procedure, a value is returned>;
string requestID2 = <code here that calls a stored procedure, a value is returned>;
string urlString = <code here that contructs the URL based on the values of entityName, entityType, requestID1, requestID2>;
return Redirect(urlString);
}
You would have to use JavaScript to open new windows for each individual HTTP request.

send id from view to controller

I have a view that receives a Model and displays info of that model.
I have a submit button and when it is clicked i want it to send the id to the method to process it and delete a row that has such id.
How can I do this? I want to use a button not an html link like
#Html.ActionLink("Delete", "Delete", new { id = Model.Id }) |
Thanks!
I tried input type hidden but hasn't worked =(
You can use a form to do this... I don't use razor, but an equivalent .aspx way to do this would be:
<%using (Html.BeginForm("Home", "myaction", new { Id = 1 }))
{ %>
<input type="submit" value="submit" />
<%} %>
This will post to ~/Home/myaction/1
Just call Html.BeginForm with the appropriate razor syntax.

FindControl method cannot locate the control on the page

Ive tried searching for hours now and cannot find out why my code (aka, me.) is failing
Basically... I have a listview control which I'm passing a datatable of products (ID, Name, Description and Price columns), and im trying to make it so that when the "checkout" button is pressed, it parses through all the controls on the page, finds all the controls with the correct ID's and adds the items values to the cart.
ive checked all my ID's in the source code and they match up to the ones being requested by the FindControl method.
the error getting thrown back is:
Object reference not set to an instance of an object.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Line 21: For I = 1 To counter
Line 22: Dim cartItem As New Core.Types.CartItem
Line 23: cartItem.Name = CType(productsContainer.FindControl("product" + I.ToString()), HtmlGenericControl).InnerText
Line 24: cartItem.Quantity = Convert.ToInt32(CType(productsContainer.FindControl("quantity" + I.ToString()), HtmlSelect).Value)
Line 25: cartItem.Price = Convert.ToDecimal(CType(productsContainer.FindControl("price" + I.ToString()), HtmlGenericControl).InnerText.Remove(0, 1))
my .aspx code:
<div class="productsContainer" id="productsContainer" runat="server">
<asp:ListView runat="server" ID="lsvProducts">
<LayoutTemplate>
<ul class="lsvProducts">
<li class="highlight">
<div class="productName">
Product
</div>
<div class="productQuantity">
Number of Licenses
</div>
<div class="productPrice">
Price
</div>
</li>
<asp:PlaceHolder ID="itemPlaceHolder" runat="server"></asp:PlaceHolder>
</ul>
</LayoutTemplate>
<ItemTemplate>
<li>
<div style="display: none;">
<%=setCurrent()%>
</div>
<input type="hidden" id='productID<%#Eval("ID")%>' />
<div class="productName" id='product<%=currentItem%>'>
<%#Eval("Name")%>
</div>
<div class="productQuantity">
<select id='quantity<%=currentItem%>'>
<option selected="selected"
value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
</select>
</div>
<div class="productPrice" id='price<%=currentItem%>'>
<%#"$" + Convert.ToDouble(Eval("Price")).ToString()%>
</div>
</li>
</ItemTemplate>
</asp:ListView>
</div>
<div class="clearer">
</div>
<div class="purchaseButton">
<asp:Button ID="btnAddCart" runat="server" Text="Add to Cart" />
</div>
</div>
and my code behind:
Dim counter As Int32
Public currentItem As Int32
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
'get all active products to display in the listing
Dim query As String = "SELECT * FROM Products WHERE Active = 1"
Dim dt As DataTable = DAL.Data.GetDataTable(query, "MainDB")
counter = dt.Rows.Count
lsvProducts.DataSource = dt
lsvProducts.DataBind()
End Sub
Protected Sub btnAddCart_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnAddCart.Click
'create a new instance of the cart
Dim cart As New Core.Types.Cart
'foreach item in the listing, find its details and add it to the shopping cart
For I = 1 To counter
Dim cartItem As New Core.Types.CartItem
cartItem.Name = CType(productsContainer.FindControl("product" + I.ToString()), HtmlGenericControl).InnerText
cartItem.Quantity = Convert.ToInt32(CType(productsContainer.FindControl("quantity" + I.ToString()), HtmlSelect).Value)
cartItem.Price = Convert.ToDecimal(CType(productsContainer.FindControl("price" + I.ToString()), HtmlGenericControl).InnerText.Remove(0, 1))
cartItem.ID = Convert.ToInt32(CType(productsContainer.FindControl("productID" + I.ToString()), HtmlGenericControl).InnerText)
cart.AddItem(cartItem)
Next
If (cart.isEmpty) Then
'empty cart, go nowhere. show a message saying the carts empty and to choose something.
Else
Response.Redirect("~/Checkout.aspx")
End If
End Sub
Public Function setCurrent()
currentItem = currentItem + 1
Return currentItem
End Function
Please help... this is driving me insane!
Thanks in advance :)
If you're in a datagrid/ repeater/ listview, to use the "FindControl" method, you'll have to iterate through the data items in the list view, then for each item peform the find control method. e.g. in C#:
foreach(RepeaterItem item in Repeater1.Items)
{
Literal lit = (Literal)item.FindControl("controlId");
}
I'm not sure thats the exact syntax but you get what I mean. You can't just use the find control method on the listview Id - the Ids of server controls in each item get re-written because you're looping through a collection...
Cheers, Sean
FindControl only looks in the current naming container. If you wish to find controls from a different naming container, you should have your own (recursive) implementation. For example:
private Control FindControlRecursive(Control parent, string id)
{
Control controlFound = parent.FindControl(id);
int i = 0;
while (controlFound == null && i < parent.Controls.Count)
{
controlFound = FindControlRecursive(parent.Controls[i++], id);
}
return controlFound;
}
After that use FindControlRecursive(productsContainer, "product" + I.ToString())
It looks like your nested controls are just basic Html controls? I'm not sure they'll be registered with ASP.NET unless you have runat="server" to register them as server-side controls.
It's been a while since I've done heavy ASP.NET dev, but in my prior experience we always used server-side controls and had no problems.
The other thing I noticed was that if your ContentPlaceHolder for a child page is nested inside a LoggedInTemplate inside a LoginView on a masterpage, then you can forget about using FindControl to grab the handle on a control inside the child page.

Resources