MVC3 Multiple Models - single page - asp.net-mvc

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 -->
}

Related

How can I check if a check box is checked in view page with razor in asp.net mvc?

I'm new in asp.net mvc and write this razor code for show me check box component:
#Html.CheckBox("FlatFile",false)
I want write razor c# script to check if that check box is checked then work some thing, I don't want to write javascript or anything, I just want write c# razor script code for that purpose.
How can I write that?
You can check this using FormCollection in your controller action.
try using below code:
[HttpPost]
public ActionResult Index(FormCollection frm)
{
bool MyBoolValue = Convert.ToBoolean(frm["FlatFile"].Split(',')[0]);
return View();
}
Your checkbox code:
#Html.CheckBox("FlatFile",false)
Now you can use the CheckBox name (i.e., FlatFile) to do stuff in your controller like :
public ActionResult Something(IEnumerable<bool> FlatFile)
{
if(FlatFile!= null) --you can give your condition here
{
--do something
}
else
{
--do something else
}
}
A sample example:-
This is my controller code:-
public ActionResult test()
{
return View();
}
[HttpPost]
public ActionResult test(bool FlatFile)
{
if(FlatFile==true)
{
ViewBag.Message = "Selected";
return View();
}
else (FlatFile == false)
{
ViewBag.Message="Not selected";
return View();
}
}
This is my view code(i.e., test.cshtml):-
#using (Html.BeginForm("test", "User", FormMethod.Post,
new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<fieldset>
<legend>Test CheckBox</legend>
<table>
<tr>
<td>#Html.Label("Select"):</td>
<td>#Html.CheckBox("FlatFile", false)</td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="Check" /></td>
</tr>
<tr>
<td>#ViewBag.Message</td>
</tr>
</table>
</fieldset>
}

While uploading photo on website it is not storing in specified folder

I am trying to store an image on specified folder when it is uploaded.I am not getting where I am doing mistake.
Here is my controller code
public ActionResult Create(EmployeeViewModel model, HttpPostedFileBase photo)
{
if (ModelState.IsValid)
{
var search = db.Employees.FirstOrDefault(x => x.EmpID == SessionWrapper.UserId);
if (search != null)
{
ViewBag.Message = "Email you've enter is used by someone else. Reenter please";
}
else
{
Login login = new Login
{
UserEmail = model.UserEmail,
UserPass = Crypto.HashPassword(model.UserPass),
RoleID = 2,
Created = DateTime.Now,
};
db.Logins.Add(login);
db.SaveChanges();
if (photo != null)
{
photo.SaveAs(Server.MapPath("~/Photo/" + SessionWrapper.UserId + ".png"));
}
}
}
return View(model);
}
And this is my View Page
#model DivineDemo.Models.EmployeeViewModel
#using DivineDemo.Models
#using (Html.BeginForm("create", "Employee", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<p class="alert-success">#ViewBag.Message</p>
<table class="table table-responsive table-striped">
<tr>
<td>
<input type="file" name="photo" />
<button>
<span class="glyphicon glyphicon-save"></span>
Submit your registration details
</button>
</td>
</tr>
</table>
}
</div>
I have created folder named 'Photo' to store this uploaded images but it is not storing.
I am using Asp.Net MVC with database first Entity Framework..

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" }); }

refreshing / reloading the PartialView inside the current view

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);

Asp.net MVC Razor more than one form on a page

Yo
I have a registration page on my site - at the top of the page is a login form for existing users. In the main area there is the registration form.
The login are is a partial view with #model ViewModels.LoginViewModel
The registration are is also a partial with #model ViewModels.RegViewModel
The main page which houses these partials is a view with #model ViewModels.RegPageViewModel
This viewmodel looks like:
public class RegViewModel
{
public RegisterVm RegisterVm { get; set; }
public LoginVm LoginVm { get; set; }
}
When I submit the registration part of the page (it's action is register/capture - the receiving action expects a RegisterVm) to it's controller it complains about being passed the wrong viewmodel
What's the deal with subviews and their viewmodel? Is there a standard approach to dealing with this?
Should I have one submit URL for this page which figures out if it's a login request or a register request and then handles the post accordingly? That seems messy to me though...
http://monobin.com/__d33cf45a4 - RegisterVm.cs (LoginVm.cs is pretty much the same as this)
http://monobin.com/__m69132f76 - RegPageVm.cs
Register.cshtml:
#model xxxx.ViewModels.RegPageVm
#{
View.Title = "Register";
Layout = "~/Views/Shared/_BareBones.cshtml";
}
<link rel="stylesheet" href="#Url.Content("~/Public/Css/signup.css")" type="text/css" />
<div id="sign-up-container">
<div id="sign-up-box">
<div id="sign-up-box-left">
<img src="#Url.Content("~/Public/Images/Signup_176x81.png")" />
</div>
<div id="sign-up-box-right">
#Html.Partial("_Register")
</div>
</div>
</div>
<div class="clear">
</div>
_Register.cshtml:
#model xxxx.ViewModels.RegisterVm
#using (Html.BeginForm("Capture", "Register", FormMethod.Post))
{
<table class="sign-up-box-inner">
<tr>
<td class="label-area">
#Html.LabelFor(x => x.Email)
</td>
<td class="field-area">
#Html.TextBoxFor(x => x.Email, new { #class = "login-input", title = "Enter Name" })
</td>
</tr>
<tr>
<td class="label-area">
#Html.LabelFor(x => x.Password)
</td>
<td class="field-area">
#Html.PasswordFor(x => x.Password, new { #class = "login-input", title = "Enter Name" })
</td>
</tr>
<tr>
<td class="label-area">
#Html.LabelFor(x => x.UserName)
</td>
<td class="field-area">
#Html.TextBoxFor(x => x.UserName, new { #class = "login-input", title = "Enter Name" })
</td>
</tr>
<tr>
<td colspan="2">
<input type="image" src="../../Public/Images/Submit_150x47.png" class="submit-button" />
</td>
</tr>
</table>
#Html.AntiForgeryToken()
}
And finally RegisterController.cs:
public class RegisterController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost, ValidateAntiForgeryToken]
public ActionResult Capture(RegisterVm registerVm)
{
if (!ModelState.IsValid)
{
return View("index", new RegPageVm()
{
LoginVm = new LoginVm(),
RegisterVm = registerVm
});
}
return RedirectToAction("index", "Event");
}
}
w://
You need to ensure that the form elements (like the textbox etc) should have the same id as the RegisterVM and LoginVM properties. Your theory is right but I think you might be making a mistake in the naming convention of MVC.
If you can share your view code + the VM classes, then we'll be able to help better.
EDIT:
Looking at your code I think you should be passing the view model to your partial view. Like for example the following line believe should be like this >
#Html.Partial("_Register", Model.RegisterVm)
According to your answer to nEEbz:
You are using:
Html.TextBoxFor(x=>x.LoginVM.Email) // i guess
this would turn into <input name="LoginVM.Email" ...>
Notice the LoginVM. part
Your login action probably looks like:
public ActionResult Login(LoginVM model) { }
so it expect field names like Email and Password, not LoginVM.Email and LoginVM.Password.
So you could could use Html.Textbox instead (so that the field name doesn't get autocreated).

Resources