From the menu page a user clicks an "Add to Order" button. The "Add to Order" button triggers the addToOrder function. That function works correctly, the drink is passed and an order is created with the drink information. After clicking the "Add to Order" button the user is sent to a confirmation page where their drink order is displayed and takes in their name in a form. The information passes correctly to the confirmation page, however when the form on the confirmation page is submitted the drink information is not passed but the rest of the form is. Any suggestions on how to get the drink information to pass in the object is greatly appreciated!
In the Home Controller:
From the menu page, this gets the drink information and works correctly:
[HttpGet]
public ActionResult addToOrder(int id)
{
Drink drinkToAdd = _drinkRepository.GetDrink(id);
List<Drink> dList = new List<Drink>();
dList.Add(drinkToAdd);
Order order = new Order();
order.drinkList = dList;
order.total = drinkToAdd.drinkPrice;
ViewData.Model = order;
return View("OrderConfirmation");
}
This method gets the information from the form in the order confirmation page:
[HttpGet]
public ActionResult confirmedOrder(Order order, int drinkID)
{
Drink drinkToAdd = _drinkRepository.GetDrink(drinkID);
List<Drink> dList = new List<Drink>();
dList.Add(drinkToAdd);
order.drinkList = dList;
_orderRepository.Add(order);
return View("ThankYou");
}
This is the order confirmation page:
#model BartenderApp.Models.Order
#{
ViewData["Title"] = "Order Confirmation";
}
<html>
<body>
<h1>Order Confirmation</h1>
<form asp-action="confirmedOrder" method="get" >
<p>#Html.DisplayNameFor(m => m.FirstName): #Html.TextBoxFor(m => m.FirstName)</p>
<p>#Html.DisplayNameFor(m => m.LastName): #Html.TextBoxFor(m => m.LastName)</p>
<table class="table">
<thead>
#foreach (var item in Model.drinkList)
{
<tr>
<td>
#Html.HiddenFor(modelItem => item.id)
</td>
<td>
<b>#Html.DisplayNameFor(modelItem => item.drinkName)</b>
</td>
<td>
<b> #Html.DisplayNameFor(modelItem => item.drinkDescription)</b>
</td>
<td>
<b> #Html.DisplayNameFor(modelItem => item.drinkPrice)</b>
</td>
</tr>
}
</thead>
<tbody>
#foreach (var item in Model.drinkList)
{
<tr>
<td>
#Html.HiddenFor(modelItem => item.id, new { drinkID = item.id } )
</td>
<td>
#Html.DisplayFor(modelItem => item.drinkName)
</td>
<td>
#Html.DisplayFor(modelItem => item.drinkDescription)
</td>
<td>
#Html.DisplayFor(modelItem => item.drinkPrice)
</td>>
</tr>
}
</tbody>
</table>
<p style="float:left">#Html.ActionLink("Modify Order", "Menu")</p>
<p style="float:right"><b>#Html.DisplayNameFor(m => m.total):</b> $#Html.DisplayFor(m => m.total)</p>
<input type="submit" value="Checkout" name="checkout" style="float:right" />
</form>
</body>
</html>
When I hit the submit button on the form I thought the entire object would pass but only the first and last name are. I have tried to then pass the specific drinkID so I could locate it in the repository and add it to the order. However, the drinkID is not passing either (always 0). Why is the drink information not passing with the rest of the object?
Thanks
This is the URL after I hit the submit button on the order confirmation page:
https://localhost:44378/Home/confirmedOrder?FirstName=John&LastName=Jones&item.id=1&item.id=1&checkout=Checkout
In this example, I did add the drink with the ID of 1 to my order. There is also another order in the repository, so the ID of the order is 2.
Related
I have a view of List type and Model has a selectList which on change should change the actionLink parameter.
I have tried using a form and posting all the contents of the model to the controller but it does not work.
This is part of the view
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.coursenumber)
</td>
<td>
#Html.DisplayFor(modelItem => item.coursename)
</td>
<td>
#Html.DisplayFor(modelItem => item.coursescopename)
</td>
<td>
#Html.DisplayFor(modelItem => item.avetmiss)
</td>
<td>
#Html.DropDownListFor(modelitem => item.InvoiceOptionsId, item.InvoiceOptionsList, "--select--", new {#class = "form-control", id = "ddl" + item.coursenumber})
</td>
<td>
#Html.ActionLink("Events","Events",new{id= item.coursenumber,priceKey = item.InvoiceOptionsId})
</td>
</tr>
}
The priceKey is calculated from the dropdownlist.
You need to use javascript/jquery to handle client side events. One option would be to modify the html to (assumes a for loop - see notes below)
<td>
#Html.DropDownListFor(m => m[i].InvoiceOptionsId, Model[i].InvoiceOptionsList, "--select--", new { #class = "form-control" })
</td>
<td>
Events
</td>
Then add the following script (requires jquery{version}.js)
$(function() {
var url = '#Url.Action("Events")';
$('.event').click(function() {
var id = $(this).data('id'); // get the items id
var priceKey = $(this).closest('tr').find('select').val(); // get the value of the associated dropdown
location.href = url + '?id=' + id + '&priceKey=' + priceKey; // redirect
});
});
Note: Its not clear if the code you have shown is part of a form that you post back, but if so, you need to use a for loop (or custom EditorTemplate) to generate the form controls. Using a foreach loop generates duplicate name attributes (without indexers) which will not bind to your model when you post the form.
how can i get the querystring id in there? is there any way
#using (Html.BeginForm("InformVendor", "Procurement",new {id="querystring Mode = "Inform" }, FormMethod.Post))
{
<tr>
<td>
#Html.DropDownListFor(m=>m.VendorId,new MultiSelectList(Model.VendorDropdownlist, "CustomerId", "ContactName"))
</td>
<td>
#Html.CheckBoxFor(m => m.IsEmail)
</td>
</tr>
<tr>
<td>
<input type="submit" id="btnsubmit" value="Nominate Vendor" />
</td>
<td></td>
</tr>
}
The easiest way is to have your id field be hidden. This way the user doesn't see the ID field but your post back controller does.
#Html.HiddenFor(x => x.YourID)
If you add the Id to your view model and render it as a hidden field.
#Html.HiddenFor(m => m.Id)
You will be able to retrieve it like this instead of using the querystring.
public ActionResult InformVendor(AViewModel model)
{
var Id = model.Id;
}
I am new bee to Asp.net. I like to pass an id of an entity to edit method in controller through view. Here is my code.
#
#model IEnumerable<Login.DAL.tabLogin>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<div id="work_area">
</div>
<table>
<tr>
<th>
Username
</th>
<th>
Password
</th>
<th>
Email
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Username)
</td>
<td>
#Html.DisplayFor(modelItem => item.Password)
</td>
<td>
#Html.DisplayFor(modelItem => item.Email)
</td>
<td>
Edit|
#Html.ActionLink("Details", "Details", new { id=item.UserID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.UserID })
</td>
</tr>
}
</table>
<script type="text/javascript" language="javascript">
function editUser(idval) {
alert(idval);
$('#work_area').load('#Url.Action("Edit","Home", new RouteValueDictionary(new { id = idval}))');
}
</script>
I did not get the correct functionality .
$('#work_area').load('#Url.Action("Edit","Home", new RouteValueDictionary(new { id = 1}))');
If I hard code the id value as above , It is working as expected. Please help me on this.
The problem is that you're mixing Razor and JavaScript and don't have an understanding of what happens where/when. The line of code:
$('#work_area').load('#Url.Action("Edit","Home", new RouteValueDictionary(new { id = 1}))');
will render as a completed URL before the javascript is rendered. That means, once the page is loaded by the browser, that line already says:
$('#work_area').load('http://example.com/home/edit/1');
and will never change based on javascript. To get the javascript parameter into your URL, you'll have to combine the URL from Razor with a javscript parameter. Try something like:
function editUser(idval) {
alert(idval);
var baseUrl = '#Url.Action("Edit","Home")';
$('#work_area').load(baseUrl + '/' + idval);
}
Right now I have the following code:
#model IEnumerable<MvcAuction.Models.Furniture>
#{
ViewBag.Title = "Search";
}
<hgroup class="title">
<h1>#ViewBag.Title.</h1>
</hgroup>
#using (Html.BeginForm("SearchIndex", "Furniture", FormMethod.Get))
{
<p>
Description: #Html.TextBox("SearchString")
<input type="submit" value="Search" /></p>
}
<table class="searchResults">
<tr>
<th>
#Html.DisplayNameFor(model => model.Description)  
</th>
<th>
#Html.DisplayNameFor(model => model.EndingDate)  
</th>
<th>
#Html.DisplayNameFor(model => model.Category)
</th>
<th>
#Html.DisplayNameFor(model => model.Price)
</th>
<th>
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
<td>
#Html.DisplayFor(modelItem => item.EndingDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.Category)
</td>
<td>
#Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<button data-bind="click: toggleBidInput ">
<span data-bind="text: bidCancel"></span>
</button>
</td>
<td>
<input data-bind="visible: bidInputVisible" />
<button data-bind="visible: bidInputVisible">
Submit</button>
</td>
</tr>
}
</table>
#section Scripts{
#Scripts.Render("~/Scripts/knockout-2.1.0.js")
<script type="text/javascript">
function ViewModel() {
var self = this;
self.bidInputVisible = ko.observable(false);
self.bidCancel = ko.observable("Bid");
self.toggleBidInput = function () {
self.bidInputVisible(true);
self.bidCancel("Cancel");
};
}
ko.applyBindings(new ViewModel());
</script>
}
So with this code I have a "Bid" at the end of each row of the table.
When I click on it, it gets renamed to "Cancel" and a Text Input and another "Submit" Button appear next to it (in all rows).
I would like to separate each "Bid" button so when I click on it only THAT button in that particular row changes to cancel and only in that row the Text Input and "Submit" Button appear.
I can't seem to separate the effects of the button for each separate row.
KnockoutJS, by nature, is a "Client side library". I'm not sure if you can achieve what you expect by mixing the "client side code" with the "mvc4 server side code" like you mention.
Using KnockoutJS, when you bind a table's row (like for your example) to a list of items in a collection, the "click" commands become available to each items that it is bound to.
So, from what I can see in your example, I would do the following changes:
1) Put each Model.item in a collection within the ViewModel. ex: self.items = ko.observable([])
There are many ways to achieve this, but for the sake of this example, simply try this:
self.items = ko.observableArray([
{
itemDescription: 'desc 1',
itemEndingDate: '2012.01.01',
itemCategory: 'abc',
itemPrice : 123
},
{
itemDescription: 'desc 2',
itemEndingDate: '2012.01.02',
itemCategory: 'bcd',
itemPrice : 234
}
])
2) put the "toggleBidInput", "bidCancel" and "toggleBidInput" inside each items.
3) Bind the table's tbody to that collection. ex:
<tbody data-bind="foreach:items">..</tbody>
4) Bind the rows's cells to the proper items. ex:
<tr>
<td>
<span data-bind="text:itemDescription"></span>
</td>
<td>
<span data-bind="text:itemEndingDate"></span>
</td>...
When Knockout iterates through the items (the foreach..) the click button will be tied to the each item.
For point 1) (passing the data from the server to the client), there are many methods:
1) Use MVC's utility to generate JSON strings and put that string in a variable "model data". use this "model data" to create the items that will include the extra observables and functions.
2) use ajax to "fetch" data asynchronously. and populate the items from the values returned from the server. Web API is great for this actually. See John Papa's great article: http://www.johnpapa.net/2forfree/
Hope this helps.
I am currently writing a simple MVC 3 application that displays a list of items and allows the user to filter the items (on the same page). The user can then click on an item and will be redirected to a details page.
The problem I have is that when the user clicks 'back to list' the search criteria is lost and so is the current page (search results are paged).
I am new to MVC and cannot seem to figure out how this should be done.
Controller
....
public ActionResult Index(PacketSearch search)
{
const int pageSize = 20;
var allPackets = this.repository.GetAllPackets().Where(p => (string.IsNullOrEmpty(search.FromIp)) || p.FromIp == search.FromIp);
var pagedPackets = new PaginatedList<RawPacket>(allPackets, search.Page ?? 0, pageSize);
search.SearchResults = pagedPackets;
return View(search);
}
public ActionResult Details(int id)
{
var packet = this.repository.GetPacket(id);
return View(packet);
}
Main page
....
#if (Model.SearchResults != null && Model.SearchResults.Count > 0)
{
<table>
<tr>
<th>
Timestamp
</th>
<th>
From IP
</th>
</tr>
#foreach (var item in Model.SearchResults) {
<tr>
<td>
#Html.ActionLink(item.TimestampString, "Details", "Packets", new { id = item.Id }, null)
</td>
<td>
#Html.DisplayFor(modelItem => item.FromIp)
</td>
</tr>
}
</table>
}
<br />
#if (Model.SearchResults.HasPreviousPage)
{
#Html.RouteLink("<<<", "Packets", new { page = (Model.SearchResults.PageIndex - 1) })
}
Page #(Model.SearchResults.PageIndex + 1) of #Model.SearchResults.TotalPages
#if (Model.SearchResults.HasNextPage)
{
#Html.RouteLink(">>>", "Packets", new { page = (Model.SearchResults.PageIndex + 1) })
}
Details Page
<h2>Packet Details</h2>
<fieldset>
<legend>RawPacket</legend>
<div class="display-label">Timestamp</div>
<div class="display-field">
#Html.DisplayFor(model => model.TimestampString)
</div>
<div class="display-label">FromIp</div>
<div class="display-field">
#Html.DisplayFor(model => model.FromIp)
</div>
</fieldset>
<p>
#Html.ActionLink("Back to List", "Index")
</p>
Any help would be much appreciated, thanks.
You must persist the input somewhere and the best place is url(because it can be cached and remembered by user).
Define another Action in controller which will do the main job of searching and send the search parameters through a query string to it.