How to pass records from one view to another view? - asp.net-mvc-4

I have a table of records and a submit button.
How do I pass those records from one view to another view while clicking the Submit Button?
Thanks in advance!

You have a table of records (from where are you getting those records?)
I'm guessing
In your controller:
public ActionResult Index()
{
ModelTemp = model = new ModelTemp();
model.listRecord = new List<ModelTempB>();
return view(model);
}
In your view:
#for (int x = 0; x < Model.listRecord .Count; x++)
{
<tr>
<td>
#Html.DisplayFor(modelItem => Model.listRecord[x].Someproperty)
<br/>
#Html.HiddenFor(modelItem => Model.listRecord[x].Someproperty)
</td>
</tr>
}
In your controller for Post:
[HttpPost]
public ActionResult Confirmation(ModelTemp model)
{
//now you can access the list of records
return view();
}

easiest way would be put a hidden input within the form same as submit button, serialize your records to json string on client or server depending on your situation. you can access the form collection and deserialize records from string in other controller.

Related

Property values of the same type are updated incorrectly in Blazor

Background:
I wanted to achieve the following:
Keep a copy of the data context and use the copy for editing
So that I can reset the data context back to its unchanged state using an onclick event by doing copyValue = unchangedValue
Here is my attempt (it's been trimmed down in size to reduce noises but it has the same issue):
**index.razor**
#page "/"
#using SolutionName.Data
#using System.Reflection
<EditForm Model="Items2">
<table class="table">
<thead>
<tr>
<th>Summary</th>
</tr>
</thead>
<tbody>
#foreach (var i in Items2)
{
<tr #key="#i.GetHashCode()">
<InputText #bind-Value="i.Summary"></InputText>
</tr>
}
</tbody>
</table>
</EditForm>
//
//reflections for debuggings
//
#if (Items != null)
{
<p>
#foreach (var item in Items)
{
<span>#($"Items.{typeof(WeatherForecast).GetProperty(nameof(WeatherForecast.Summary)).Name}={typeof(WeatherForecast).GetProperty(nameof(WeatherForecast.Summary)).GetValue(item)}")</span>
}
</p>
}
#if (Items2 != null)
{
<p>
#foreach (var item in Items2)
{
<span>#($"Items2.{typeof(WeatherForecast).GetProperty(nameof(WeatherForecast.Summary)).Name}={typeof(WeatherForecast).GetProperty(nameof(WeatherForecast.Summary)).GetValue(item)}")</span>
}
</p>
}
#code{
List<WeatherForecast> Items = new List<WeatherForecast>();
List<WeatherForecast> Items2 = new List<WeatherForecast>();
protected override void OnInitialized()
{
Items = new List<WeatherForecast>()
{
new WeatherForecast()
{
Date = DateTime.Now,
Summary = "123",
TemperatureC = 1
}
};
Items2 = Items;
}
private void ResetItems2()
{
Items2 = Items;
}
}
As you can see, I am binding Items2, and not Items, to the <EditForm>.
However, updating the summary seems to update both Items2 and Items. I also noticed that this will not happen if Items and Items2 are of two different types (say that they have exactly the same properties, and I cast one to another...)
Two questions:
Why is Item updated in this case?
Is there a way to only update Items2 and not Items, while allowing Items and Items2 to be the same type?
Detailed steps to reproduce the issue:
Step 1. Initialized and render for the first time
Step 2. Change the value to 456 and then tab away
The expected result should be
Items.Summary=123 (not 456)
Items2.Summary=456
The issue is that you're using reference type assignment. When you assign Items to Items2, you actually assign a pointer to Itemss values. Both variable point to the same list of objects.
If it's applicable create a value type instead. Saving data in the local storage and then retrieving it is a viable solution.
This:
List<WeatherForecast> Items = new List<WeatherForecast>();
List<WeatherForecast> Items2 = new List<WeatherForecast>();
is superfluous. Code like this:
List<WeatherForecast> Items;
List<WeatherForecast> Items2;

ModelState.IsValid == false, although all model values are inserted

today I have the problem, that after i inserted all data to a formular to create a new Product, the programm say that ModelState.IsValid==false.
When i look into the modelState during debugging there is a Error on field 0. The error: "The CuId field is required".
To prevent that i set CuId right in the Creat POST action like so in the ProductController.cs:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Product product)
{
int lastcu = db.Customers.Max(l => l.Id);
product.CuId = last;
if (ModelState.IsValid)
{
db.Products.Add(product);
db.SaveChanges();
return RedirectToAction("Create", "NewIssue");
}
return View(product);
}
But again it sets the same error.
My view looks like that. Actually the model.CuId should already set there:
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Product</legend>
<div class="editor-label">
#Html.LabelFor(model => model.CuId, "Customer")
#ViewBag.Cuname
#Html.HiddenFor(model => model.CuId, new { id = "lastcu" })
</div>
My GET Controller looks like this:
public ActionResult Create()
{
int lastcu = db.Cu.Max(l => l.Id);
//gives the id a Name
var lastcuname = db.Customers.Find(lastcu).Name;
//show to User by creating the product
ViewBag.Cuname = lastcuname;
ViewBag.CuId = lastcu;
return View();
}
When I look in debug mode into the values of the model product, all fields are filled (also CuId) except of the the foreign key what is bind to the product.CuId and the Id of the product what is set automatically from the database.
Hopefully you can help me. Thanks in advance.
As for the first part of your question, ModelState is populated by the DefaultModelBinder when the method is first called. If property CuId has the [Required] attribute and its value is not posted back, then an error is added to ModelState and therefore ModelState.IsValid is false. Just setting a property of your model does not remove ModelState values.
As for the second part of your question, your not passing you model to the view in the GET method so #Html.HiddenFor(m => m.CuId) generates a hidden input with no value (because the value of model.CuId is null or its default). All you currently doing is passing some values to the view using ViewBag (not good practice) which you never even use. Instead, pass the model to the view as follows.
public ActionResult Create()
{
int lastcu = db.Cu.Max(l => l.Id);
var lastcuname = db.Customers.Find(lastcu).Name;
// Initialize a new instance of the model and set properties
Product model = new Product()
{
CuId = lastcu,
Cuname = lastcuname // assume this is a property of your model?
};
return View(model); // return the model
}
Side note: #Html.LabelFor(model => model.CuId, "Customer") generates a html <label> which is an accessibility element. Clicking on it sets focus to its associated form control. But you don't have an associated form control (just a hidden input which cannot receive focus)

Adding a record to the database based on input passed from a link on another form MVC 4

I have been using ASP.NET MVC 4 for a while but I have not yet come across a situation where i need to insert a value into the database from a scaffolded Create view which is based on a value passed from another view. I have tried to infer from the Edit view to try and modify my code to work but I have run into a snag. I got an error similar to this post. Here is my code from the view passing the value
#Html.ActionLink("Allocate", "Create", "Allocation", new { id=item.requestID}, null)
this is from the list of requests already in the database from the Index view
here is my code on the controller that is trying to force the Create method to use the ID passed from the link above
public ActionResult Create(int id = 0)
{
Request request = db.Requests.Find(id);
ViewBag.requestID = new SelectList(db.Requests, "requestID", "requestID", request.requestID);
return View(request);
}
then here is the posting code to the db
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Allocation allocation)
{
if (ModelState.IsValid)
{
db.Allocations.Add(allocation);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.requestID = new SelectList(db.Requests, "requestID", "requestID", allocation.requestID);
return View(allocation);
}
Basically what I am trying to do is allocate funds to a request made where by the allocation is entered into the db based on the request id. I am trying to prevent the user from choosing the request id from a drop down list. When I run this i get an error
The model item passed into the dictionary is of type 'System.Data.Entity.DynamicProxies.Request_A52006F7570E0448EE323CB36858E4D13EED0BAD958340B32FF166708545DA8C', but this dictionary requires a model item of type 'BudgetAllocation.Models.Allocation'.
If theres anyone out there who can help me out with this please do as soon as you can. I appreciate all the effort offred!!!!!
//EDIT
Here is my Create view
#model BudgetAllocation.Models.Allocation
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Allocation</legend>
#Html.HiddenFor(model => model.requestID)
<div class="editor-label">
#Html.LabelFor(model => model.allocAmount, "Amount")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.allocAmount)
#Html.ValidationMessageFor(model => model.allocAmount)
</div>
<p>
<input type="submit" value="Allocate" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
The problem is your view id strongly typed with BudgetAllocation.Models.Allocation while in get action of Create you are passing object of type BudgetAllocation.Models.Request thats why you are getting the exception.
You have to pass object of type BudgetAllocation.Models.Allocation in Create get action as well because you view is strongly typed to it.
public ActionResult Create(int id = 0)
{
Request request = db.Requests.Find(id);
return View(request) // <-------------- here is the mistake
}
it should return allocation object, something like this, it is just an example may be you need to do some other thing instead of selecting:
public ActionResult Create(int id = 0)
{
Allocation allocation = db.Allocations.Find(x=>x.requestID == id);
ViewBag.requestID = new SelectList(db.Requests, "requestID", "requestID", request.requestID);
return View(allocation);
}
UPDATE:
you simply need to do like this not return allocaiton object return simply View:
public ActionResult Create(int id = 0)
{
ViewBag.requestID = new SelectList(db.Requests, "requestID", "requestID", request.requestID);
return View();
}

Url.Action is how to reformat URL

I am creating an MVC4 application.
In my contract controller overview page i have an Url.Action
int teller = 0;
foreach (var item in Model)
{
<a href="#Url.Action("Details", "Contract",new { id = teller })">
<tr>
<td>#Html.DisplayFor(modelItem => item.ContractMSFNo)</td>
<td>#Html.DisplayFor(modelItem => item.StageCode)</td>
<td>#Html.DisplayFor(modelItem => item.ValidFromView)</td>
<td>#Html.DisplayFor(modelItem => item.ValidToView)</td>
</tr>
</a>
teller++;
}
I need to pass the id. I am using id in the ActionLink details in Contract Controller
my controller is
public ActionResult Details(int id)
{
//code
return View(contract);
}
When i click on the link Url generated is
http://localhost:4826/Contract/Details/0
/0 is the id
i want my Url to be http://localhost:4826/Contract/Details
i know this can be acheived thru Html.Actionlink but it is my compulsion to use Url.Action. Can it be acheived with Url.Action
It can't be done by routing or ActionLink. But you may try to use session.
1) Add to your controller new method to save your id to session:
public JsonResult Save(int id)
{
Session["ID"] = id;
return Json("Success");
}
2) Add jQuery method to save data in session from View and delete parameter from Url.Action:
<a class="mylink" href="#Url.Action("Details", "Contract")"></a>
<script>
$(".mylink").click(function(){
var data = { id : teller}; //**teller is from your example
$.get("#Url.Action("Details", "Contract")", data)
});
</script>
3) Change your Details ActionResult to get id from session:
public ActionResult Details()
{
var id = (int)Session["ID"];
//code
return View(contract);
}
P.S: Ask your client, how he expects to give sombody external links. It will be impossible if url doesn't have a parameter. And it is very bad for SEO.
If you want your URL without the id parameter, simply don't pass it to the Url.Action() method, as follows:
#Url.Action("Details", "Contract")
If you add like {id=teller} then route automatically add id parameters end of the link. If you don't need id parameters for this url you need to remove
new { id = teller }
Final version like this
#Url.Action("Details", "Contract")
OK, reading this comment: "no actually there are many ids ... code is foreach (var item in Model) { ", I am not sure I understand what you really want to achieve. You are passing a parameter to the view, which can have only one value. Are you sure that you are not looking for something like:
foreach (var item in Model)
{
<a href="#Url.Action("Details", "Contract",#item.ID>
...
}
instead? The fact the ID is visible or not in the URL seems to be another problem, no ?

Cascade Drop down list

I am trying to create a cascading drop down list, and I am getting an error.
This contains what I am try to do with in my controller class:
public ActionResult Create()
{
ViewBag.Status = new SelectList(db.pjt_Statuses, "pjt_Status_ID", "StatusName");
ViewBag.CategoryID = new SelectList(db.pjt_Categories, "pjt_Category_ID", "CatName");
return View();
}
public ActionResult SubCategory(int id)
{
var SubCategory = from s in db.pjt_SubCategories
where s.CategoryID == id
select s;
return Json(SubCategory.ToList());
}
// POST: /Project/Create
[HttpPost]
public ActionResult Create(pjt_Projects pjt_projects)
{
if (ModelState.IsValid)
{
pjt_projects.CreationDate = DateTime.Now;
db.pjt_Projects.Add(pjt_projects);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.Status = new SelectList(db.pjt_Statuses, "pjt_Status_ID", "StatusName", pjt_projects.Status);
ViewBag.CategoryID = new SelectList(db.pjt_Categories, "pjt_Category_ID", "CatName", pjt_projects.CategoryID);
return View(pjt_projects);
}
View
This shows what I am try to do on the front end. I am getting a error with the bold line in my view code below. The error I am getting is:
There is no ViewData item of type IEnumerable<SelectListItem> that has the key pjt_SubCat_ID.
Code:
<div class="span3 offset1">
#Html.LabelFor(model => model.CategoryID, "Category")
#Html.DropDownList("CategoryID", String.Empty)#*, null, new { #onchange = "FetchSubCategories();" })*#
<br />
#Html.ValidationMessageFor(model => model.CategoryID)
</div>
<div class="span3 offset1">
<label>Sub Category</label>
#Html.DropDownList("pjt_SubCat_ID", String.Empty)
<br />
#Html.ValidationMessageFor(model => model.SubCategoryID)
</div>
Can someone advise me what is going wrong here?
The problem is that the engine is trying to get the SelectList from the viewbag and it cannot find it. I am guessing that you want the Dropdown to display the items you have stored in the viewbag under "pjt_SubCat_ID" but you are not adding that item to the viewbag anywhere in the code that you have listed in your question.
If that is supposed to be the data returned from the SubCategory() method, you will not find that data in the viewbag and you should have a javascript that calls this method on the click event of the original SelectList (category id one) and binds the returned data to the subcategory one.