Error passing between Model and ViewModel? - asp.net-mvc

In the previous question "ASP .NET Core Repository Id Article passed in was changed to 0?" I did it successfully, but due to a conflict with the team on GitHub, I had to rewrite my code. However, when I run it, I have a transmission error between Model and ViewModel. What is this and how do I fix it? I don't change anything between my code.
Controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EditArticle(Article article)
{
if(!ModelState.IsValid)
{
return View(article);
}
if(!_studentRepository.EditArticle(article))
{
throw new ArgumentException("...");
}
return RedirectToAction("Index");
}
View
#model Megatron.ViewModels.ArticleFacultyViewModel
#{
ViewData["Title"] = "Edit Article";
}
<div>
<form asp-action="EditArticle">
<partial name="_StatusMessage" model="#ViewData["Message"]" />
<div>
#Html.HiddenFor(a => a.Article.Id)
<div class="form-group row">
<div class="col-2">
<label asp-for="Article.Title" class="col-form-label"></label>
</div>
<div class="col-5">
<input asp-for="Article.Title" class="form-control" />
</div>
</div>
<div class="form-group row">
<div class="col-2">
<label class="col-form-label">Type of contribution</label>
</div>
<div class="col-3">
<button hidden class="btn btn-primary" type="button" data-toggle="collapse" data-target="#ImportFileCollapse" aria-expanded="false" aria-controls="ImportFileCollapse">
</button>
<button hidden class="btn btn-primary" type="button" data-toggle="collapse" data-target="#TextAreaCollapse" aria-expanded="false" aria-controls="TextAreaCollapse">
</button>
<button id="button-collapse" class="btn btn-primary" type="button" data-toggle="collapse" data-target=".multi-collapse" aria-expanded="false" aria-controls="ImportFileCollapse TextAreaCollapse">
Switch to Editor
</button>
</div>
</div>

You return a Artical type model to the View in the post method,
if(!ModelState.IsValid)
{
return View(article);
}
While the view expect a
ArticleFacultyViewModel type model. You may convert it.
if(!ModelState.IsValid)
{
var articleVM = new ArticleFacultyViewModel
{
Article = article,
Faculties = _facultyRepository.GetFaculties()
};
return View(articleVM);
}

Related

Button Submit in MVC is not working as expected

I have a submit button in index.cshtml page and when i click that button i need to go in another ActionResult server method.But it's not working.(not hitting to the server side method)
Html
#model IEnumerable<AAB.Domain.Items>
<!-- Featured Products -->
<div class="card-deck card-deck-product mt-3 mb-2 mb-sm-0">
#foreach (var item in Model)
{
<div class="card card-product" id="#item.ItemId">
<div class="card-body">
<button class="wishlist atw-demo " title="Added to wishlist"><i data-feather="heart"></i></button>
<img class="card-img-top" src="#item.ImageUrl" alt="Card image cap">
#item.ItemName
<div class="price"><span class="h5">Rs:#item.ItemPrice</span></div>
</div>
<div class="card-footer">
<input type="submit" class="btn btn-sm" id="#item.ItemId" value="Add to Cart" href="#Url.Action("AddNewItems","Home",new { ItemId=item.ItemId})"/>
</div>
</div>
}
</div>
Server side
[HttpPost]
public ActionResult AddNewItems(int ItemId)
{
// Some code here.
return PartialView("_PopCart", ItemId);
}
Surround your button with a tag.
<a href="#Url.Action("AddNewItems","Home",new { ItemId=item.ItemId})">
<input type="submit" class="btn btn-sm" id="#item.ItemId" value="Add to Cart" />
</a>

How can I return text to my current mvc view?

I have a login page within an ASP.NET Core App with a pop up to send a password reset email to the users email (Just using Identity):
<div class="login-body">
<div class="container">
<form asp-controller="Account" asp-action="Login" asp-route-returnurl="#ViewData["ReturnUrl"]" method="post" class="form-signin">
<h2 class="form-signin-heading">#Localizer["Sign In"]</h2>
<div class="login-wrap">
<div class="user-login-info">
<input asp-for="Email" type="email" class="form-control" placeholder="#Localizer["Email"]" autofocus/>
<span asp-validation-for="Email" class="text-danger"></span>
<input asp-for="Password" type="password" class="form-control" placeholder="#Localizer["Password"]"/>
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<label class="checkbox">
<input asp-for="RememberMe"/> Remember me
<span class="pull-right">
<a data-toggle="modal" href="#forgotPassModal">Reset Password</a>
</span>
</label>
<button class="btn btn-lg btn-login btn-block" type="submit">#Localizer["Sign In"]</button>
<div class="registration">
#Localizer["No Account"]
<a asp-area="" asp-controller="Account" asp-action="Register">#Localizer["Create Account"]</a>
</div>
</div>
<!-- Modal -->
<div aria-hidden="true" aria-labelledby="myModalLabel" role="dialog" tabindex="-1" id="forgotPassModal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Reset Password</h4>
</div>
<div class="modal-body">
<p>Enter your e-mail address below to reset your password.</p>
<input type="text" name="email" placeholder="Email" autocomplete="off" class="form-control placeholder-no-fix">
</div>
<div class="modal-footer">
<button data-dismiss="modal" class="btn btn-default" type="button">Cancel</button>
<button class="btn btn-success" asp-controller="Account" asp-action="ForgotPassword" method="post">Submit</button>
#*<input type="button" class="btn btn-success" asp-controller="Account" asp-action="ForgotPassword" formmethod="post">Submit<input>*#
</div>
</div>
</div>
</div>
<!-- modal -->
</form>
</div>
When I input the email address it does the right thing, sends an email with a code, but it redirects me to a separate view stating to go check your emails.
Is it possible to just return a message either to the popup window or login page saying the same thing?
This is the ForgotPassword Action:
public async Task<IActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindByEmailAsync(model.Email);
if (user == null || !(await UserManager.IsEmailConfirmedAsync(user)))
{
return View("ForgotPasswordConfirmation");
}
var code = await UserManager.GeneratePasswordResetTokenAsync(user);
var callbackUrl = Url.Action(nameof(ResetPassword), "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
await _emailSender.SendEmailAsync(model.Email, "Reset Password",
$"Please reset your password by clicking here: <a href='{callbackUrl}'>link</a>");
return View("ForgotPasswordConfirmation");
}
return View(model);
}
What you can use is TempData. TempData can hold data for one more additional request and only for one additional request. So you can store this information in the TempData. It is meant for things like your use case. It could look something like this.
public IActionResult Login()
{
var loginModel = new LoginModel();
loginModel.ForgotPassWordModel = (ForgotPassWordModel) TempData["ForgotPassword"];
return View(loginModel);
}
public IActionResult ForgotPassword()
{
if (valid)
{
TempData["ForgotPassword"] = new ForgotPassWordModel() {callbackUrl = "Go to this"};
return RedirectToAction("Login");
}
return View();
}
Here is my example LoginModel and my ForgottonPasswordModel. Ofcourse, yours will be more complicated.
public class ForgotPassWordModel
{
public string callbackUrl;
}
public class LoginModel
{
public ForgotPassWordModel ForgotPassWordModel { get; set; }
}
When someone makes a request to ForgotPassword, if it is valid, store the result in TempData and Redirect back to Login. Now you can read the TempData["ForgotPassword"] that you just set in the previous request. In my example, I put the data in my LoginModel. If there is no tempData, it would be null. Now in your view you can check for this ForgotPassword property.
#if (Model.ForgotPassWordModel != null)
{
// Show message/modal
}
The great thing about TempData is that when you set data, it is only held for one more additional request so it works for situations like these.

MVC refresh table data in modal using entity framework

good day. how can I refresh a modal table data? well, I have this textbox that when a user clicks show a modal pop-up. inside the pop-up is a partial view with the table and a search. When a user searches, instead of reloading the value in the modal, it redirects me to the partial view itself. I have seen a lot of examples like this one -- https://forums.asp.net/t/2098629.aspx?Advance+search+in+a+MVC+Popup+Window+ -- but still cannot go through it. its basically a modal popup but contains a partial view in it, once the search was clicked, just need to reload the table and no more. thanks in advance
Partial View Code:
public ActionResult ShowTaxPayer(int? page, string searchString)
{
var user = (from u in db2.Payers
select new Taxpayer
{
ID = u.objid,
Firstname = u.firstname,
Lastname = u.lastname,
Middlename = u.middlename,
Address = u.primaryaddress
});
if (string.IsNullOrEmpty(searchString))
{
return View(user.ToList().ToPagedList(page ?? 1, 10));
}
else
{
return View(user.Where(s => s.Firstname.Contains(searchString)).ToList().ToPagedList(page ?? 1, 10));
}
}
Razor:
#using (Html.BeginForm("Index", "Wizard", FormMethod.Post))
{
#Html.ValidationSummary(true)
<fieldset>
<div class="wizard-step">
#Html.Label("Taxpayer Name")
#Html.TextBoxFor(m => m.taxpayername, new { data_toggle = "modal", data_target = "#myModal", data_backdrop = "static", data_keyboard = "false" })
#Html.ValidationMessageFor(m => m.taxpayername)
</div>
<div class="wizard-step">
#Html.Label("Taxpayer Address")
#Html.EditorFor(m => m.taxpayeraddress)
#Html.ValidationMessageFor(m => m.taxpayeraddress)
</div>
<div class="wizard-step">
#Html.Label("Trade Name")
#Html.EditorFor(m => m.tradename)
#Html.ValidationMessageFor(m => m.tradename)
</div>
<div class="wizard-step confirm">
</div>
<p>
<input type="button" id="back-step" name="back-step" value="<-- Back" />
<input type="button" id="next-step" name="next-step" value="Next -->" />
</p>
</fieldset>
}
The Modal:
<div class="modal fade" id="myModal" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">Modal title</h4>
</div>
<div class="modal-body">
#{Html.RenderAction("ShowTaxPayer", "Wizard");}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
I just need to load the data from my model in the modal and not redirect me to the actual view. Thanks in advance.
Here the Model Popup
<div class="modal-body">
#{Html.RenderAction("ShowTaxPayer", "Wizard");}
</div>
and changed to
<div class="modal-body" id="popupTableName">
</div>
and Add Javascript
<script>
window.onload = LoadTable();
function LoadTable(){
$.get( '#Url.Action("actionName","ControllerName", new { id = Model.ID } )', function(data) {
$('#popupTableName').html(data);
});
}
function onChange(){
LoadTable();
}
</script>

I need to call a controller by passing the param from the view on clicking the ActionLink

I am trying to search a student and display the student record based on the value entered on textbox. I am not sure how to pass the value without using Jquery. Is there a way.
Controller:
[Authorize]
public ActionResult GetStudentsByName(string name)
{
SchoolDbEntities db = new SchoolDbEntities();
var student = db.Students.Where(s => s.StudentName.Contains(name));
return View(student);
}
View
<div class="panel-body">
<div class="form-group">
#Html.LabelFor(m=> m.SearchEntity.StudentName,"Search Student")
#Html.TextBoxFor(m => m.SearchEntity.StudentName, new { #class = "form-control" })
</div>
</div>
<div class="panel-footer">
<button type="button" onclick="location.href='#Url.Action("GetStudentsByName", "Student")'" class="btn btn-primary">Search <i class="glyphicon glyphicon-search"></i></button>
<button id="Reset"
class="btn btn-primary btn-sm">
<i class="glyphicon glyphicon-share-alt"></i> Reset
</button>
</div>
I need to pass the param , In the #Url.Action("GetStudentsByName", "Student", new {#name= 'value from the textbox')
Also it is a Get Method and not httpPost.
You can keep the input form element inside a form control and submit the form via GET method.
Make sure the input element name matches with your action method parameter name
#using (Html.BeginForm("GetStudentsByName","Student",FormMethod.Get))
{
<input type="text" name="name"/>
<button type="submit" class="btn btn-primary">Search </button>
}
If you dont wanna make the button a submit button then by giving your text box a specific class you can do it .
<div class="panel-body">
<div class="form-group">
#Html.LabelFor(m=> m.SearchEntity.StudentName,"Search Student")
#Html.TextBoxFor(m => m.SearchEntity.StudentName, new { #class = "form-control,txt-input" })
</div>
</div>
<div class="panel-footer">
<button type="button" onclick="location.href='#Url.Action("GetStudentsByName", "Student",new { data= "STUDENT_NAME" })'.replace("STUDENT_NAME", $('.txt-input').val())" class="btn btn-primary">Search <i class="glyphicon glyphicon-search"></i></button>
<button id="Reset"
class="btn btn-primary btn-sm">
<i class="glyphicon glyphicon-share-alt"></i> Reset
</button>
</div>
I tried something like this long back , i think it should work.
Try this
View
#using (Html.BeginForm("GetStudentsByName", "Home"))
{
<div class="form-group">
#Html.LabelFor(m => m.StudentName, "Search Student")
#Html.TextBoxFor(m => m.StudentName, new { #class = "form-control" })
</div>
<input type="submit" value="Search" class="btn btn-primary" />
}
</div>
Controller
public ActionResult GetStudentsByName()
{
string name = Request.Form["StudentName"]
SchoolDbEntities db = new SchoolDbEntities();
var student = db.Students.Where(s => s.StudentName.Contains(name));
return View(student);
}
using Request.Form["StudentName"] you can access the value from view to controller. Also, one more suggestion, use using statement it helps to manage unhandled memory. For example
public ActionResult GetStudentsByName()
{
string name = Request.Form["StudentName"]
using(SchoolDbEntities db = new SchoolDbEntities())
{
var student = db.Students.Where(s => s.StudentName.Contains(name));
return View(student);
}
}

getting null value for HttpPostedFileBase in mvc controller

I want to give user the option to change their profile picture.On hitting the save button my controller action is hit but I get null value for HttpPostedFileBase.I am uploading files first time in mvc so not able to figure out where I am doing wrong and hence getting null value in controller.
controller
[AuthenticationRequired]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ChangeProfilePicture(HttpPostedFileBase imageData)
{
}
view
#using (Ajax.BeginForm("ChangeProfilePicture", "Account", new { enctype = "multipart/form-data" },new AjaxOptions { OnSuccess = "OnSuccess" }))
{
#Html.AntiForgeryToken()
<div class="modal-body" id="tilesDescription">
<div class="row">
<div class="col-md-12">
<div class="text-center">
<div class="fileUpload btn btn-primary">
<span>Select a photo from your computer</span>
<input id="uploadBtn" type="file" class="upload" name="imageData" accept="image/*" />
</div>
<div class="text-center">
<img id="imgprvw" alt="uploaded image preview" class="imgPreview hide" />
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-rounded btn-sm btn-tiles" data-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-rounded btn-sm btn-tiles disabled" id="btnProfilePic">Set as profile picture</button>
</div>
}
You cannot post your file using ajax like that, cause is not supported.
From my experience, the easiest way to get files posted using Ajax (if using jquery), is using :
http://malsup.com/jquery/form/

Resources