Custom display template behavior on page refresh - asp.net-mvc-3

I am having an issue with my custom template when page is refreshed. My scenario is that I have multiple address records to be displayed, in which I opted to use custom templates so I won't have to use foreach() to display each record. Here's my custom template code:
#model Address
<div>
#Html.LabelFor(model => model.AddressLine)
#Html.DisplayFor(model => model.AddressLine)
<br />
</div>
Let's say I have 2 address records for display. What's happening is that upon initial page load, it will display 2 records correctly but when page is refreshed, it will display the 2 records again in which now I end up with 4 records on screen. Subsequent page refreshes will display even more duplicates on the screen. My question is, do I need to handle that page refresh event? Or am I just doing something very obviously wrong here?
UPDATE
As requested here is my code for the View and the Action,
View:
#model Patient
<div id="editDetails">
#using(Html.BeginForm("Edit", "Patient"))
{
#Html.DisplayFor(m => m.Addresses)
<input type="submit" value="Submit" />
}
</div>
Action:
public ActionResult Details(string id)
{
Patient patient = patientRepository.GetPatientData(id);
if (patient != null)
{
patientData.GetOtherDetails(patient);
return View(patient);
}
else
return View();
}

Related

Partial view in NET 6

i am lost with NET6.
I created this partial view _MenuNav.cshtml :
#model IEnumerable<CateringMilano.Models.Menu>
#foreach (var item in Model)
{
<div>
<a alt="#item.MenuTitle)">#item.MenuName</a>
<b>#item.MenuTitle</b>
</div>
}
and the cod in my controller is :
// GET: /Menus/_MenuNav/
public ActionResult _MenuNav(string menuPosition)
{
// Get my db
var model = _context.Menu.Include(m => m.ChildMenuSub) as IQueryable<Menu>;
model = model.Where(p => p.MenuPosition == menuPosition);
// Send your collection of Mreations to the View
return PartialView(model);
}
and in the last project with net 4 i use to write the following code in the principal view in order to call my partial view :
#Html.Action("_MenuNav", "Menus", new { menuPosition = "Menu" })
but it looks like it does not work anymore this with NET6
Do you know how to rewrite my code in order to get the same result?
you must be mixing view components with partial views. Partial view were always used like this
<div id="partialName">
<partial name="_PartialName" />
</div>
with model
<partial name="_PartialName" model="Model.MyInfo" />
or for async
<div id="partialName">
#await Html.PartialAsync("_PartialName")
</div>
and the most popular way to update parital view is using ajax
And you can check my answer about viewcomponents here
https://stackoverflow.com/a/69698058/11392290

MVC correct handling of ajax search form and paging

I have a question regarding the ajax and simple filtering. Before writing this post i did read some question more or less regarding this topic, but it is not the same and i didn't receive my answere there!
I have a simple search page, with only few filtering, this filtering should not immidiately be adjustaed to the results or whatever. So when the user changes the filters and click search he gets the result, when he modifies filter nothing should happen until he clicks search again.
So my question is more about handling with the paging, i know how the paging works on the server side with .Skip() .Take() however when i click on the page number, i still have to do an ajax call and submit the same model back just with other page number, but the paging is outside of the form and it doesn't have submit stuff on it ... so how do i resubmit the model back with all the filteres in there?
So here is my view:
#using (Ajax.BeginForm("Index", "Search", new AjaxOptions { UpdateTargetId = "searchResults" }, new { #role = "form", #class = "form-horizontal" }))
{
#Html.AntiForgeryToken();
#Html.EditorFor(m => m.IsOnline)
#Html.EditorFor(m => m.UserLocation)
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">#Base.Search</button>
</div>
</div>
}
And the paging is:
#if(Model.TotalPages>1)
{
<div class="row">
<div class="col-sm-12 col-centered">
<ul class="pagination text-center">
<li class="disabled">«</li>
#{
for(int i = 1; i<=Model.TotalPages; i++)
{
<li><a href="#">#i
#if(Model.CurrentPage==i)
{
<span class='sr-only'>(current)</span>
}
</a></li>
}
}
<li>»</li>
</ul>
</div>
</div>
}
And here is my controller:
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult Index(SearchModel searchModel)
{
if (ModelState.IsValid)
{
searchModel = Operations.GetSearchedListUsers(searchModel);
}
return View(searchModel);
}
So how i see it, even when i click on the page number i should do an index post action and re submit model but for example with other pagenumber how should i do it?
Or is my thinking is totaly wrong and in first place i shouldn't use ajax.form and model??
Please give advice?
Lets start with a general search page.
In search page we will a SearchPage view which have partial view SearchResult view which also may have another paging controls
SearchPage view will have all the control Filter that will keep the states if search, searchResult view update when Search Button is click. To maintain the filter,search keyword and page number and other states we would need to override the default submit and handle all through the ajax calls.
SearchResult view is partial view which will be updated on the searchbutton or Page click.
We might need to create searchModel model that has all the requires attributes:Filters,keyword and Page.
To make everything in ease, we would handle all these secenario in a single action called
Search with SearchModel. The searchModel will return a partialView("SearchResult").
Regarding the ajax call, lets say we have
var keyword=$("#txtKeyword").val();
var filter1=$("#txtFilter11").val();
function SubmitSearch() {
$.ajax({
url: '/Home/Search',
type: 'POST',
data: { keyword: keyword, Filter1: filter1}
timeout: 50000,
success: function (data) {
//Process data
},
error: function (x, t, m) {
if (t === "timeout") {
alert("got timeout");
} else {
alert(t);
}
}
});
}
And you can hook in the search button, page button etc.

passing data from view to controller on asp.net mvc 3

i have problem to pass data from view to controller , i have view that is strongly typed with my viewmodel "TimeLineModel", in the first i passed to this view my viewmodel from action on my controller
public ActionResult confirmation(long socialbuzzCompaignId)
{
return View(new TimeLineModel() { socialBuzzCompaignId = socialbuzzCompaignId, BuzzMessages = model });
}
with this i can get info from my action and display it on view , but i have other action POST which i won't get my view model to do some traitement
[HttpPost]
public ActionResult confirmation(TimeLineModel model)
{
}
i can get some propretie of the model but in others no , for example i can get the properti "socialBuzzCompaignId" of model , but other propertie like "IEnumerable BuzzMessages" i can't get it , i dont now why !!
this is the content of my view
#model Maya.Web.Models.TimeLineModel
#{
ViewBag.Title = "confirmation";
}
#using (Html.BeginForm())
{
<h2>confirmation</h2>
<fieldset>
#foreach (var msg in Model.BuzzMessages)
{
<div class="editor-label">
#msg.LongMessage
</div>
<br />
}
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
You need to include BuzzMessages properties within a form element. Since it's not editable, you'd probably want to use hiddens. There are two ways to do this. Easiest is instead of doing a foreach loop, do a for loop and insert them by index.
#for (int i =0; i<Model.BuzzMessages.Count(); i++v)
{
<div class="editor-label">
#Model.BuzzMessages[i].LongMessage
#Html.HiddenFor(m => m.BuzzMessages[i].LongMessage);
</div>
<br />
}
but to do this you'd need to use an IList instead of an IEnumerable in your view model to access by index.
Alternatively, you could create an Editor Template named after your BuzzMessages class (whatever its name is).
#model BuzzMessagesClass
#Html.HiddenFor(m => m.LongMessages)
<!-- Include other properties here if any -->
and then in your main page
#Html.EditorFor(m => m.BuzzMessages)
Check out http://coding-in.net/asp-net-mvc-3-how-to-use-editortemplates/ or search stack overflow if the details of editor templates confuse you.
Just like any HTML POST method, you have to get the data back to the Controller somehow. Just simply "showing" the data on the page doesn't rebind it.
You have to put the data in an input (or a control that will post back) to the appropriate model property name.
So, if you have a model property with name FirstName and you want this data to be rebound to the model on POST, you have to supply it back to the model by placing an "input hidden" (or similar control that postbacks) with the ID of FirstName will rebind that property to the model on POST.
Hope that explains it.
#foreach (var msg in Model.BuzzMessages)
{
<div class="editor-label">
#msg.LongMessage
<input type="hidden" name="BuzzMessages.LongMessage" value="#msg.LongMessage" />
</div>
}
It will post array of LongMessages. Get values like this:
[HttpPost]
public ActionResult confirmation(TimeLineModel model, FormCollection collection)
{
var longMessages = collection["BuzzMessages.LongMessage"];
}

MVC3 Drop Down or ListBox with dynamic check boxes

I have an MVC3 C#.Net web app. I have a requirement to display a list of check boxes (either in a drop down or a List Box) dynamically based on a table in our db. The table can contain 1:500 entries. I then need to pass the selected check boxes to the Controller in order to perform an action on each selection. Any ideas on an implementation?
There are many ways to go about this but here is a general demo.
You can pass a list of the checkbox values and descriptions either on the Model (as this example does), ViewData[""] dictionary or ViewBag (MVC3+).
Then in your view loop through them and add them to your form using the name="chxBxGroupName" to group them.
Now create a controller action to post to that takes a List of the value type (in this example int) with the parameter naming matching the name="chxBxGroupName".
It will post a list of checked values.
The post page will just print out:
123
456
// This is your landing page. It gathers the data to display to the user as checkboxes.
public ViewResult MyPageWithTheCheckboxes()
{
// For example: Assume a Dictionary with the checkbox value and description
// Replace with DB call, etc.
return View(new Dictionary<int, string> { { 123, "Foo" }, { 456, "Bar" } });
}
<%# Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage<Dictionary<int,string>>" %>
<!-- Rest of HTML page... -->
<form id="frm1" action="<%=Url.Action("MyPost")%>" method="post">
<% foreach (var item in Model) { %>
<input type="checkbox" id="chxBx<%=item.Key%>" name="chxBxGroupName" value="<%=item.Key%>"/>
<label for="chxBx<%=item.Key%>"><%=item.Value%></label>
<br/><br/>
<% } %>
<input type="submit" value="Go!"/>
</form>
<!-- Rest of HTML page... -->
public ContentResult MyPost(List<int> chxBxGroupName)
{
return Content(string.Join(Environment.NewLine, chxBxGroupName ?? new List<int>()), "text/plain");
}
the answer provided by Jay accomplishes exactly what you need. If you want to put the items in a list you can do it by surrounding the markup with a div control lie below
<div style="height:40px;overflow:auto;">
<% foreach (var item in Model) { %>
<input type="checkbox" id="chxBx<%=item.Key%>" name="chxBxGroupName" value="<%=item.Key% >"/>
<label for="chxBx<%=item.Key%>"><%=item.Value%></label>
<br/><br/>
<% } %>
</div>
unfortunately you cant have checkboxes in a <select />, but if you really wanted it to look like a select list you could add some JQuery that processes onclick of a textbox and shows the div. This obviously would require some jQuery and might not be worth it

Partial View - >> How to REFRESH the HTML content without having to redirect to the view

My site has a concept like Skype that allow users to go "Online" and "Offline". I created a partial view that allows the user to switch mode:
#if (Convert.ToBoolean(ViewData["IsLogged"].ToString()))
{
<div id="onlineStatus">
You are currently <strong>ONLINE</strong> >>
#Html.ActionLink("Go OFFLINE", "GoOffline", "Account")
</div>
}
else
{
<div id="offlineStatus">
Ready for business >>
#Html.ActionLink("Go ONLINE", "GoOnline", "Account")
</div>
}
This is how we load the Partial View:
public ActionResult OnlineStatusCtrl()
{
if (SiteUser.IsAuthenticated)
ViewData["IsLogged"] = SiteUser.IsOnline.ToString();
return PartialView("OnlineStatusCtrl");
}
When a user clicks on the link "Go ONLINE" or "Go OFFLINE", the Controller respond as:
public ActionResult GoOnline()
{
if (SiteUser.IsAuthenticated)
SiteUser.GoOnline();
ViewData["IsLogged"] = "True";
return RedirectToAction("Index", "Home");
//return PartialView("OnlineStatusCtrl");
//return EmptyResult();
}
public ActionResult GoOffline()
{
if (SiteUser.IsAuthenticated)
SiteUser.GoOffline(true);
ViewData["IsLogged"] = "False";
return RedirectToAction("Index", "Home");
}
This works well ...but the ONLY problem is that if I am on View XXXX, and I click on "Go Online", the controller redirects me to the Index View.
I tried "return EmptyResult()" or "return PartialView("OnlineStatusCtrl") but it does just not work.
From the code, you can see that the only thing the PartialView cares about is the "ViewData['IsLogged'] value"
QUESTION:
What is the way to REFRESH a partial view without having to refresh the entire page or redirect to the main page?
Is it maybe a matter of putting an Html.Beginform() ?
Is it maybe a matter of the Controller returning something that just refresh the content of the PartialView independently from what view is holding the PV itself?
Aiaiaiaia
I still can't figure out how MVC works with PartialViews/
UPDATE
I have updated the code as x suggested and the HTML output is as follow:
<div id="divStatus">
<form action="/" data-ajax="true" data-ajax-mode="replace" data-ajax-update="#divStatus" id="form0" method="post">
<div id="offlineStatus">
Ready for business >>
Go Online
</div>
</form>
</div>
When I click on the LINK, the Controller return PartialView("_OnlineStatusCtrl"); which is hte name of the calling PV ...and the ENTIRE PAGE gets replaced.
You're going to have to use an ajax call of some sort (Microsoft ajax helpers built into MVC, or jquery/javascript ajax call.
To use Microsoft's Ajax, you can use Ajax.BeginForm or Ajax.ActionLink. Both take an AjaxOptions parameter that will allow you to set javascript functions for OnSuccess, and an UpdateTargetId to display the returned data (usually a partial view). Using this will call your action which should return a partial view. Your partial view then replaces the html element (usually a div) identified by the UpdateTargetId parameter. If you decide to go this route, make sure you reference all the proper Microsoft ajax/mvc scripts. You'll pretty much need each script with any combinations of Microsoft, Ajax, Mvc, and even unobtrusive in the name.
Here's an example of one of my ajax forms (modified slightly for simplicity)
<% using(Ajax.BeginForm("addAttribute", new { id = Model.PersonId, attributeId = item.AttributeId }, new AjaxOptions { UpdateTargetId = "myTargetId", OnSuccess = "initForm" })) { %>
<input type="submit" value="Ok" class="editMode okButton" disabled="disabled" />
<input type="button" class="editMode cancelButton" value="Cancel" />
<br />
<input type="button" value="Add" class="addButton" />
<% } %>
I have a div with an id of "myTargetId" (for this example) that will be updated with the returned partial view.

Resources