I have a small app set up using Sring MVC and Sitemesh. When i click a link, a form, etc., i want it to open the new page without reloading the whole decorator page, just the decorator:body part. Is there any simple way of doing that?
The only way is to use AJAX for fetching the page part without full page reloading
UPDATED (04/05/2011):
using JQuery for AJAX.
Controller:
#RequestMapping(value = "/myapp/getpart", method = RequestMethod.GET)
public String getPart(Model model) {
//...do something
model.addAttribute("myObject", myObject);
return "getPart";
}
View:
<div id="container">
</div>
<a id="myAnchor">get page part</a>
<script>
$(document).ready(function(){
$('#myAnchor').click(function(e){
e.preventDefault();
$.get('/myapp/getpart', function(data) {
$('#container').html(data);
alert('Data was fetched.');
});
});
});
</script>
Related
I'm trying to determine the correct approach to populating multiple dropdown lists on a view page of an .net MVC application, which is using angularJS.
In my app, designed as a silo-SLA app. I'm using the angular ngRoute module, and the $routeProvider to describe the multiple HTML pages for a single CSHTML page.
.config(function ($routeProvider, $locationProvider) {
$routeProvider.when('/club', { templateUrl: '/App/Club/Views/MCLView.html', controller: 'mclViewModel' });
$routeProvider.when('/club/list', { templateUrl: '/App/Club/Views/MCLView.html', controller: 'mclViewModel' });
$routeProvider.when('/club/show/:clubId', { templateUrl: '/App/Club/Views/ClubView.html', controller: 'clubViewModel' });
$routeProvider.otherwise({ redirectTo: '/club' });
$locationProvider.html5Mode(true);
});
My CSHTML page is basically empty except for the <div ng-view></div> tag. The routed HTML pages get loaded into the ng-view div.
<div data-ng-app="club" id="club" data-ng-controller="rootViewModel">
<h2>{{ pageHeading }}</h2>
<div ng-view></div>
</div
Each html view page loaded into the ng-view has an associated viewmodel javascript controller.
I started out populating the first dropdown on the html page by using $http.get in the angular controller to get the list data (json) from a server call. Then do a JSON.parse on the result.data and populate the select list control that is defined in the html page.
$scope.refreshColorsDropdown = function () {
var sel = document.getElementById('colorDropdown');
var colors = JSON.parse($scope.mycolors);
angular.forEach(colors, function(color) {
var opt = document.createElement('option');
opt.innerHTML = color.name;
opt.value = color.hex;
sel.appendChild(opt);
});
}
I could continue this approach for each dropdown on my page, creating several server calls to populate all my dropdowns ... but this seems tedious and code heavy.
Would a reasonable approach be to consider building one server calls that returns multiple collections, one for each dropdown, and then I'd parse those to populate all the dropdowns?
I'd like to pre-populate the lists on the server side C# code, however my cshtml files are empty except for the ng-view div, so there's no coding going on there.
So to my question ... if my HTML views contain all the html content, and the cshtml are empty ... what strategy should I be using to populate multiple html list controls from the server side?
Using MVC, you can make a ViewModel that contains all collections needed and return this collection to your Angular Controller.
Your View Model would be something like:
public class MyViewModel
{
public List<ColorModel> Colors{get;set;}
public List<FabircModel> Fabrics {get;set;}
}
In your MVC Controller:
MyViewModel mvm = new MyViewModel();
mvm.Colors = get colors here;
mvm.Fabrics = get fabrics here;
return Json(mvm, JsonRequestBehavior.AllowGet);
In your success object in Angular:
myservice.getData()
.success(function(data){
$scope.colors = data.Colors;
$scope.fabrics = data.Fabrics;
})
Hopefully, that helps or at least gets you started.
If you ignore the fact you are using angular the answer would be to populate a view model with what you need and razor the cshtml, because you are using angular...nothing changes....because you said SERVER-SIDE that is still the answer.
If you move this to the client an angular service that can cache the data is probably the most direct way.
Hi can someone please tell me how I can load a PartialView into a div container I have prepared located in _Layout.cshtml (that is completely separate from the link itself). I want it loaded into the container on the click of the following action link:
<span>ContactUs</span>
I would like to do this without javascript because I need to create a model in my controller and pass it to the PartialView and I dont think its possible to pass a strongly typed model to a view using javascript.
If I wanted to I could use:
$('.colorboxLink').click(function () {
$('.colorbox_container').load(this.href);
});
but as I mentioned this does not give me the chance to create and pass a strongly typed model to the partial view...its important that I can create and pass a model to the view because Im getting a null reference exception when I try something like foreach(var item in Model.ItemList) in the partial view.
Heres what my controller looks like:
public virtual ActionResult RenderColorbox(string path)
{
return PartialView(path, null);
}
However, currently, clicking the action link simply renders the PartialView in a new blank page rather than inside the container I have set up.
Thank you all for your help.
EDIT: To load the colorbox I used the following as suggest:
$('.colorboxLink').click(function () {
$('.colorbox_container').load(this.href, function () {
var colorboxOptions = {
inline: true,
scrolling: false,
opacity: ".9",
fixed: true,
onLoad: function () {
$('#cboxContent').css({
"background": "white"
});
$('#cboxLoadedContent').css({
"margin-bottom": "28px",
"height": "558px"
});
}
}
$('#contactColorbox').colorbox(colorboxOptions);
});
But still loads without colorbox, but rather as a pop up modal.
but as I mentioned this does not give me the chance to create and pass
a strongly typed model to the partial view.
It gives you such chance. You are sending an AJAX request to the RenderColorbox action on the ContactPartial controller. Inside this action you can prepare and send whatever complex view model you want to the partial:
public ActionResult RenderColorbox(string path)
{
SomeComplexModel model = ...
return PartialView(path, model);
}
Also make sure that you cancel the default action of the link by returning false from the click handler:
$(function() {
$('.colorboxLink').click(function () {
$('.colorbox_container').load(this.href);
return false;
});
});
If you don't do this, when you click on the link, your AJAX call has barely any chance to execute before the browser redirects away to the target page.
I am new to MVC3 and Razor.
I have an "attention banner" on the master page as a Partial View that I want to "acknowledge" with a click on a link to close the banner (without reloading the page). I believe I need to use jQuery and an Ajax call, but I just can't seem to find the right combination.
Here is part of my _Layout.cshtml:
<section id="main">
<span id="attentionBar">#{ Html.RenderPartial("_AttentionBarPartial"); }</span>
#RenderBody()
</section>
This is my Partial View (just using Session as a shortcut for now to get it to work). I'm not sure what to use as the "link" to reload the view:
#{ this.Layout = null;}
#if(! String.IsNullOrWhiteSpace(#Session["Attention"].ToString()))
{
<div class="attentionPanel">
<span class="attentionLabel">Attention</span>
#Session["Attention"].ToString()
<span class="attentionLabel">
#* WHAT DO I PUT HERE *#
#Ajax.ActionLink("X", "AcknowledgeAttentionBar", "Home", new AjaxOptions{ UpdateTargetId="attentionPanel", InsertionMode=InsertionMode.Replace })
</span>
</div>
}
Here is my Home controller. Again, I am not sure that the code is quite correct, but essentially I will clear out the condition that shows the attention banner.
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Home Controller Updated At " + DateTime.Now.ToLongDateString()
+ " " + DateTime.Now.ToLongTimeString();
return View();
}
public PartialViewResult AcknowledgeAttentionBar()
{
Session["Attention"] = String.Empty;
return PartialView("_AttentionBarPartial");
}
}
2 things:
Make sure you have included the jquery.unobtrusive-ajax.js script to your page in order for Ajax.ActionLink helper to work and send an AJAX request when the link is clicked instead of a normal redirect:
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
In your AjaxOptions you have specified UpdateTargetId="attentionPanel" but there's no element in your markup with id="attentionPanel". You have a div with class="attentionPanel" but that's not the same thing. On the other hand you have wrapped your banner in a <span id="attentionBar">, so you probably meant UpdateTargetId="attentionBar".
I'm trying to use jQuery to load a PartialView. It does this fine at the first loading of the page. But then I need to be able to reload the PartialView when a save button is pressed. I get a reload, but this time the PartialView is all I get back. I.e. I don't get the PartialView loaded as a part of the main page, but rather as a page of its own. What am I doing wrong?
Here are the relevant parts of the jQuery in the View:
$.get('<%=Url.Action("GetTasks", "Timesheet", new {id = DateTime.Today.ToShortDateString() }) %>', function (data) {
$('#tasksDiv').html(data);
}); //This part works fine on first load of the page
$('#savenewtask').click(function (event) {
event.preventDefault();
$.get('<%=Url.Action("GetTasks", "Timesheet", new {id = DateTime.Today.ToShortDateString() }) %>', function (data) {
$('#tasksDiv').html(data);
});
}); //This only loads the PartialView, but not as part of the main page...
The button and the div to load in:
<p>
<input type="button" value="Spara" id="savenewtask" />
</p>
<div id="tasksDiv">
</div>
UPDATE:
It actually worked, I had just confused the two input fields I have on the page. But I'll rephrase the question to a simple one: Is this the best way to do this sort of thing with PartialViews, or should I go about it another way? (I.e. I was just trying to figure out a way to achieve what I wanted without knowing if it is the "best practice" way of doing it).
I have typically used the load method, which sets the innerHtml.
var url = '<%=Url.Action("GetTasks", "Timesheet", new {id = DateTime.Today.ToShortDateString() }) %>'
$("#tasksDiv").load(url);
I am in the process of putting a new site together which will make use of AJAX to pull through page content should the user have javascript enabled.
So, I am in the situation whereby every Action Method requires a check to see if the request was through AJAX or not, which is straightforward. If the request was through AJAX then I can return a partialview, if not then a full view can be returned.
With this pattern though, I'll need to create a View and a PartialView for every page on the site. The only real difference between them is going to the inclusion of the masterpage.
Am I missing a trick here is is this doubling up of views the only way to go?
Thanks
EDIT - a bit more info
Lets say I had a page that could get accessed through /site/test. Somewhere in my JS I would add a hash to the url like so #/site/test. JS would then watch for any hash changes and load the partial views as needed. If JS was not available though, an entire view would need to be returned.
So for each page I would need the view, which would then include a call to RenderPartial which would load up the partial view which would actually contain the page content. So, for every page there are two files. It just seems there should be a cleaner way of doing this.
Sergio, yes you are missing a trick!!
You should organise your page so that the static content in it is just that - static. This static page then calls the partial(s) that give the dynamic content. this would typically be used in the main page as such (i'm using jquery as per microsofts adopted stance on ajax now):
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>My Header</h2>
<%--lots of stuff omitted--%>
<div id="dynamicList"><%Html.RenderPartial("List"); %></div>
<%--also lots missed out here--%>
<input type="button" id="btnRefresh" value="refresh" />
</asp:Content>
this means that the partial would always be rendered in the initial request. subsequent refreshes would call the partial method in the controller and repopulate the 'dynmaicList' div along the lines of:
<script type="text/javascript">
// you might have a click or similar here to invoke the partial refresh
$(function() {
//click event (or some other 'change' event)
$('#btnRefresh').click(function() {
dynamicList();
});
});
function dynamicList() {
// where action/controller retruns a partialview result
var url = '<%= Url.Action("List", "MyController") %>';
// this is merely a wrapper method around jquery $ajax
SendAjax(url, formParams(), beforedynamicListQuery, dynamicListResponse);
}
function beforedynamicListQuery() {
$("#dynamicList").fadeTo('slow', 0.5);
}
function dynamicListResponse(data) {
if (data.length != 0) {
if (data.indexOf("ERROR:") >= 0) {
$("#dynamicList_errmsg").html(data);
}
else {
var selector = "#dynamicList";
$(selector).fadeTo('slow', 1, function() {
$(this).html(data);
});
}
}
}
</script>
anyway, that's my take on it!! ;)