refreshing / reloading the PartialView inside the current view - asp.net-mvc

I have a PartialView that is an image upload, and basically I am displaying some images and then the normal Upload buttons :-
#model MvcCommons.ViewModels.ImageModel
<table>
#if (Model != null)
{
foreach (var item in Model)
{
<tr>
<td>
<img src= "#Url.Content("/Uploads/" + item.FileName)" />
</td>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
</tr>
}
}
</table>
#using (Html.BeginForm("Save", "File", FormMethod.Post, new { enctype = "multipart/form-data" })) {
<input type="file" name="file" />
<input type="submit" value="submit" /> <br />
<input type="text" name="description" />
}
Now my idea is to have this in different pages. I tried it in 1 page already and is working fine, however when I Upload an image,
public ActionResult ImageUpload()
{
ImageModel model = new ImageModel();
model.Populate();
return View(model);
}
I want to go back to the "previous" View, ie the View that is hosting this partial view? When I do return View(model) as above, I get into the ImageUpload partial view which I do not want to.
Thanks for your help and time.
***UPDATE*********
I went for the simple route for the time being, and hard coded the actual View name
public ActionResult ImageUpload()
{
ImageModel model = new ImageModel();
model.Populate();
return View("~/Views/Project/Create.cshtml", model);
}
however I got an error :-
The model item passed into the dictionary is of type MvcCommons.ViewModels.ImageModel, but this dictionary requires a model item of type MvcCommons.Models.Project.

Use the overload that takes a string of the name of the view you want.
http://msdn.microsoft.com/en-us/library/dd460310
protected internal ViewResult View(
string viewName,
Object model
)
i.e.
return View("ViewName", model);
if you have this in different pages then you can inject context via the action paramaters;
public ActionResult ImageUpload(string parentViewName)
{
ImageModel model = new ImageModel();
model.Populate();
return View(parentViewName, model);
}
NOTE: You should only need to pass the views name not the path:
return View("Create", model);

Related

ViewModel comes as null from view to controller

I have my code as below.Can somebody help me in this I am not able to send model to view.
ViewModel class
IEnumerable<CarList> MyCarPositions.
In my view.
#model TestMVC.ViewModel.
foreach (var item in Model.MyCarPositions)
{
#Html.TextBoxFor(x => item.Name)
#Html.TextBoxFor(x => item.Brand)
}
My Controller
ViewModel carviewmodel = new carviewmodel();
[HttpGet]
public ActionResult Index()
{
carviewmodel.MyCarPositions = repository.GetCarPositions();
return View(carviewmodel);
}
[HttpPost]
public ActionResult Index(ViewModel carvmodel)
{
// Here in httppost carvmodel comes as null.
}
Your foreach loop is generating duplicate name attributes without indexers which cannot be bound to your model. Its also generating invalid html because of the duplicate id attributes. You need to generate the collection using a custum EditorTemplate for the type in your collection, or use a for loop.
You have not shown you models, but property MyCarPositions needs to be List<T> if using the for loop option.
#model TestMVC.ViewModel
#using Html.BeginForm())
{
for (int i = 0; i < Model.MyCarPositions.Count, i++)
{
#Html.TextBoxFor(x => x.MyCarPositions[i].Name)
#Html.TextBoxFor(x => x.MyCarPositions[i].Brand)
}
<input type="submit" .. />
}
This will generate the correct name attributes necessary for binding
<input type="text" name="MyCarPositions[0].Name" .... />
<input type="text" name="MyCarPositions[1].Name" .... />
<input type="text" name="MyCarPositions[2].Name" .... />
Side note: You should be initializing the model inside the controller method
// ViewModel carviewmodel = new carviewmodel(); remove this
[HttpGet]
public ActionResult Index()
{
ViewModel carviewmodel = new carviewmodel(); // initialize it here
carviewmodel.MyCarPositions = repository.GetCarPositions();
return View(carviewmodel);
}
Right away I can see a syntax error that might be causing your issue.
foreach (var item in Model.MyCarPositions)
{
#Html.TextBoxFor(x => item Name <--- missing a '.' and a closing bracket
#Html.TextBoxFor(x=>item.Brand)
}
Should be:
foreach (var item in Model.MyCarPositions)
{
#Html.TextBoxFor(x =>item.Name)
#Html.TextBoxFor(x=>item.Brand)
}

Data not loading on partial view, MVC

I am doing work on form where user can enter a customer record....View is scaffold with Create controller.
On 'Create' View, user can enter 'engineNo' to check its details which passes to another action "CheckRecord",,it can be seen from view...
<form>
<input type="text" id="enginNo" />
<input type="button" value="search" id="btnSearch" />
</form>
#using (Html.BeginForm("Index","Home",FormMethod.Get))
{
#Html.AntiForgeryToken()
<div id="info">
#{Html.RenderAction("CheckRecord","Sales");}
</div>
some create fields
}
The Create and "CheckRecord" actions are,,
public ActionResult Create()
{
ViewBag.CustomerId = new SelectList(db.CustomersDMs, "CustomerId", "Name");
ViewBag.SMClientBranchId = new SelectList(db.SMClientBranchesDMs, "SMClientId", "Name");
ViewBag.EngineNumber = new SelectList(db.StockDMs, "EngineNumber", "ChasisNumber");
return View();
}
public ActionResult CheckRecord(string enginNo)
{
var results = db.StockDMs.Where(c=>c.EngineNumber ==enginNo);
return PartialView("_part",results);
}
And my partialview,,,
#model IEnumerable<SM.CRM.AutosLoan.Models.Core.DomainModels.StockDM>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.AutoCompanyBrand.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.SMClientBranch.Name)
</td>
}
My problem is, the partial view is rendered correctly but the Model of partial view doesn't have value,,,Why is that, i am doing something wrong...Please help,,,Thanks for your time
(Posting this as answer since I mentioned it in comments and that's not the correct place)
Your action CheckRecord(string enginNo) takes an argument of enginNo, but you're calling it without any argument. That in turn means your db lookup will most likely not return any results, unless you get results on..
var results = db.StockDMs.Where(c => c.EngineNumber == null);
Make sure the action gets a valid argument, for example:
#{ Html.RenderAction("CheckRecord", "Sales", new { enginNo = "abc123" }); }

How to get list of ordered items in ASP.NET MVC4 form post method

HTML5 offline ASP.NET MVC4 application allows to enter order quantities for customer.
Ordered item codes and quantities are not passed to Order method.
In code below Order method Result parameter value is null.
How to get ordered item codes and quantities in Order method?
How to post only items which whose ordered quantity is greater than 0 ?
Product list is big and unordered products can not posted.
I can switch to ajax, jquery and MVC4 Web API if this is reasonable.
Controller:
public class OfflineOrderController : ControllerBase
{
public class OrderedItems
{
public string Id;
public decimal Quantity;
}
[HttpGet]
public ActionResult Order(string customerId)
{
return View(new MobileOrderOrderViewModel(customerId));
}
[HttpPost]
public ActionResult Order(string customerId, IEnumerable<OrderedItems> Result)
{
... save order to database
return new ContentResult() { Content = "Order received" };
}
}
View:
<!DOCTYPE html>
<html manifest="~/MobileOrder/Manifest">
<body>
#using (Html.BeginForm())
{
<table>
<tbody>
#foreach (var product in Model.Products())
{
<tr>
<td>#product.Id</td>
<td>
<input type="hidden" name="Id" value="#product.Id" />
<input type="number" name="Quantity" min="0" max="10000000" />
</td>
</tr>
}
</tbody>
</table>
<input type="submit" value="Send order">
<input type="hidden" name="customerId" value="#Model.CustomerId" />
}
</body>
</html>
Have you tried the techniques that Phil Haack described in the following blog post?
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/
In short, you can use something like the following. It's better if you make the Products a property instead of a method call.
#for (int i = 0; i < Model.Products.Length; i++) {
<tr>
<td>#Model.Products[i].Id</td>
<td>
#Html.HiddenFor(m => Model.Products[i].Title)
#Html.TextBoxFor(m => Model.Products[i].Quantity)
</td>
</tr>
}
This will create html elements with the "Products" prefix. In order to make sure that it is model bound properly, you can use something like this:
[HttpPost]
public ActionResult Order(string customerId, [Bind(Prefix = "Products")] IEnumerable<OrderedItems> Result)
{.....}
Disclaimer: No code was tested when answering this question; it was all typed in right here.

Post Html table created by a model in MVC view to controller

I created a list based on the scaffolding
#model IEnumerable<FleetLink.Domain.Entities.UserTable>
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
<table>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Master_IP)
#Html.TextBoxFor(modelItem=>item.Master_IP)
</td>
<td>
#Html.DisplayFor(modelItem => item.Master_Name)
</td>
</tr>
<tr><td><input type="submit" value="Submit" /></td></tr>
</table>
}
In my controller I have a get and a post method for index
[HttpPost]
public ActionResult Index(List<UserTable> list)
{
return View();
}
[HttpGet]
public ActionResult Index()
{
var users= from userTable in _repo.GetUsers()
select userTable;
return View(users);
}
I was expecting it would call post method when I clicked on submit and would pass the entire tables data to the Index HTTPPost method. But it is always calling the get method of Index. The goal is to pass entire table data after user edits it so I can save all table data at once. Please advice on what I am doing wrong.
I resolved this issue by changing the foreach to for(int i=0....) as well as changing the #using (Html.BeginForm("Index", "Home", FormMethod.Post)) to
#using (Html.BeginForm(FormMethod.Post))
Thanks

MVC3 Multiple Models - single page

I have a _layout page which has a login box (partial view) and that view has it's own model. So the controller looks like this:
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(LoginModel loginModel)
{
if(ModelState.IsValid)
{
var g = new GallaryImage();
var user = g.LoginUser(loginModel.Username, loginModel.Password);
if(user != null)
{
FormsAuthentication.SetAuthCookie(user.username, false);
return RedirectToAction("Index", "Home");
}
ModelState.AddModelError("", "Invalid Username/Password");
}
return View(loginModel);
}
But as soon as my main content page needs a model, my web app fails because the Login box expects a LoginModel type, but my content page is sending a different model:
This is the GET method for my main Index screen:
public ActionResult Index()
{
IndexModel model = new IndexModel();
var g = new GallaryService.GallaryImage();
var i = g.GetRandomImage();
if (i != null)
model.RandomImageUrl = "~/Images/Watermarks/" + i.filename;
return View(model);
}
So, my main content page has an IndexModel, but my partial view has a LoginModel. When I try run it, I get an error:
"The model item passed into the dictionary is of type 'GalleryPresentation.Models.IndexModel', but this dictionary requires a model item of type 'GalleryPresentation.Models.LoginModel'."
How do I handle this - My _layout needs the model for the login box.
As requested, here is the Loginbox cshtml file.
#using GalleryPresentation.Models
#model LoginModel
<script src="../../Scripts/jquery.validate.min.js" type="text/javascript"></script>
#using (Html.BeginForm("index", "Account", FormMethod.Post))
{
<table class="smallBox">
<tr>
<td>#Html.LabelFor(m => m.Username)</td>
<td>#Html.TextBoxFor(m => m.Username, new { #class = "smallText" })</td>
<td>#Html.LabelFor(m => m.Password)</td>
<td>#Html.PasswordFor(m => m.Password, new { #class = "smallText" })</td>
</tr>
<tr>
<td colspan="4" align="right"><input type="submit" value="Login"/></td>
</tr>
<tr>
<td colspan="2">#Html.ValidationSummary()</td>
</tr>
</table>
}
And the Index.cshtml file (THe main content screen) has this:
#using GalleryPresentation.Models
#model IndexModel
#{
ViewBag.Title = "Craig and Melanie's Digital Moments";
}
<br/>
<div style="text-align: center">
<img src="#Url.Content( Model.RandomImageUrl)" alt="#ViewBag.Title" />
</div>
Questions like this aren't always the easiest to answer because there isn't a straightforward solution. There are several issue though that should be considered. If it is possible, I would recommend that you handle login validation errors in a separate view. The partial view for the small login box then does not require a strongly-typed view model.
There's no perfect solution, but I don't think that it makes a lot of sense for you to always be creating LoginModel objects on every request that renders a view which depends on _Layout. The solution below advocates the creation of a separate login view which can be used for explicit login attempts and for the handling of any login failures.
If you have any trouble following this, feel free to your question in a comment and I'll do my best to answer.
Login Box
#using (Html.BeginForm("Index", "Account"))
{
<table class="smallBox">
<tr>
<td>Username</td>
<td>#Html.TextBox("Username", new { #class = "smallText" })</td>
<td>Password</td>
<td>#Html.Password("Password", new { #class = "smallText" })</td>
</tr>
<tr>
<td colspan="4" align="right"><input type="submit" value="Login"/></td>
</tr>
</table>
}
Account Controller
public ActionResult Login()
{
return View();
}
public ActionResult RetryLogin()
{
ModelState.AddModelError(null, "The Username or Password you entered is invalid. Please try again.");
return View("Login");
}
[HttpPost]
public ActionResult Index(LoginModel loginModel)
{
if(ModelState.IsValid)
{
var g = new GallaryImage();
var user = g.LoginUser(loginModel.Username, loginModel.Password);
if(user != null)
{
FormsAuthentication.SetAuthCookie(user.username, false);
return RedirectToAction("Index", "Home");
}
ModelState.AddModelError("", "Invalid Username/Password");
}
return RedirectToAction("RetryLogin");
}
Login View
#using (Html.BeginForm("Index", "Account"))
{
#Html.ValidationSummary()
<!-- login form here -->
}

Resources