This question already has answers here:
Disable browser cache for entire ASP.NET website
(8 answers)
Closed 2 years ago.
I am facing an issue while showing the partial view in div with updatetargetid property of Ajax.ActionLink.
This is my controller-
[HandleError]
public class HomeController : Controller
{
static NumberViewModel model = new NumberViewModel();
public ActionResult Index()
{
model.IsDivisibleBy3 = (model.CurrentNumber % 3 == 0);
if (Request.IsAjaxRequest())
{
return PartialView("ViewUserControl1", model);
}
return View();
}
[ActionName("Increment")]
public ActionResult Increment()
{
model.CurrentNumber++;
return RedirectToAction("Index");
}
}
My Index view -
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Home Page
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<script type="text/javascript">
function ShowResult() {
var windowWidth = document.documentElement.clientWidth;
var windowHeight = document.documentElement.clientHeight;
leftVal = (windowWidth - 655) / 2;
topVal = (windowHeight - 200) / 2;
$('#result').css({
"left": leftVal,
"top": topVal
});
$('#background').fadeIn("slow");
}
</script>
<div id="background" class="hiddenDiv">
<div id="result" class="popupBox">
</div>
</div>
<%= Ajax.ActionLink("Show", "Index", new AjaxOptions() { UpdateTargetId="result", OnComplete="ShowResult", HttpMethod="Get" })%>
<%= Html.ActionLink("Increment","Increment") %>
</asp:Content>
This works in FF but not in IE6-IE8.
IE Scenario-
So when I Click on 'show', first time it shows '0 is divisible by 3'.
if click 'Increment', the number is now 1 and is not divisible by 3.
Now if I click on 'show' it shows '0 is divisible by 3'.
After keeping debug points in VS, I found- second time the request does not go to the server at all. Resulting in not updating the updatetargetid div.
Does anybody face this issue before?
ie is caching dubplicate request just add this to your action method:
Response.CacheControl = "no-cache";
Response.Cache.SetETag((Guid.NewGuid()).ToString());
so you will have:
[ActionName("Increment")]
public ActionResult Increment()
{
Response.CacheControl = "no-cache";
Response.Cache.SetETag((Guid.NewGuid()).ToString());
model.CurrentNumber++;
return RedirectToAction("Index");
}
Related
Please see Darin's solution here .. Converting HTML.EditorFor into a drop down (html.dropdownfor?)
I am not able to make the drop down list work. Can any help with this please. Thank you.
I am getting BC30203 error in my ascx page.
BC30203: Identifier expected. (Line 4 - new[] ).. What do I put in place of model. I tried putting the actual model name and may be I am getting the syntax wrong.. this code goes in the editor template according to the posted solution link above...
Code:
<%= Html.DropDownList(
"",
new SelectList(
new[]
{
new { Value = "true", Text = "Yes" },
new { Value = "false", Text = "No" },
},
"Value",
"Text",
Model
)
) %>
No idea why you are getting such error, the code should work. The following editor template works perfectly fine for me, I have just tested it:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%= Html.DropDownList(
"",
new SelectList(
new SelectListItem[]
{
new SelectListItem { Value = "true", Text = "Yes" },
new SelectListItem { Value = "false", Text = "No" }
},
"Value",
"Text",
Model
)
) %>
with the following model:
public class MyViewModel
{
[UIHint("YesNoDropDown")]
public bool IsActive { get; set; }
}
controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new MyViewModel());
}
}
and view:
<%# Page
Language="C#"
MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<AppName.Models.MyViewModel>"
%>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Home Page
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<%= Html.EditorFor(model => model.IsActive) %>
</asp:Content>
I want to display all the images in my image's folder.
This is my code :
<%
string dir = Server.MapPath("Content/slideshow/images");
string[] files;
int numFiles;
files = System.IO.Directory.GetFiles(dir);
numFiles = files.Length;
for (int i = 1; i < numFiles; i++)
{
%>
<i><a href="#">
<img src="/Content/slideshow/images/image<%= i %>.jpg" alt="" height="239px" width="930px" />
</a></i>
<% }%>
When I code like this, it display only the images that have the name "image"+blah blah blah . But I want to render all images in different name in a folder.
Can anyone solve this?
I would suggest you using view models to achieve this. So let's start by defining such:
public class ImageViewModel
{
public string Url { get; set; }
}
then we could have a controller action which will populate this view model (or precisely a collection of it):
public class ImagesController: Controller
{
[ChildActionOnly]
public ActionResult Images()
{
var appData = Server.MapPath("~/Content/slideshow/images");
var images = Directory.GetFiles(appData).Select(x => new ImageViewModel
{
Url = Url.Content("~/Content/slideshow/images/" + Path.GetFileName(x))
});
return PartialView(images);
}
}
then we could define a corresponding partial view (~/Views/Shared/Images.ascx):
<%# Control
Language="C#"
Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<ImageViewModel>>"
%>
<%= Html.DisplayForModel() %>
next a corresponding display template which will be rendered for each image (~/Views/Shared/DisplayTemplates/ImageViewModel.ascx):
<%# Control
Language="C#"
Inherits="System.Web.Mvc.ViewUserControl<ImageViewModel>"
%>
<img src="<%= Model.Url %>" alt="" height="239px" width="930px" />
and the final part that's left is to include this child action somewhere in a view or a master page:
<%= Html.Action("Images", "Images") %>
public DisplayImages()
{
System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(Location);
foreach (System.IO.FileInfo f in dir.GetFiles("*.*"))
{
//Do Something
}
}
I am fairly new to MVC and just trying to achieve something which I think shouldn't be too complicated to achieve. Just want to know what the best approach for that is. I have an Event-RSVP application (NerdDinner kind) where you go to view details of the event and then click on an AJAX link that will RSVP you for the event.
<%
if (Model.HasRSVP(Context.User.Identity.Name))
{
%>
<p>
You are registered for this event!
<%:
Ajax.ActionLink("Click here if you can't make it!", "CancelRegistration", "RSVP", new { id = Model.RSVPs.FirstOrDefault(r => r.AttendeeName.ToLower() == User.Identity.Name.ToLower()).RSVPID }, new AjaxOptions { UpdateTargetId = "QuickRegister"})
%>
</p>
<%
}
else
{
%>
<p>
<%:
Ajax.ActionLink("RSVP for this event", "Register", "RSVP", new { id=Model.EventID }, new AjaxOptions { UpdateTargetId="QuickRegister" }) %>
</p>
<%
}
%>
Now corresponding to these two links, my functions in RSVP Controller look like these.
[Authorize, HttpPost]
public ActionResult Register(int id)
{
Event event = eventRepository.GetEvent(id);
if (event == null)
return Content("Event not found");
if (!event.IsUserRegistered(User.Identity.Name))
{
RSVP rsvp = new RSVP();
rsvp.AttendeeName = User.Identity.Name;
event.RSVPs.Add(rsvp);
eventRepository.Save();
}
return Content("Thanks, you are registered.");
}
[Authorize, HttpPost]
public ActionResult CancelRegistration(int id)
{
RSVP rsvp = eventRepository.GetRSVP(id);
if (rsvp == null)
return Content("RSVP not found");
if (rsvp.Event.IsUserRegistered(User.Identity.Name))
{
eventRepository.DeleteRSVP(rsvp);
eventRepository.Save();
}
return Content("Sorry, we won't be seeing you there!");
}
Both of these seem to work without any issues. Now I want to make it a little fancier by doing either of these two:
1) Return an AJAX link from controller so that when you register, you get cancel registration link shown to you without page refresh.
2) Somehow make the view rendering refreshed when the controller method has finished executing so the first code block in my question gets executed after the click of any of the AJAX links. So clicking on register will register you and show you cancel link and clicking on cancel will cancel your registration and show you register link.
Any help would be greatly appreciated.
Thanks.
You could by using jQuery show and hide these links.
I never use the Ajax.ActionLink, I do my AJAX without the helper but I think it should look loke this :
Ajax.ActionLink("Click here if you can't make it!", "CancelRegistration", "RSVP", new { id = Model.RSVPs.FirstOrDefault(r => r.AttendeeName.ToLower() == User.Identity.Name.ToLower()).RSVPID }, new AjaxOptions { UpdateTargetId = "QuickRegister", OnSuccess = "ShowHideLinks" }, new { id = "cancel-link", #style = "display:none"})
Ajax.ActionLink("RSVP for this event", "Register", "RSVP", new { id=Model.EventID }, new AjaxOptions { UpdateTargetId="QuickRegister", OnSuccess = "ShowHideLinks" }, new { id = "register-link"})
And some javascript/jQuery to initialize the current display link :
function ShowHideLinks() {
$('#register-link').toggle();
$('#cancel-link').toggle();
}
<%: if(Model.HasRSVP(Context.User.Identity.Name)) { %>
ShowHideLinks();
<%: } %>
Hope this help!
You can set the links using jQuery. I see you are passing Content from both the action methods... You can use $.post() in jQuery to execute these action and in the success eventhandler compare the returned content (you would need to send something which is more easy to compare than the current strings) and set the links appropriately.
I have a timesheet application that has a View where the user can select customers and tasks and add them to a dynamic table. This table is filled with the tasks and input fields for filling in hours worked.
For adding the new tasks in the dynamic table I use jQuery, so the savenewtask button is not a submit button. Instead I have a proper submit button for saving the hours when filled in.
The View is strongly typed to a model called TimesheetViewModel (see below). The controller passes the model to the View, and then the input fields are bound to properties in the model.
However, when I submit with the submit button and try to update the model in the Controller it doesn't update. It seemed from the Nerddinner tutorial (which I am using to learn MVC) that the model should automatically be updated using the values from the forms fields it had been bound to when you use UpdateModel(). But it doesn't. What am I doing wrong?
Here is all the relevant code:
View:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<script src="../../Scripts/jquery-1.4.1.js" type="text/javascript"></script>
<script src="../../Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
//Hook onto the MakeID list's onchange event
$("#CustomerId").change(function () {
//build the request url
var url = "Timesheet/CustomerTasks";
//fire off the request, passing it the id which is the MakeID's selected item value
$.getJSON(url, { id: $("#CustomerId").val() }, function (data) {
//Clear the Model list
$("#TaskId").empty();
//Foreach Model in the list, add a model option from the data returned
$.each(data, function (index, optionData) {
$("#TaskId").append("<option value='" + optionData.Id + "'>" + optionData.Name + "</option>");
});
});
}).change();
});
</script>
<h2>Index</h2>
<% using (Html.BeginForm())
{%>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Fields</legend>
<div>
<label for="Customers">
Kund:</label>
<%:Html.DropDownListFor(m => m.Customers, new SelectList(Model.Customers, "Id", "Name"), "Välj kund...", new { #id = "CustomerId" })%>
<label for="Tasks">
Aktiviteter:</label>
<select id="TaskId">
</select>
</div>
<p>
<input type="button" value="Save new task" id="savenewtask" />
</p>
<table width="100%">
<%--<% foreach (var task in Model.Tasks)--%>
<% foreach (var task in Model.WeekTasks)
{ %>
<tr>
<td>
<%: task.Customer.Name %>
</td>
<td>
<%: task.Name %>
</td>
<td>
<% foreach (var ts in task.TimeSegments)
{ %>
<input class="hourInput" type="text" size="2" id="<%: ts.Task.CustomerId + '_' + ts.TaskId + '_' + ts.Date %>"
value="<%: ts.Hours %>" />
<% } %>
</td>
</tr>
<% } %>
</table>
<input type="submit" value="Save hours" id="savehours" />
</fieldset>
<% } %>
</asp:Content>
From the Controller:
private TimesheetViewModel _model;
public TimesheetController()
{
_model = new TimesheetViewModel();
}
public ActionResult Index()
{
return View(_model);
}
[HttpPost]
public ActionResult Index(FormCollection collection)
{
try
{
UpdateModel(_model);
_model.Save();
return View(_model);
//return RedirectToAction("Index");
}
catch
{
return View();
}
}
The ViewModel:
public class TimesheetViewModel
{
private TimesheetContainer _model; //TimesheeContainer is an Entity Framework model
public TimesheetViewModel()
{
_model = new TimesheetContainer();
}
public IList<Customer> Customers
{ get { return _model.Customers.ToList(); } }
public IList<Task> Tasks
{ get { return _model.Tasks.ToList(); } }
public IList<Task> WeekTasks
{
get
{
//Get the time segments for the current week
DateTime firstDayOfWeek = DateTime.Parse("2010-12-05");
DateTime lastDayOfWeek = DateTime.Parse("2010-12-13");
List<TimeSegment> timeSegments = new List<TimeSegment>();
foreach (var timeSegment in _model.TimeSegments)
{
if(timeSegment.DateTimeDate > firstDayOfWeek && timeSegment.DateTimeDate < lastDayOfWeek)
timeSegments.Add(timeSegment);
}
//Group into tasks
var tasks = from timeSegment in timeSegments
group timeSegment by timeSegment.Task
into t
select new { Task = t.Key };
return tasks.Select(t => t.Task).ToList();
}
}
public IList<TimeSegment> TimeSegments
{ get { return _model.TimeSegments.ToList(); } }
public void Save()
{
_model.SaveChanges();
}
public void AddTimeSegments(Task task)
{
_model.AddToTasks(task);
_model.SaveChanges();
}
}
Partial class to get tasks for a specific week (only dummy week at this time for testing):
public partial class TimeSegment
{
public DateTime DateTimeDate
{ get { return DateTime.Parse(Date); } }
}
Why is the model not updating, and what can I change to make it work?
Put a breakpoint on your first ActionResult Index(), is that getting called when you do the submit? you may need [HttpGet] on it, otherwise I think it gets both.
I'm quite new to both ASP.Net and MVC.
I got the following code in my master page:
<div id="main-menu" class="menu">
<%
var items = (IList<CompanyName.Framework.Web.MenuItem>)ViewData["MainMenu"];
if (items.Count > 0)
{
%><ul><%
foreach (var item in items)
{
if (!string.IsNullOrEmpty(item.RequiredRole) && !System.Threading.Thread.CurrentPrincipal.IsInRole(item.RequiredRole))
continue;
%><li><%= item.Title %></li><%
}
%></ul><%
}
%>
</div>
Can I move the code to another file or refactor the code in any way?
edit:
My ApplicationController that all controllers derive:
public class ApplicationController : Controller
{
List<MenuItem> _mainMenu = new List<MenuItem>();
List<MenuItem> _contextMenu = new List<MenuItem>();
protected IList<MenuItem> MainMenu
{
get { return _mainMenu; }
}
protected IList<MenuItem> ContextMenu
{
get { return _contextMenu; }
}
protected string PageTitle { get; set; }
protected override void OnResultExecuting(ResultExecutingContext filterContext)
{
ViewData["PageTitle"] = PageTitle;
ViewData["MainMenu"] = MainMenu;
ViewData["ContextMenu"] = ContextMenu;
base.OnResultExecuting(filterContext);
}
}
Here are a couple of suggestions:
Improvement number 1: use view models and strongly typed views instead of ViewData
public ActionResult Index()
{
// TODO: Fetch this data from a repository
var menus = new[] {
new MenuItem(), new MenuItem()
}.ToList();
return View(menus);
}
and then in your view:
<div id="main-menu" class="menu">
<%
if (Model.Count > 0)
{
%><ul><%
foreach (var item in Model)
{
if (!string.IsNullOrEmpty(item.RequiredRole) && !System.Threading.Thread.CurrentPrincipal.IsInRole(item.RequiredRole))
continue;
%><li><%= item.Title %></li><%
}
%></ul><%
}
%>
</div>
Still horrible and completely unreadable tag soup.
Improvement number 2: use editor/display templates:
In ~/Views/Home/DisplayTemplates/MenuItem.ascx:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<CompanyName.Framework.Web.MenuItem>" %>
<% if (!string.IsNullOrEmpty(Model.RequiredRole) &&
System.Threading.Thread.CurrentPrincipal.IsInRole(Model.RequiredRole)) { %>
<li>
<%= Model.Title %>
</li>
<% } %>
And then in your main view:
<div id="main-menu" class="menu">
<ul>
<%= Html.DisplayForModel() %>
</ul>
</div>
Improvement number 3: Avoid coding business rules in a view. So in your view model add a property:
public bool IsLinkVisible
{
get
{
return !string.IsNullOrEmpty(RequiredRole) &&
Thread.CurrentPrincipal.IsInRole(RequiredRole);
}
}
so that your display template now looks like this:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<CompanyName.Framework.Web.MenuItem>" %>
<% if (Model.IsLinkVisible) { %>
<li>
<%= Model.Title %>
</li>
<% } %>
Improvement number 4: Write a custom HTML helper to render this anchor because writing C# in a view is still ugly and untestable:
public static class HtmlExtensions
{
public static MvcHtmlString MenuItem(this HtmlHelper<MenuItem> htmlHelper)
{
var menuItem = htmlHelper.ViewData.Model;
if (!menuItem.IsLinkVisible)
{
return MvcHtmlString.Empty;
}
var li = new TagBuilder("li");
var a = new TagBuilder("a");
a.MergeAttribute("href", menuItem.Uri);
a.SetInnerText(menuItem.Title);
li.InnerHtml = a.ToString();
return MvcHtmlString.Create(li.ToString());
}
}
and finally your display template:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<CompanyName.Framework.Web.MenuItem>" %>
<%= Html.MenuItem() %>
Yes, you can just put that block into an .ascx file and use:
<% html.RenderPartial("myPartialFile.asx"); %>
The above assumes that myPartialFile.ascx is located in the same folder as your master page, usually, the Views/Shared folder.