Using hidden fields during HTTP post for the reload of same page postback - asp.net-mvc-3

I have a View where the User can leave a feedback comment in regards to the content video that is playing on the page. Using the following code I am able to manually enter the UserID and ContentID and it saves to the database without problem.
#using (Html.BeginForm("Screencast", "Media", FormMethod.Post, new { id = "form", enctype = "multipart/form-data" }))
{
<div class="row">
<div class="six columns">
<div class="row">
<div class="six columns">
#Html.LabelFor(c => c.FeedbackComment.UserID)
#Html.TextBoxFor(c => c.FeedbackComment.UserID)
</div>
<div class="six columns">
#Html.LabelFor(c => c.FeedbackComment.ContentID)
#Html.TextBoxFor(c => c.FeedbackComment.ContentID)
</div>
<div class="row">
<div class="twelve columns">
#Html.LabelFor(c => c.FeedbackComment.FeedbackString)
#Html.TextAreaFor(c => c.FeedbackComment.FeedbackString)
</div>
</div>
</div>
</div>
</div>
<input type="submit" value="Submit button" class="medium button bottom20"/>
}
However, when the user is on the page before the HTTP post I actually have the related variables in my Model called:
Model.User.UserID
Model.SelectedItem.ContentID
I want to pass these in as hidden fields but when I try to do either:
#HtmlHiddenFor(c => c.FeedbackComment.UserID, #Model.User.UserID)
#HtmlHiddenFor(c => c.FeedbackComment.ContentID, #Model.SelectedItem.ContentID)
or
#HtmlHidden("UserID",#Model.User.UserID)
#HtmlHidden("ContentID",#Model.User.UserID)
Then these values are returned null despite the values being populated before the post. I read about a workaround of putting the input tags in manually but when I did this the #Using.HtmlBeginForm was returning an error of not being set to an instance of an object
Can someone please help me to understand how I can pass these values to the same page using the values I have in the model prior to the post.

Given the following view model (partial):
public class YourViewModel
{
public User User { get; set; }
public SelectedItem SelectedItem { get; set; }
}
You can bind the these properties to a hidden form element. When you post back these properties will still contain their values.
#Html.HiddenFor(x => x.User.UserID)
#Html.HiddenFor(x => x.SelectedItem.ContentID)
Your action method:
public ActionResult YourActionMethod(YourViewModel viewModel)
{
// When you debug here you will see that the values are retained
}
I hope this helps.

Related

View data from another controller in ASP.NET Core MVC

I'm trying to build an ASP.NET Core 6 MVC app.
I have two controllers 'home' and 'work'. How can I display data from 'work' model in the home/index view?
Unfortunately, I don't know the terminology to better formulate the question, but actually I want to achieve that on the home page I can display the last few works.
The part where I enter/edit data works fine. When I go to the /Works/Index page, I see all the entered data. How to display, for example, the last 4 on the home page of the application
In index.cshtml I have
#model IEnumerable<Website.Models.Work>
#foreach (var item in Model)
{
<div class="col-lg-3 col-sm-6">
<div class="gallery-item wow fadeInUp delay-0-2s">
<img src="~/assets/images/gallery/gallery-1.jpg" alt="Gallery">
<div class="gallery-content">
<span class="category">#Html.DisplayFor(modelItem => item.Tag)</span>
<h5>#Html.DisplayFor(modelItem => item.Headline)</h5>
</div>
</div>
</div>
}
But I get an error:
System.NullReferenceException: Object reference not set to an instance of an object.
If you just want to know how to display the data on page, here is a working demo below:
HomeController
public class HomeController: Controller
{
private readonly YourDbContext _context;
public HomeController(YourDbContext context)
{
_context = context;
}
public IActionResult Index()
{
//get the last 4 records...
var model = _context.Work.AsEnumerable().Reverse().Take(4).ToList();
return View(model);
}
}
Home/Index.cshtml
#model IEnumerable<Website.Models.Work>
#foreach (var item in Model)
{
<div class="col-lg-3 col-sm-6">
<div class="gallery-item wow fadeInUp delay-0-2s">
<img src="~/assets/images/gallery/gallery-1.jpg" alt="Gallery">
<div class="gallery-content">
<span class="category">#Html.DisplayFor(modelItem => item.Tag)</span>
<h5>#Html.DisplayFor(modelItem => item.Headline)</h5>
</div>
</div>
</div>
}

Razor Pages Net Core auto reload partial view on set frequency

I am still trying to get to grips with Razor Pages for Net Core and seem to be a bit stuck on this. I have my Index.cshtml:
#page
#model IndexModel
<input type="hidden" name="hdnPageSelector" id="hdnIndexPage" />
<div class="text-center">
<p>Welcome to</p>
<h1 class="display-4">"My Web App"</h1>
</div>
<div class="form-row">
<div class="form-group col-md-2">
<partial name="IndexPartials/_Navigation" />
</div>
<div class="form-group col-md-1">
</div>
<div class="form-group col-md-6">
<partial name="IndexPartials/_Body" />
</div>
<div class="form-group col-md-1">
</div>
<div id="refreshMembers" class="form-group col-md-2">
<partial name="IndexPartials/_Members" />
</div>
</div>
Note the last div has an id="refreshMembers".
The partial view (_Members) that is loaded there looks like this:
#model IndexModel
<label>Members</label>
<br />
#{
foreach (ApplicationUser user in Model.AppUsersList)
{
if (user.IsLoggedIn)
{
<label>#user.FirstName #user.LastName </label>
<span class="dot"></span>
}
else
{
<label>#user.FirstName #user.LastName</label>
}
}
}
Within the controller I have a property called:
public IList<ApplicationUser> AppUsersList { get; set; }
And this is populated on OnGetAsync() as follows:
AppUsersList = _userManager.Users.OrderBy(x => x.FirstName).Where(y => y.UserName != currentUser.UserName).ToList();
This is fine, the page loads with the partial view populated as expected. I now want the partial to refresh every 5 seconds so I have put this piece of Javascript/JQuery in place:
$(function () {
setInterval(function () {
$("#refreshMembers").load("/Index?handler=RefreshMembers");
}, 5000);
});
with the following method setup:
public async Task<IActionResult> OnGetRefreshMembers()
{
var currentUser = await _userManager.GetUserAsync(User);
AppUsersList = _userManager.Users.OrderBy(x => x.FirstName).Where(y => y.UserName != currentUser.UserName).ToList();
return new PartialViewResult
{
ViewName = "_Members",
ViewData = new ViewDataDictionary<List<ApplicationUser>>(ViewData, AppUsersList)
};
}
However the partial view doesn't get refreshed. If I put a breakpoint within this method I can see it is being hit every 5 seconds, despite Devtools stating there is an error on each attempt:
In a nut shell, I just can't seem to get my partial view to be reloaded every 5 seconds. It feels like I am close but just missing something and don't know what that is.
Having been reminded to check the Output window in VS a bit better, I found the cause of my problems... Well two things actually. This is the corrected method:
public async Task<IActionResult> OnGetRefreshMembers()
{
var currentUser = await _userManager.GetUserAsync(User);
AppUsersList = _userManager.Users.OrderBy(x => x.FirstName).Where(y => y.UserName != currentUser.UserName).ToList();
return new PartialViewResult
{
ViewName = "IndexPartials/_Members",
ViewData = new ViewDataDictionary<IndexModel>(ViewData, this)
};
}
Where...
I didn't include the folder that the partial lives in when naming it on the PartialViewResult
I need to return the entire IndexModel object - having updated the AppUserList property, and not just the list of AppUsers.

MVC3 RenderPage never renders content

So I have this master/detail setup with a WebGrid. All is well until I try and use RenderPage to display the detail when a record is clicked:
<div class="innerbox">
#{
if(gdEligibility.HasSelection){
#RenderPage("~/Views/Eligibility/EligibilityPolicyDetailView.cshtml",
new { Customer = gdEligibility.SelectedRow })
}
}
</div>
Everything works, if I put a break point I can step through the detail view's cshtml file no problem, no errors. But nothing is ever rendered between the outer div's. Ever. Why doesn't RenderPage return anything? I even tried adding .ToHtmlString() on the end of the line but still nothing.
The detail cshtml:
#{ foreach(TravelInsurance.Models.Policy p in Page.Customer.Policies){
<fieldset>
<legend>Policy</legend>
<div class="display-label">Policy Number</div>
<div class="display-field">
#Html.DisplayFor(model => p.PolicyNumber)
</div>
<div class="display-label">Premium</div>
<div class="display-field">
#Html.DisplayFor(model => p.Premium)
</div>
</fieldset>
}}
This question suggests that RenderPage will use the parent model...
Maybe try using
#{Html.RenderPartial("EligibilityPolicyDetailView", new { Customer = gdEligibility.SelectedRow });}
or
#Html.Partial("EligibilityPolicyDetailView" ,new { Customer = gdEligibility.SelectedRow })
Pl. try again by removing the attribute "ajaxUpdateContainerId" in the grid definition and it should work.

Mvc3 IEnumerable<QuestionModel> have a List<QuestionOptionModel> property. When I post, I get null list

I'm making a survey application. Survey has Questions and Questions have QuestionOption. haveThere is a example here.
I am trying to use this technique in a large form with a list(List) but when I post back, the Viewmodel.Order that should’ve contained list of items and activities return with the lists empty.
My QuestionModel.cs like this.
public int Id { get; set; }
public string QuestionText { get; set; }
public System.Nullable<bool> OptionType1 { get; set; }
public System.Nullable<bool> OptionType2 { get; set; }
public List<QuestionOptionModel> OptionList = new List<QuestionOptionModel>();
When I post back "IEnumerable questions" List OptionList comes null. How can I do this?
public ActionResult CallSurvey()
{
IEnumerable<QuestionModel> questionModelList = (IEnumerable<QuestionModel>)SessionHelper.GetSessionObject(SessionKeys.SurveyKey);
questionModelList = questionSrv.GetQuestionModel();
return View(questionModelList);
}
questionModelList include all my survey question and question options. When I post it, post back is coming with only null optionList.
[HttpPost]
public ActionResult CallSurvey(IEnumerable<QuestionModel> questions)
{ ..... }
CallSurvey.cshtml
<body>
#using ((Html.BeginForm()))
{
#ViewBag.Test
<section class="slides layout-regular template-kendo">
#foreach (var item in Model)
{<article>
#Html.Partial("QuestionEditor", item)
</article>
}
<div class="slide-area" id="prev-slide-area"></div>
<div class="slide-area" id="next-slide-area"></div>
</section>
}
</body>
QuestionEditor.cshtml
#model LSMM.Business.Model.Survey.QuestionModel
#using LSMM.Web.Helpers
<div>
#using (Html.BeginCollectionItem("Questions"))
{
<table id="table1">
<tr>
<td>
<div id="#Model.Id" class="hint">
#Html.HiddenFor(m => m.Id)
#Html.HiddenFor(m => m.QuestionText)
#Html.HiddenFor(m => m.OptionType1)
#Html.HiddenFor(m => m.OptionType2)
#for (int i = 0; i < Model.OptionList.Count; ++i)
{
#Html.LabelFor(m => m.OptionList[i].Id)
#Html.LabelFor(m => m.OptionList[i].QuestionId)
#Html.LabelFor(m => m.OptionList[i].Checked)
#Html.LabelFor(m => m.OptionList[i].Description)
#Html.LabelFor(m => m.OptionList[i])
}
<span id="sorular">#Model.Id. #Model.QuestionText</span>
<br />
<br />
</div>
</td>
</tr>
<tr>
<td>
<div class="hint2">
#Html.Partial("QuestionOptionEditor", Model)
</div>
</td>
<td>
<div id="#Model.Id-Img">
<h2 style="top: 200px; right: 0;">
<img src="../../Content/css/img/#Model.Id-Img.png"></h2>
</div>
</td>
</tr>
</table>
and QuestionOptionEditor.cshtml
#model LSMM.Business.Model.Survey.QuestionModel
#using LSMM.Web.Helpers
#foreach (var option in #Model.OptionList)
{
<p>
#if (#Model.OptionType1 == false)
{
#Html.Partial("QuestionOptionModel", option)
}
else
{
#Html.Partial("../Shared/DisplayTemplates/QuestionOptionModel", option)
}
</p>
}
Here QuestionOptionModel views like this;
#model LSMM.Business.Model.Survey.QuestionOptionModel
#(Html.RadioButtonFor(m => m.Id, true, new { Id = #Model.Id, Name = #Model.QuestionId })) #Html.Label("Evet")
<br />
<br />
#(Html.RadioButtonFor(m => m.Id, false ,new { Id=#Model.Id, Name = #Model.QuestionId})) #Html.Label("Hayır")
The name attribute on your radio buttons is not "correct" according to the naming rules used by the default ModelBinder. That's why you aren't seeing the values you expect, the ModelBinder couldn't find what it was looking for.
This is easy to fix and you should end up with less code.
Take advantage of the framework and let it do work for you:
MVC can loop IEnumerables for you. Let it. There's little reason to write foreach loops in views these days.
Get rid of those partials. Use MVC's Templates feature instead.
Then your view can be as simple as:
<body>
#using ((Html.BeginForm()))
{
#ViewBag.Test
<section class="slides layout-regular template-kendo">
<table id="table1">
#* Table header goes here *#
#Html.EditorFor(model => model.OptionList)
</table>
<div class="slide-area" id="prev-slide-area"></div>
<div class="slide-area" id="next-slide-area"></div>
</section>
}
</body>
When you use an EditorTemplate or a DisplayTemplate, MVC will automatically fix the name attribute on your form fields. It won't do that with a partial.
Another suggestion, also if you don't mind. Get rid of those nulla-bools on your model and write different QuestionOptionModel types. DisplayTemplate/EditorTemplates are wise to the type system and MVC will pick the template that matches the type it is presented.
So you could have another class that derives from QuestionOptionModel:
public class ExtendedQuestionOptionModel : QuestionOptionModel
{
//Stuff goes here.
}
and you could have a List<QuestionOptionModel> hanging off your model that contains:
QuestionOptionModel
ExtendedQuestionOptionModel
QuestionOptionModel
and when you do this:
#Html.EditorFor(model => model.QuestionOptions)
MVC will go through the option list and render the Editor Template for QuestionOptionModel, then the Editor Template for ExtendedQuestionOptionModel, then the Editor Template for QuestionOptionModel again.
The game you want to play is to try to minimize the C# code in the views, because the views cannot be unit tested. Code that isn't unit tested will eventually come back and get you.
Your question is abit ambiguous. Frankly i hope this is what you are loooking for : IEnumerable can be transformed to list using
List<foo>listFoo =iEnumerableEntityFoo.toList()

The model item passed into the dictionary is of type... ut this dictionary requires a model item of type

I'm new to exploring MVC3 and came up with a problem.
I'm editing my Master view and want the login boxes to be visible on every page when a user isn't logged in. I've done this by using this code:
#if (Request.IsAuthenticated)
{
<text>Welcome <strong>#User.Identity.Name</strong>!
[ #Html.ActionLink("Log Off", "LogOff", "Account") ]</text>
}
else
{
Html.RenderPartial("../Account/LogOn");
}
This works when going to my normal Index method of the HomeController.
However, when going to the Index method of my NewsController I get the following error:
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[LeagueSite.Models.News]', but this dictionary requires a model item of type 'LeagueSite.Models.LogOnModel'.
I understand what the problem is but don't really know a sollution for it.
The view LogOn looks like this (standard MVC3 logon view):
#model LeagueSite.Models.LogOnModel
#{
ViewBag.Title = "Log On";
}
<h2>Login</h2>
<p>
Please enter your user name and password. #Html.ActionLink("Register", "Register") if you don't have an account.
</p>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#Html.ValidationSummary(true, "Login was unsuccessful. Please correct the errors and try again.")
#using (Html.BeginForm()) {
<div>
<fieldset>
<legend>Account Information</legend>
<div class="editor-label">
#Html.LabelFor(m => m.UserName)
</div>
<div class="editor-field">
#Html.TextBoxFor(m => m.UserName)
#Html.ValidationMessageFor(m => m.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(m => m.Password)
</div>
<div class="editor-field">
#Html.PasswordFor(m => m.Password)
#Html.ValidationMessageFor(m => m.Password)
</div>
<div class="editor-label">
#Html.CheckBoxFor(m => m.RememberMe)
#Html.LabelFor(m => m.RememberMe)
</div>
<p>
<input type="submit" value="Log On" />
</p>
</fieldset>
</div>
}
`
Any tips/ideas?
Quick and dirty: instead of Html.RenderPartial use Html.RenderAction:
Html.RenderAction("LogOn", "Account");
and in the LogOn action of the Account controller ensure to return a PartialView or you will get a stack overflow and Cassini will crash:
public ActionResult LogOn()
{
return PartialView();
}
I think your "news" view has already a model associated to it.
maybe it starts like this?:
#model LeagueSite.Models.News
well, if so, if you are not passing a model to your partial view, then the framework assumes by default that the model for that partial is "LeagueSite.Models.News", which of course isn't what you want. You must pass the LogOnModel to your LogOn partial view like this:
Html.RenderPartial("../Account/LogOn", Model.ObjLogonModel);
this assumes that you have an instance of LogonModel into your "News" model. then you'll be able to handle the Logon action
regards

Resources