I am having an issue capturing the model when it's passed from the view to the controller.
Basically, every Question has a set of QuestionResponse (think of it as the list of offered responses for a certain question in a dropdown). ClinicalSummaryAnswer is the structure capturing one response per question, for a given user. So a user ends up with a collection of ClinicalSummaryAnswer, where every element is an answer to the respone.
When I submit the form below, all the elements in the model ClinicalSummaryView (ClinicalSummaryAnswer, Questions, QuestionResponse) are null from the controller side. Any ideas why this could happening? I suspect it may be due to the foreach? I am not sure. Please help!!
My View
#model TissueBankApp.Models.View.ClinicalSummaryView
<div>
#using (Html.BeginForm("Create", "ClinicalSummary", FormMethod.Post, new { #class = "form-horizontal" }))
{
<div class="form-group">
<input type="hidden" asp-for="Person.PersonId" value="Person.PersonId" />
<input type="submit" value="Create" class="btn btn-outline-primary btn-sm" />
<a asp-action="Details" asp-controller="Person" asp-route-id="Person.PersonId" class="btn btn-outline-primary btn-sm">Cancel</a>
</div>
<div class="col-md-12">
<div class="form-row">
<b> #Html.DisplayFor(model => model.ClinicalSummary.Description) </b>
</div>
#foreach (var question in Model.Questions) //For every question, generate question, and generate responses
{
<div class="form-row">
<label class="control-label col-md-4">#question.QuestionText</label>
#if (question.QuestionResponse.Count() != 0) //If count ViewData[QID] != 0, generate select dropdown, otherwise, input.
{
#Html.DropDownListFor(n => n.ClinicalSummaryAnswer.FirstOrDefault(m => m.QuestionId == question.QuestionId).AnswerId, new SelectList(question.QuestionResponse, "ResponseId", "ResponseText"), "", new { #class = "form-control col-md-4" })
}
else
{
#Html.TextBoxFor(n => n.ClinicalSummaryAnswer.FirstOrDefault(m => m.QuestionId == question.QuestionId).OtherText, new { placeholder = "", #class = "form-control col-md-4", #type = "date" });
}
</div>
}
</div>
}
</div>
Controller
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(ClinicalSummaryView viewModel, string[] AnswerId, string[] OtherText)
{
//STUFF
//Ignore the OtherText, and AnswerId. I was testing to see if these are passed from view to controller and they are indeed. I just have no way of identifying which answer belongs to which question.
}
Firsly,you need know that for each property of the complex type, model binding looks through the sources for the name pattern prefix.property_name. If nothing is found, it looks for just property_name without the prefix.Your backend wants to receive ClinicalSummaryView.ClinicalSummaryAnswer which is a list model. so what you pass should be ClinicalSummaryAnswer[index].PropertyName.
Change like below:
#using (Html.BeginForm("Create", "Home", FormMethod.Post, new { #class = "form-horizontal" }))
{
<div class="form-group">
<input type="hidden" asp-for="Person.PersonId" value="#Model.Person.PersonId"/>
<input type="submit" value="Create" class="btn btn-outline-primary btn-sm" />
<a asp-action="Details" asp-controller="Person" asp-route-id="#Model.Person.PersonId" class="btn btn-outline-primary btn-sm">Cancel</a>
</div>
<div class="col-md-12">
<div class="form-row">
<b> #Html.DisplayFor(model => model.ClinicalSummary.Description) </b>
</div>
#{ var i = 0;} //add here...
#foreach (var question in Model.Questions)
{
<div class="form-row">
<label class="control-label col-md-4">#question.QuestionText</label>
#if (question.QuestionResponse.Count() != 0)
{
//change here....
#Html.DropDownList("ClinicalSummaryAnswer["+i+ "].AnswerId", new SelectList(question.QuestionResponse, "ResponseId", "ResponseText"), new { #class = "form-control col-md-4" })
}
else
{
//change here....
#Html.TextBox("ClinicalSummaryAnswer["+i+"].OtherText",null, new { placeholder = "", #class = "form-control col-md-4", #type = "date" });
}
</div>
i++; //add here...
}
</div>
}
Besides, the following code should be modify:
//change the value
<input type="hidden" asp-for="Person.PersonId" value="#Model.Person.PersonId"/>
<input type="submit" value="Create" class="btn btn-outline-primary btn-sm" />
//change asp-route-id here..
<a asp-action="Details" asp-controller="Person" asp-route-id="#Model.Person.PersonId" class="btn btn-outline-primary btn-sm">Cancel</a>
Related
Hey so I have a modal popup form where I have to upload files and post data to the database. In the controller I'm retrieving the values by FormCollection. When I try to get the input fields with form collection i get this error : Can not implicitly convert System.Windows.Forms.Form to 'String'. Here is my code:
Controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(FormCollection formCollection, HttpPostedFileBase upload, AAC_procedure_document_types model,NgarkoDokument ngarkoDok)
{
try
{
if (ModelState.IsValid)
{
if (upload != null && upload.ContentLength > 0)
{
var file = new AAC_procedure_documents
{
Emer_Dokumenti = System.IO.Path.GetFileName(upload.FileName),
Lloji_File = model.Emri_llojit,
Content_Type = upload.ContentType
};
using (var reader = new System.IO.BinaryReader(upload.InputStream))
{
file.Permbajtje_Dokumenti = reader.ReadBytes(upload.ContentLength);
}
ngarkoDok.AAC_procedure_documents = new List<AAC_procedure_documents> { file };
}
AAC_procedure_documents_location lokacion = new AAC_procedure_documents_location();
lokacion.Rafti = formCollection["Rafti"];
lokacion.Zyra = formCollection["Zyra"].ToString();
lokacion.Nr_Kutise = Convert.ToInt32(formCollection["Nr_Kutise"]);
db.AAC_procedure_documents_location.Add(lokacion);
db.SaveChanges();
return RedirectToAction("Dokumenti");
}
}
catch (RetryLimitExceededException /* dex */)
{
//Log the error (uncomment dex variable name and add a line here to write a log.
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
}
return View(formCollection);
}
Html form
<div id="myModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Ngarkoni dokumenta</h4>
</div>
<div class="modal-body">
#using (Html.BeginForm("Create", "NgarkoDokument", FormMethod.Post, new { enctype = "mulptiple/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-group">
<label for="exampleFormControlSelect1">Lloji i dokumentit</label><br />
<select title="Lloji i dokumentit" name="lloji" class="form-control col-md-3 box" id="tipiDropdown"> </select>
<input type="button" title="Ngarko dokument" name="ngarko" value="Ngarko" id="uploadPop" class="btn btn-info col-md-3" onclick="document.getElementById('file').click();" />
<input type="file" onchange="javascript: updateList()" multiple="multiple" style="display:none;" id="file" name="postedFiles" />
<div id="fileList"></div>
</div>
<br /><br />
<div class="form-group">
<label for="formGroupExampleInput">Fusha indeksimi</label> <br />
#*<input title="Indeksimi dokumentit" id="indeksimi" class="form-control col-md-3" type="text" name="indeksimi" placeholder="indeksimi" required />*#
#Html.TextBoxFor(a => a.Fusha_Indeksimit.Emri_Indeksimit, new { #class = "form-control", #placeholder = "indeksimi" })
<button title="Shto indeksim" id="modalPlus" type="submit" class="btn btn-info"><i class="glyphicon glyphicon-plus"></i></button>
</div>
<label for="formGroupExampleInput">Vendndodhja fizike e dokumentit</label><br>
<div id="zyraModal" class="form-group col-md-4">
#*<input title="Zyra fizike" id="zyra" class="form-control" type="text" name="zyra" placeholder="Zyra" />*#
#Html.TextBoxFor(a => a.Vendndodhja_fizike.Zyra, new { #class = "form-control", #placeholder = "Zyra" })
</div>
<div class="form-group col-md-4">
#* <input title="Kutia fizike" id="kutia" class="form-control" type="number" name="kutia" placeholder="Nr i kutisë" />*#
#Html.TextBoxFor(a => a.Vendndodhja_fizike.Nr_Kutise, new { #class = "form-control", #placeholder = "Nr i kutisë" })
</div>
<div class="form-group col-md-4">
#* <input title="Rafti fizik" id="rafti" class="form-control" type="text" name="rafti" placeholder="Rafti" />*#
#Html.TextBoxFor(a => a.Vendndodhja_fizike.Rafti, new { #class = "form-control", #placeholder = "Rafti" })
</div>
<br /><br />
<div class="row" id="ruaj">
<button value="Create" title="Ruaj dokumentin" type="submit" class="btn btn-success">Ruaj</button>
</div>
}
</div>
</div>
The namespace to FormCollection must to be System.Web.Mvc instead of System.Windows.Forms. Take a look in your usings and remove System.Windows.Forms...
The class FormCollection exists in two tecnologies, WindowsForm and Web.
Working on an MVC WebApp project and would like to have a button be a "manager" but also show dynamic data about the "employees" they manage through a cascading effect using bootstraps collapse data-toggle. So far I have been unsuccessful.
Take a look at my diagram here, to see what I am looking to achieve.
Basically how do I use a button to display dynamic data using div instead of table.
Here is a quick example of what I have started:
<div class="container">
<div class="row">
#foreach (var man in Model.Manager)
{ //this loop displays all the Manager names
<div class="col-md-4">
//#*#Html.ActionLink(man.ManagerName, "Index", new { id = man.ManagerID }, new { #class = "btn btn-sm", data_toggle = "collapse", data_target = "#employee" })*# <!-- This is the cshtml that doesnt work. -->
<button type="button" class="btn btn-default" data-toggle="collapse" data-target="#employee">#man.ManagerName</button>
<div id="employee" class="collapse">
<div class="row"> //This throws everything off
<div class="col-md-2">
</div>
<div class="col-md-10">
#foreach (var emp in man.Employee)
{
#Html.DisplayFor(modelItem => emp.EmployeeName)
}
</div>
</div>
</div>
</div>
<div class="col-md-1">
#Html.ActionLink("Edit", "Edit", new { id = man.ManagerID }, new { #class = "btn btn-default" })
</div>
<div class="col-md-7">
#Html.ActionLink("Delete", "Delete", new { id = man.ManagerID }, new { #class = "btn btn-default" })
</div>
}
</div>
</div>
Thanks a bunch!
This post explains how to fix the alignment problem and problem with the collapse. Every row will be class = collapse and will collapse/expand only first row. Everything works.
<div class="container">
#{int i = 0;}
#*<div class="row">*#
#foreach (var man in Model.Manager)
{ //this loop displays all the Manager names
//MOVING This in here fixes your problem with alignment
<div class="row">
#{i++;}
<div class="col-md-4">
//#*#Html.ActionLink(man.ManagerName, "Index", new { id = man.ManagerID }, new { #class = "btn btn-sm", data_toggle = "collapse", data_target = "##i" })*# <!-- This is the cshtml that doesnt work. -->
<button type="button" class="btn btn-default" data-toggle="collapse" data-target="##i">#man.ManagerName</button>
<div id="#i" class="collapse">
<div class="row">
//This throws everything off
<div class="col-md-2">
</div>
<div class="col-md-10">
#foreach (var emp in man.Employee)
{
#Html.DisplayFor(modelItem => emp.EmployeeName)
}
</div>
</div>
</div>
</div>
<div class="col-md-1">
#Html.ActionLink("Edit", "Edit", new { id = man.ManagerID }, new { #class = "btn btn-default" })
</div>
<div class="col-md-7">
#Html.ActionLink("Delete", "Delete", new { id = man.ManagerID }, new { #class = "btn btn-default" })
</div>
#*//MOVING This in here fixes your problem with alignment*#
</div>
}
#*</div>*#
</div>
I spent some time on this problem. I'm passing a ViewModel back from my View to the Controller via a form HttpPost. However, only SelectedItemId has value. Users and Rights are null.
View model UserRightViewModel
public class UserRightViewModel
{
public string SelectedItemId { get; set; }
public SelectList Users;
public List<RightViewModel> Rights { get; set; }
}
View model RightsViewModel
public class RightsViewModel
{
public int ID { get; set; }
public string Name{ get; set; }
public bool isSelected { get; set; }
}
Controller Post
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(UserRightsViewModel _viewModel)
{
UserRightsViewModel viewModel = _viewModel;
/*value _viewModel = null for Users and Rights
/* code stuff */
return View(viewModel);
}
View
#model Web.ViewModels.UserRightsViewModel
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="content-wrapper">
<!-- Content Header (Page header) -->
<section class="content-header">
<h1>
#ViewBag.Title
</h1>
#*<ol class="breadcrumb">
<li><i class="fa fa-dashboard"></i> Home</li>
<li>Examples</li>
<li class="active">Blank page</li>
</ol>*#
</section>
<!-- Main content -->
<section class="content">
<!-- Default box -->
<div class="box">
<div class="box-header with-border">
<div class="box-tools pull-right">
<button type="button" class="btn btn-box-tool" data-widget="collapse" data-toggle="tooltip" title="Collapse">
<i class="fa fa-minus"></i>
</button>
<button type="button" class="btn btn-box-tool" data-widget="remove" data-toggle="tooltip" title="Remove">
<i class="fa fa-times"></i>
</button>
</div>
</div>
<br />
<div class="form-group">
#Html.LabelFor(model => model.SelectedItemId, "User", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(m => m.SelectedItemId, Model.Users, new { onchange = "redirect(this.value)", #class = "form-control" })
#Html.ValidationMessageFor(model => model.SelectedItemId)
</div>
</div>
<br />
<div class="box-body">
#for (int i = 0; i < Model.Rights.Count(); i += 2)
{
<div class="row form-group">
<div class="col-md-6">
<div class="row">
<div class="col-md-4">
<div class="col-md-6">
</div>
<div class="col-md-6">
#Html.CheckBoxFor(model => model.Rights.ElementAt(i).isSelected, new { #class = "checkbox checkbox-center" })
#Html.ValidationMessageFor(model => model.Rights.ElementAt(i).isSelected, "", new { #class = "text-danger" })
</div>
</div>
<div class="col-md-8">
#Model.Rights.ElementAt(i).Denumire
</div>
</div>
</div>
<div class="col-md-6">
<div class="row">
<div class="col-md-4">
<div class="col-md-6">
</div>
<div class="col-md-6">
#Html.CheckBoxFor(model => model.Rights.ElementAt(i + 1).isSelected, new { #class = "checkbox checkbox-center" })
#Html.ValidationMessageFor(model => model.Rights.ElementAt(i + 1).isSelected, "", new { #class = "text-danger" })
</div>
</div>
<div class="col-md-8">
#Model.Rights.ElementAt(i + 1).Name
</div>
</div>
</div>
</div>
}
<br />
<br />
<div class="form-group">
<div class="row">
<div class="col-md-6">
<div class="col-md-9">
</div>
<div class="col-md-3">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</div>
<div class="col-md-6">
#Html.ActionLink("Cancel", "Index", null, new { #class = "btn btn-danger" })
</div>
</div>
</div>
</div>
</div>
</section>
</div>
}
I have no idea why some values are null. Why some of values are sent and some not?
Users is null because your not (and nor should you) creating and input for each property of each SelectListItem in the SelectList (if you need to return the view you re-populate the value in the POST method). And in any case, its a field, not a property (has no { get; set; }) so the DefaultModelBinder cannot set it).
Rights is null because you cannot use .ElementAt() to generate form controls for a collection (inspect the html your generating and you will see that the name attributes have no relationship to your model). The name attributes need to be
<input name="Rights[0].ID" ... />
<input name="Rights[0].Name" ... />
<input name="Rights[0].isSelected" ... />
<input name="Rights[1].ID" ... />
<input name="Rights[1].Name" ... />
<input name="Rights[1].isSelected" ... />
....
Note that your only generating a for control for the isSelected property which on its own would be meaningless in the POST method and you will an least want to include a hidden input for the ID property.
It appears from your code that you want to generate a 2 column layout, in which case your code should be (simplified)
<div class="row form-group">
#for(int i = 0; i < Model.Rights.Count; i++)
{
<div class="col-md-6">
#Html.HiddenFor(m => m.Rights[0].ID)
#Html.CheckBoxFor(m => m.Rights[0].isSelected)
</div>
// End current 'row' and start a new one every 2nd item
if ((i + 1) % 2 == 0)
{
#:</div><div class="row form-group">
}
}
</div>
Hi here is answer for your doubt, some values are posting and some values are not.
Actually you are getting the correct result and everything works perfectly
I said this because, if you bind selectedid and selectlistitem to the dropdownlistfor helper, then you will get only selectedid which was assigned as a name for the dropdownlist control. so when post, browser has sent name value pair.
This is same reason for checkbox also , which property has binded to the name that only you will get it in the post.
Hope above information was helpful
Thanks
Karthik
I can see you put submit button outside form. so form not submitting property.
I want to retrieve data from a view, it should work like this:
User fill a form available on the webpage
User clicks SEARCH button
Some function(s) collect the data and display them in another view
I tried all the basic tutorials and tips on others stackoverflow question but it still doesn't work. I don't know what I'm doing wrong...
Here's my code from the view:
section id="roomSearch">
<div class="banner">
<div class="banner-info">
<div class="container">
<div class="details-1">
#using (Html.BeginForm("UploadRoomSearchData", "HomeController", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="col-md-10 dropdown-buttons">
<div class="col-md-3 dropdown-button">
#Html.AntiForgeryToken()
<div class="input-group">
#Html.TextBoxFor(m => m.YourName, new { #class = "form-control has-dark-background", #placeholder = "Imię" })
#Html.ValidationMessageFor(m => m.YourName, "", new { #class = "text-danger" })
<!--<input class="form-control has-dark-background"
name="slider-name" id="slider-name" placeholder="Imię" type="text" required="">-->
</div>
</div>
<!---strat-date-piker---->
<link rel="stylesheet" href="~/Content/jquery-ui.css" />
<script src="~/Scripts/jquery-ui.js"></script>
<script>
$(function () {
$("#datepicker,#datepicker1").datepicker();
});
</script>
<!---/End-date-piker---->
<div class="col-md-3 dropdown-button">
<div class="book_date">
<form>
<input class="date" id="datepicker" type="text" value="Przyjazd" onfocus="this.value = '';" onblur="if (this.value == '') {this.value = 'Przyjazd';}">
<!-- #Html.TextBoxFor(m => m.CheckIn, new { #class = "date" })
#Html.ValidationMessageFor(m => m.CheckIn, "", new { #class = "datefield" })-->
</form>
</div>
</div>
<div class="col-md-3 dropdown-button">
<div class="book_date">
<form>
<input class="date1" id="datepicker1" type="text" value="Wyjazd" onfocus="this.value = '';" onblur="if (this.value == '') {this.value = 'Wyjazd';}">
<!--#Html.TextBoxFor(m => m.CheckOut, new { #class = "date1" })
#Html.ValidationMessageFor(m => m.CheckOut, "", new { #class = "datefield" })-->
</form>
</div>
</div>
<div class="col-md-3 dropdown-button">
<div class="section_1">
<select id="country" onchange="change_country(this.value)" class="frm-field required">
<option value="null">Dwuosobowy</option>
<option value="null">Jednoosobowy</option>
<option value="AX">Apartament</option>
<option value="AX">Gościnny</option>
</select>
</div>
</div>
<div class="clearfix"> </div>
</div>
<div class="col-md-2 submit_button">
<form >
<input type="submit" value="SZUKAJ">
<!-- <p> #Html.ActionLink("SZUKAJ", "Book1", "Home")</p>-->
</form>
</div>}
And here's my code in the controller. For now I try to retrieve only a name, to see if it's working.
[HttpPost]
public ActionResult UploadRoomSearchData(FormCollection form)
{
string name = Request["YourName"].ToString();
StringBuilder sbRoom = new StringBuilder();
sbRoom.Append("<b>Amount :</b> " + name + "<br/>");
//return RedirectToAction("Book1");
return Content(sbRoom.ToString());
}
I also tried something like this:
foreach(var v in form)
{
Write.Response("name:" + v);
}
I tried your code and it seems to work.
First I have the controller method to display the form
public ActionResult CreatePerson()
{
Person model = new Person();
return View(model);
}
Then the form:
#model RetrieveDataFromaView.Models.Person
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Person</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.YourName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.YourName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.YourName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="submit" class="btn btn-default" />
</div>
</div>
</div>
}
Which does a post to the controller method
[HttpPost]
public ActionResult CreatePerson(FormCollection formCollection)
{
string name = Request["YourName"].ToString();
StringBuilder sbRoom = new StringBuilder();
sbRoom.Append("<b>Amount :</b> " + name + "<br/>");
return Content(sbRoom.ToString());
}
This returns a view with only the content of the StringBuilder.
Maybe you are looking for RedirectToAction?
Hello you have this line inside the form:
#Html.AntiForgeryToken()
You can remove it or add the corresponding attribute to use it:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreatePerson(FormCollection formCollection)
{
///Your code here
}
Basically this is a token generated for the server to avoid requests from forms not generated by the server.
You have many ways of retrieving data from a form Post in ASP.NET MVC.
Using a Model
Usually, forms are created by specifying a Model type in the Razor view. You can use that type to retrieve the data. ASP.NET MVC will parse the body and populate the object in parameter for you.
Ex:
Controller:
public class HomeController: Controller
{
[HttpGet]
public ActionResult Index()
{
return View(new Person());
}
[HttpPost]
public ActionResult Index(Person p)
{
//Just for the sake of this example.
return Json(p);
}
}
Razor view
#model WebApplication2.Models.Person
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<title>title</title>
</head>
<body>
<div>
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div>
#Html.LabelFor(m => m.FirstName): <br/>
#Html.TextBoxFor(m => m.FirstName)
</div>
<div>
#Html.LabelFor(m => m.LastName): <br/>
#Html.TextBoxFor(m => m.LastName)
</div>
<input type="submit" value="Submit" />
}
</div>
</body>
</html>
Using a FormsCollection
The FormsCollection object allows you to access the raw values of a form. It acts as a Dictionary for the Forms value. This is useful, especially when you have a dynamic model to parse, or if you just plain don't know about the Model type.
It's also pretty straightforward to use.
[HttpPost]
public ActionResult Index(FormCollection form)
{
var dict = form.AllKeys.ToDictionary(key => key, key => form[key]);
return Json(dict);
}
PS: I saw you are using Request[key]. It may just be me, but this call just looks like Dark magic, where you get data from who knows where (it uses the Query String, the cookies, the Request body, etc. It seems like it could be really problematic in some cases in the future. I much prefer knowing exactly where the data comes from. But that may just be me.
Conclusion
In conclusion, use the Model approach if you know exactly what should be in the Form. Use the FormCollection approach if you really need to. That's pretty much it.
Good luck.
I am new as MVC 5, I have create a new project and I am setting up the login (With external login).
This is using the VIsual Studio 2013 MVC 5 Application template
So what is happening is when I click the button for a social media login I am getting an error of the wrong model being passed
The model item passed into the dictionary is of type
'WebPortal.Models.LoginViewModel', but this dictionary requires a
model item of type 'WebPortal.Models.ExternalLoginListViewModel'.
If you need the controls and model code let me know. But as I said this is the default code that came with the template. The only things I have been changing is the View at this point to change the look. And have posted the View Code below.
I think the issue is that since I am starting from the Layout page, the model is never being initiated since there is no model for the layout.... Again I am new so I am only guessing.
Here is the Partial path
"_Layout" -> "_SocialBar"(Partial View) -> "Login"(Partial View) -> "LoginPartial"(Partial View) -> "_ExternalLoginsList"(Partial View)
SocialBar (Partial View)
<div class="header-top dark ">
<div class="container">
<div class="row">
<div class="col-xs-3 col-sm-6 col-md-9">
...Some Code....
<!-- header-top-first end -->
</div>
<div class="col-xs-9 col-sm-6 col-md-3">
#Html.Partial("_Login")
</div>
</div>
</div>
</div>
Login Partial View page
#using Microsoft.AspNet.Identity
#if (Request.IsAuthenticated)
{
...Some Code...
}
else
{
...Some Code...
#Html.Partial("_LoginPartial")
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
LoginPartial View Code
#using WebPortal.Models
#model LoginViewModel
#using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { role = "form" }))
{
#Html.AntiForgeryToken()
<form class="login-form margin-clear">
<div class="form-group has-feedback">
<label class="control-label">#Html.LabelFor(m => m.Email)</label>
#Html.TextBoxFor(m => m.Email, new { #class = "form-control" })
<i class="fa fa-user form-control-feedback"></i>
</div>
<div class="form-group has-feedback">
<label class="control-label">#Html.LabelFor(m => m.Password)</label>
#Html.PasswordFor(m => m.Password, new { #class = "form-control" })
<i class="fa fa-lock form-control-feedback"></i>
</div>
<div class="form-group has-feedback">
#Html.CheckBoxFor(m => m.RememberMe)
<label class="control-label">#Html.LabelFor(m => m.RememberMe)</label>
</div>
<input type="submit" value="Log in" class="btn btn-gray btn-sm" />
<span class="pl-5 pr-5">or</span>
#Html.ActionLink("Sign Up", "Register", "Account", null, new { #class = "btn btn-default btn-sm" })
<div class="form-group has-feedback">
Forgot your password?
</div>
#Html.Partial("../Account/_ExternalLoginsList")
</form>
}
ExternalLogin List Code
#model WebPortal.Models.ExternalLoginListViewModel
#using Microsoft.Owin.Security
#{
var loginProviders = Context.GetOwinContext().Authentication.GetExternalAuthenticationTypes();
if (loginProviders.Count() == 0)
{
<span class="text-center">No External Logins</span>
}
else
{
<span>Login with   
#foreach (AuthenticationDescription p in loginProviders)
{
switch (#p.AuthenticationType)
{
case "Facebook":
<button type="submit" class="btn btn-xsm facebook" id="#p.AuthenticationType" name="provider" value="#p.AuthenticationType"><i class="fa fa-facebook"></i></button>
break;
case "Twitter":
<button type="submit" class="btn btn-xsm twitter" id="#p.AuthenticationType" name="provider" value="#p.AuthenticationType"><i class="fa fa-twitter"></i></button>
break;
case "Google":
<button type="submit" class="btn btn-xsm googleplus" id="#p.AuthenticationType" name="provider" value="#p.AuthenticationType"><i class="fa fa-google-plus"></i></button>
break;
case "Microsoft":
<button type="submit" class="btn btn-xsm microsoft" id="#p.AuthenticationType" name="provider" value="#p.AuthenticationType"><i class="fa fa-windows"></i></button>
break;
default:
<button type="submit" class="btn btn-xsm" id="#p.AuthenticationType" name="provider" value="#p.AuthenticationType">#p.AuthenticationType.ToString()</button>
break;
}
}
</span>
}
}
When you do #Html.Partial() and don't provide it a model, it uses the current (or parent, if you want to think of it that way) model instead. So when you do
#Html.Partial("../Account/_ExternalLoginsList")
Without the second parameter to specify the model, it provides the current one. You should be providing a view model to the partial like so:
#Html.Partial("../Account/_ExternalLoginsList", externalLoginsViewModel)
Otherwise you'll provide the current one, which is not the same type that is expected by the partial.
The ExternalLoginList partial expects a model to be passed to it.
#model WebPortal.Models.ExternalLoginListViewModel
You need to pass the model in here:
#Html.Partial("../Account/_ExternalLoginsList")
Like this:
#Html.Partial("../Account/_ExternalLoginsList", new ExternalLoginListViewModel())
OR
Put the partial's model in the parent's model
public class LoginViewModel
{
public ExternalLoginListViewModel externalLoginListViewModel;
}
and pass it to the partial.
#Html.Partial("../Account/_ExternalLoginsList", externalLoginListViewModel)
OR
I don't see any references to the model in the ExternalLoginList partial so you can probably just delete this line:
#model WebPortal.Models.ExternalLoginListViewModel