With an MVC project containing _layout.cshtml with bundles loaded, clicking around loads the Layout and bundles every time a view is loaded. Is there any build-in mechanism that I can use to load that stuff only initially, so that RenderBody() only loads the content I don't have yet (not reloading Layout)? Is this where partials come in?
If partials are the right way to handle it, does this mean I need to have two versions of each controller method (One with Layout, one without)? Any tips here would be great.
As far as I know there's no built-in mechanism to load the layout page only at once. You can do it using client-side approach if you want that layout will be loaded only at once so that it would be lighter for the server. Here's the step. Create MVC 4 application.
In your _Layout.cshtml add a div that will hold the html page you want to load. In my case "pageholder"
<div id="body">
<div id="pageholder">
#RenderSection("featured", required: false)
<section class="content-wrapper main-content clear-fix">
#RenderBody()
</section>
</div>
</div>
Add this script in your _Layout.cshtml
#Scripts.Render("~/Scripts/common.js")
<script type="text/javascript">
$(document).ready(function() {
$('.pagelink').click(function() {
var settings = {
'url': $(this).attr('url'),
'type': 'GET',
'dataType':'html'
};
get_html(settings);
});
});
</script>
Modify your menu link
<nav>
<ul id="menu">
<li>#Html.ActionLink("Home", "Index", "Home")</li>
<li>About</li>
<li> Contact</li>
</ul>
</nav>
Add js file and name it common.js and put this content
function get_html(settings) {
settings.success = function(data) {
$('#pageholder').empty().html(data);
};
settings.error = function (xhr, ajaxOptions, thrownError) {
alert(xhr.statusText);
};
$.ajax(settings);
}
Set Layout = null; both About and Contact views
#{
ViewBag.Title = "About";
Layout = null;
}
Run the application and test the About and Contact pages
Related
I've created a new asp.net MVC app in VS.NET 2013. In _Layout.cshtml, I have a reference to the angularjs library (Google developer site). I also define a controller called "con1" and create a variable.
_Layout.cshtml:
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.4/angular.min.js"></script>
<script type="text/javascript">
function con1($scope) {
$scope.somestring = "some string";
}
</script>
Index.cshtml:
<div>
{{1+1}}
</div>
The above works fine and renders the result of "2".
When I change the div to the following and start trying to access the somestring variable in the controller, I get the actual AnguarJS code rather than the result.
<div ng-controller="con1">
{{1+1}}
</div>
Output: "{{1+1}}"
Any idea why adding the controller reference breaks it? This seems to be VS.NET specific. I have a jsfiddle here that works fine: http://jsfiddle.net/jpswdzxu/. That is basically the output from the VS.NET project.
You need to define the Angular Application, or it won't work:
<script type="text/javascript">
var myApp = angular.module('myApp',[])
.controller('myAppCtrl', function($scope) {
$scope.somestring = 'teststring';
});
</script>
Then, the HTML should be:
<body ng-app="myApp">
<div ng-controller="myAppCtrl">
{{somestring}}
</div>
</body>
Or, using your jsfiddle, it would be:
<div ng-app="myApp" ng-controller="myAppController">
{{1+1}}
<br>
{{somestring}}
</div>
and:
angular.module('myApp',[])
.controller('myAppController', function ($scope) {
$scope.somestring = "some string";
});
Good Luck!
This may be a little difficult to explain, but I'll try my best. I have a product page with two tabs, full description and video. These are done using jQuery UI Tabs.
Above this section of the page I have a product image with thumbnails...but I want one of the thumbnails to be a link to see the video (which of course is contained in the video tab).
If I load the page as site.com/product#video it does load up the correct tab...but when the tab is not active, and I use a link outside of the #tab div, (ex: Video), it doesn't do anything.
How can I get a link to open the tab if it's not contained in the #tab div?
CODE
This code is outside of the tabs, and needs to open the #video tab
Open Video Tab
Tabs Code
<div id="tabs" class="ui-tabs ui-widget ui-widget-content ui-corner-all">
<ul class="product-tabs ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all">
<li class="ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-state-hover">Full Description</li>
<li class="ui-state-default ui-corner-top">Video</li>
</ul>
<div class="product-collateral">
<div class="box-collateral box-description">
<div id="description" class="ui-tabs-panel ui-widget-content ui-corner-bottom">
Content
</div>
<div id="video" class="ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide">
<h2 class="video">Video Content</h2>
</div>
</div>
</div>
</div>
What worked for me was this:
Html
Open Description Tab
Open Video Tab
<div id="tabs">
<ul>
<li>
Full description
</li>
<li>
Video content
</li>
</ul>
<div class="product-collateral">
<div class="box-collateral box-description">
<div id="description">
Content
</div>
<div id="video">
<h2 class="video">Video Content</h2>
</div>
</div>
</div>
</div>
Javascript
$(document).ready(function () {
$('#tabs').tabs();
$('.open-tab').click(function (event) {
var tab = $(this).attr('href');
$('#tabs').tabs('select', tab);
});
});
So what this does is provide a link to both the description and video tabs, which are selected when the link is clicked.
From here we can see that when selecting a particular tab, we can use either a zero-based index or the href fragment which points to the tab we wish to display.
This is why the href attributes of the a elements match up with the Ids of the div elements - when one is clicked its href fragment is then used to set the selected tab.
Update for jQuery UI 1.11
As jQuery UI has evolved, so to has the API for setting the active tab. As of jQuery UI 1.11, the following code will select the active tab:
//Selects by the zero-based index
$('#tabs').tabs("option", "active", index);
Now because we now have to provide a zero-based index, the code I initially provided will no longer work.
What we need now is an index that can actually be used. One approach is:
$('.open-tab').click(function (event) {
var index = $("selector-of-clicked-tab").index();
$('#tabs').tabs("option", "active", index);
});
Another is to use HTML5 data- attributes:
Open Description Tab
Open Video Tab
So you can do this when handling the click of these links:
$('.open-tab').click(function (event) {
$('#tabs').tabs("option", "active", $(this).data("tab-index"));
});
use jQuery:
$( "#tabs" ).tabs({ active: tabNumber });
Remember, that the indexation starts from 0
Using jquery, bind a click event to your link that opens the tab you want.
$('#tabopenlink').click(function() {
$('#tabs').tabs({active: tabidx});
});
I use mini plug-in.
(function($) {
$.fn.tabremote = function(options) {
var settings = $.extend({
panel: "#tabs",
to: "data-to",
}, options );
$this=$(this);
$panel=$(settings.panel);
$this.click(function(){
if($(this).attr("href"))
{var tos=$(this).attr("href");}
else
{var tos=$(this).attr(settings.to);}
to=tos.match(/\d/g);
$panel.tabs({active: to-1});
return false;
});
return this;
}
})(jQuery);
Opens the tab using href or any element.
id panel must contain the number of the panel. Example (1-tabs, tabs-2, ...)
Plugin subtracts 1 and open the panel. Tabs (active, (number of id -1))
Use
$("button.href").tabremote({panel:"#tabs",to:"data-href"});
panel:"#tabs" // container panel
to:"data-href" // attribute name with value
function openTabByLink(link) {
$("#tabs").find("ul li[aria-controls='"+link+"'] a").trigger("click");
}
If you use twitter bootstrap instead of jquery ui, it will be very simple.
Just add data-toggle="tab" and put the link wherever you want in the page:
Open Video Tab
For jQuery UI 1.11
HTML:
<div id="tabs">...</div>
...
Open Video Tab
JS:
$('.open-tab').click(function () {
$("#tabs").tabs('option','active',$('#tabs a.ui-tabs-anchor[href="'+$(this).attr('href')+'"]').index('#tabs a.ui-tabs-anchor'));
});
I am working on asp.net MVC 3 application and I have a layout page with a section like this:
<div class="rt-block">
<div id="rt-mainbody">
#if (IsSectionDefined("BodyTitle"))
{
<div class="rt-headline">
<h1 class="rt-article-title">
#RenderSection("BodyTitle", false)
</h1>
</div>
}
<div class="clear">
</div>
<div>
#RenderBody()
</div>
</div>
</div>
In My View, I am defining the section like this:
#section BodyTitle {
<span>Verify</span> Your Identity
}
partail view here
This View loads one of two partial views depending on link click.
I want that when one partial view is loaded then section has different text where it should have different text when other partial view is loaded. How can I change section contents on change of partial view ?
I tried to move section to partial views but in that case it is not loaded at all. Can't we define section in partial view which is declared in layout view ?
Please suggest
You cannot define sections in partial views. They must be defined in the main view. So basically what you need is to update 2 different portions of your DOM when a link is clicked. One possible way to achieve this is to render the partial view to a string inside the controller action and then return a JSON result containing the 2 properties with the corresponding partial contents.
return Json(new
{
partialHtml = RenderPartialViewToString("_SomePartial"),
sectionHtml = RenderPartialViewToString("_SomeSection")
});
and then:
$.ajax({
url: '...',
type: 'POST',
success: function(result) {
// first update the partial
$('#partialContainerId').html(partialHtml);
// now update the section
$('.rt-article-title').html(sectionHtml);
}
});
You could externalize the contents of the section inside a partial.
I'm using backbone jquery mobile and coffee script to develop a simple twitter application. My problem is the jquery mobile styles are failing to render. My View is
class HomeView extends Backbone.View
constructor: ->
super
initialize: ->
#Twitter= new TwitterCollection
template: _.template($('#home').html())
render: ->
#loadResults()
loadResults: ->
#Twitter.fetch({
success: (data) =>
$(#.el).html(#template({data: data.models, _:_}))
error: ->
alert('Error!')
})
This works fine in terms of pulling information from Twitter, however when
$(#.el).html(#template({data: data.models, _:_}))
is within the fetch function, jquerys styles do not render. Can anyone show me how to refresh the styles? Help would be much appreciated!
For reference, the html template is:
<script type="text/template" id="home">
<div data-role="header" data-position="fixed">
<h1>TWITTER DATA</h1>
</div>
<div data-role="content">
<ul data-role="listview" data-inset="true">
<% _.each(data, function (row) { %>
<li><%= row.get('text') %></li>
<% }); %>
</ul>
</ul>
</div>
Ok, I fixed it by adding ".listview('refresh').trigger('create');" to the end of
$(#.el).html(#template({data: data.models, _:_}))
When the fix is applied afterwards (after the view page has been rendered and displayed by $.mobile.changePage()) the user gets an unpleasant side-effect: the view flickers due to the change of style applied by jquery mobile.
My solution to the problem was to trigger custom event from the view once the dynamic rendering is complete and bind the $.mobile.changePage() to that event. This causes the output to be "buffered" until complete and then styled altogether.
Here's an example:
In the initialize function of my view I have code waiting for an event to be fired by the model/collection when fetched and a function to render the dynamic part of the html:
window.MyView = Backbone.View.extend({
// some other code here
initialize: function() {
this.listenTo(this.collection, "fetchCompleted:CollectionName", this.renderRows);
},
renderRows: function (eventName) {
$(this.el).find('div[class="content-primary"]').html(this.template_ul({data: this.collection}));
this.trigger( 'view:ready' );
},
//...
... then in the router I have the following code for the changePage():
myViewObject.on( 'view:ready', function() {
$.mobile.changePage($(next.el), {changeHash:false, transition: transition});
});
I have a partial view in MVC that goes something like:
<div id="comments">
...
</div>
Inside that div there's a form that calls a controller using AJAX and gets back that same partial view. The problem is that the results of calling the view replaces the contents of the div, not the whole div, and I end up with:
<div id="comments">
<div id="comments">
...
</div>
</div>
The only solution I can think about with my week of experience in ASP.Net MVC and AJAX is to put the div outside the partial view and make the partial view only contain the inside part, but then the form would refer to an id outside the view where the form is located breaking the little encapsulation I have left there. Is there any better solution?
The unobtrusive Ajax library that ships with .NET MVC 3 uses callbacks that are based on the four callbacks from jQuery.ajax. However, the InsertionMode = InsertionMode.Replace from the Ajax.BeginForm method does not result in jQuery's replaceWith being called. Instead, .html(data) is used to replace the contents of the target element (and not the element itself).
I have described a solution to this problem on my blog:
http://buildingwebapps.blogspot.com/2011/11/jquerys-replacewith-and-using-it-to.html
Are you using an AjaxHelper.Form or jQuery. If you are using jQuery, have you tried using replaceWith()? Using AjaxHelper are you using AjaxOptions { InsertionMode = InsertionMode.Replace }? I would think that using either you would be able to replace the entire DIV with the results from the partial view.
Using
AjaxOptions { UpdateTargetId = "myDiv", InsertionMode = InsertionMode.Replace }
should replace the whole content of '#myDiv' element, as tvanfosson says. Your problem is where is '#myDiv' located. Here's an example:
<div id="myDiv">
<% Html.RenderPartial("MyPartialView"); %>
</div>
where MyPartialView is:
<div id="comments">
<% using (Ajax.BeginForm(new AjaxOptions() { UpdateTargetId = "myDiv", InsertionMode = InsertionMode.Replace } )) {%>
...
<input type="submit" value="Submit comment" />
<% } %>
</div>
If you include '#myDiv' div inside the partial view, it will be rendered right after receiving the response (together with its content), and then it's content will be replace with the response which is the same partial view (including its own '#myDiv' div), and that's why you always end up with 2 nested divs.
You should always use a container for your partial views and then set the UpdateTargetId to the container id.
Edit: I updated the code to represent the exact situation you describe in your question.
I had this same problem in Asp.Net MVC 5.
I did not want the PartialView to have some knowledge about what div it might be contained within, so I did not accept that work around.
Then, I noticed the other answers referring to ReplaceWith and found the simple solution:
InsertionMode = InsertionMode.ReplaceWith
Now, the mvc partial view can completely replace itself with the ajax helpers without having any dependencies on names outside itself.
Your should try with jQuery too (from my answer on MS MVC form AJAXifying techniques):
<script type="text/javascript">
$(document).ready(function() {
ajaxify($('div#comments'));
});
function ajaxify(divWithForm) {
var form = $('form', divWithForm);
$(':submit', form).click(function (event) {
event.preventDefault();
$.post(form.attr('action'), form.serialize(),
function(data, status) {
if(status == 'success') {
var newDivWithForm = $(data);
ajaxify(newDivWithForm);
divWithForm.after(newDivWithForm).remove();
}
}
);
});
}
</script>
Did you solved the problem? I had the same issue but I found this:
http://buildingwebapps.blogspot.ro/2011/11/jquerys-replacewith-and-using-it-to.html
I hope it helps you.