I'm attempting to render JavaScript from a Razor Partial Page into the bottom of a (layout) Page. In Including JavaScript at bottom of page, from Partial Views Becuzz specifies that using a #section {} might be helpful for this purpose, but such sections are not rendered from Partial Pages.
One could in theory circumvent the problem by rendering the section of JavaScript outside of the Partial Page, into the Page itself. However, this is not possible, given that I want to reference a html element inside the script, as follows:
#section ScriptTag
{
<script type="text/javascript">
var example = $('##Html.FieldIdFor(m => m.ExampleProperty)').val();
});
</script>
}
#Html.TextBoxFor(m => m.ExampleProperty)
How can I make this work?
You can only call RenderSection between two Views/Layouts that are directly related.
In this situation you would need to essentially redefine and render the section in your View in the middle.
See: http://blogs.msdn.com/b/marcinon/archive/2010/12/15/razor-nested-layouts-and-redefined-sections.aspx for a clearer explanation
Related
I've read through a few posts here regarding this topic, but none seem to answer which method is the best for allowing sub-pages access to the host page's <script> section.
I load home.php, which has a menu displayed in one of its two <div> sections. The HTML for this menu is on home.php itself. The user is able to interact with buttons and dropdowns in the menu portion of home.php through scripts on home.php, like:
$("#graphsButton").click(function() {
if($(this).text()=="Graphs") {
$(this).html("<span><i class='fa fa-check-circle checked'></i> Graphs</span>");
graph = true;
} else {
$(this).html("<span>Graphs</span>");
graph = false;
}
});
After the user performs their initial operations, that larger menu is replaced by a smaller menu to provide the user more screen real-estate, using the following code:
function shrinkMenu() {
$('#search').html('');
$('#search').animate({
width: '4%'
}, 500);
$('#returnMain').animate({
width: '96%'
}, 500);
$('#search').load('smallMenu.php');
}
If the user wants the big menu back, on smallMenu.php I then have another <script> section with this code:
$('#growMenu').click(function () {
$('#search').html('');
$('#search').animate({
width: '20%'
}, 500);
$('#returnMain').animate({
width: '80%'
}, 500);
$('#search').load('largeMenu.php');
});
largeMenu.php contains a duplicate copy of the original HTML for the menu that loaded along with home.php, and visually, it looks exactly the same to the user.
As I toggle between large menu and small menu however, the <script> sections contained in home.php that pertain to the id tags in the original menu HTML that loaded with home.php no longer work.
In order to make it work, it seems that I would have to re-initialize all my plugins on each page load, and maintain 3 separate pages' <script> sections that are all duplicates of one another, and this seems very inefficient and probably not the best way to go about this.
Is there a better way for me to achieve the functionality I am trying to code here?
Update
My code looks like this at a high level:
<div class="searchParent" id="search">
<div class="return"></div>
<div class="menu">
<div class="largeMenu" id="largeMenu"></div>
</div>
</div>
What you are doing is fine by replacing the menu from a php file that contains a "partial view" which is your menu HTML. The partial view relies upon the parent page code, so you don't need to duplicate any code from the parent script into the partial view. The partial view can expect there is script code on the parent page it can be used with.
As I toggle between large menu and small menu however, the
sections contained in home.php that pertain to the id tags in the
original menu HTML that loaded with home.php no longer work.
The problem you are having though is that you need to ensure that the code on home.php that references these menus uses a parent container as its reference point instead of direct IDs. You are replacing elements (menus), so the bindings are lost when you do that unless you bind on a parent higher up the DOM that doesn't get replaced (remember that events bubble up).
From what I see in your code snippets, it looks like the menu is loaded into the #search container. So just ensure the code in home.php uses that container as the reference point, using something like on like this:
$('#search').on('click', '#graphsButton', function() {
// ...
});
I have a site set up in ASP.NET MVC3 right now, but the layout of everything is optimized for mobile devices.
I would now like to combine some of the existing views together to take advantage of the additional screen space in a desktop browser or tablet.
I have two views now, one displaying a list of links and a second displaying some content generated by each link; both these views are handled by separate controllers. Here is the list view (simplified). It uses a layout page, so this is what would be displayed when #RenderBody() is called in the layout (my second view also works like this, with the same layout file).
#model IEnumerable<CommandCenterEntity>
#{
if (Request.Browser.IsMobileDevice) {
Layout = "~/Views/Shared/_LayoutMobileContent.cshtml";
}
else {
Layout = "~/Views/Shared/_LayoutDesktop.cshtml";
}
}
<ul data-role="listview" id="commandcenterlist" data-filter="true" data-inset="true" data-theme="b">
#foreach (var entity in Model)
{
<li>
#Html.CommandCenterLinks(#entity, x => Url.Action("Index", "Worksheet", new { ParentId = #entity.ID_Item }))
</li>
}
</ul>
The CommandCenterLinks helper just generates an "a" tag containing a different icon depending on some properties of the entity.
I'd like to combine my views in such a way that when I click a link in the list, which would be in a div tag on the left of the screen, the generated content will display in a separate div tag on the right.
I was hoping I could reuse the same actions/controllers used in my mobile layout, so I tried using jQuery to intercept the click event on the list and capture the data returned from the action, and inject it into the div:
$(document).on("click", "#commandcenterlist a", function (e) {
$.mobile.showPageLoadingMsg();
$.ajax({
url: this.href,
success: function (data) {
$.mobile.hidePageLoadingMsg();
$("#desktopContentPane").html(data);
}
});
return false;
});
However, the data I get back in the ajax success handler contains the full html page,
<!DOCTYPE html>
<html>
<head>...</head>
<body>...</body>
</html>
...when all I want is the content that would have been generated in the layout's #RenderBody() call. I tried changing the controller method to have return PartialView("Index");, but it gave the same result. Is there a way for me to get back only that portion of the view? Or is there some cleaner, more "MVC" way of going about this?
The best option is really to return your partial view from a separate controller action. So, a few things I would change to make it work:
Take the content you want to share (whatever you want to display in the div for desktop) and put it in a partial view.
Create a controller action which returns just this partial view (use the PartialView method and pass in your partial view name), and call it from your javascript in the desktop version.
In view for the mobile version, you can use the RenderPartial method to include the contents from the partial view in your mobile page.
I've got a website and I'd like to make a part of it static. What happens is that the header, the menu bar and the footer are consistent in every page. I'd like to have them always loaded and when I click the menu button, it will only reload what is the body of the site.
Is there a simple chunck of code that can early achieve this? Something in js or ajax? I'm sorry but I don't have enough experience in these languages to accomplish something on my own. I've already tried to check jQuery library but it's still pretty confusing to me.
Thank you.
I think you don't even need Ajax or css!! Just use iFrames!! They are awesome, what happens is that u only design one page as the holder of your static content (Header-Menu ...) and put one iFrame in there as a place holder for any page you want to load in it, u should use proper css code to place the iFrame where you want, now, for every link in your menu, just set the "target" attribute equal to your iFrame's name and all the links will be loaded in that iFrame and your page won't be reloaded with every link click... I'll be back with some code...
Just add in every page a div container with ID for header, menubar and footer and just load it with this:
$(document).ready(function(){
$('#header').load('header.html');
$('#menubar').load('menubar.html');
$('#footer').load('footer.html');
});
Just make sure that the html files don't have html, head or body tags within, only the HTML-Code you would write inside the div. It's just like the include function in PHP.
EDIT:
For easy and simple implementation store the code above inside a .js file (e.g. include.js) and add this inside every head just below the include of all other scripts of your html files:
<script type="text/javascript" src="include.js"></script>
EDIT2:
Another solution ist to load the content of the page instead of the header, menubar, footer.
Here you take the same specifications (no html, body, etc. tags inside your content html files)
Name your content div e.g. <div id="content"></div>
Your navbar for example:
<div id="navbar">
Content1
Content2
</div>
JavaScript Code:
$(document).ready(function() {
//Click on a link that's child of the navbar
$('#navbar > a').click(function() {
//Get the html file (e.g. content1.html)
var file = $(this).attr('href');
//Load this file into the #content
$('#content').load(file);
return false;
});
});
You should consider the use of Server Side Included : http://httpd.apache.org/docs/current/howto/ssi.html
It's not quite easy to understand (as it refer to apache configuration), but this is a really great solution.
In a nutshell, you include parts of html code in you main page :
<!--#include virtual="/footer.html" -->
You won't have to use or understand all JQuery Framewol, user agent won't have to parse (if they are able to !) Javascript.
This is a pretty good replacement of PHP / ASP / Java for this kind of purpose.
You could use ajax to request the body of each page. But this is only one possibility - there are many. An other approach could be to create you page content using a script language (php, perl) serverside and employ a function there which adds footer, header and anything else to each page.
If you have an idea of Jquery then use click event on menu links to load the page in a div like the following syntax may help you.
$(document).ready(function(){
$("a.menu").click(function(){
$("#bodyContent").load("http://abc.com/your-linked-page.html");
});
});
To load the url dynamically use the following code:
In your menu bar the link looks like:
Home
In your Jquery code:
$(document).ready(function(){
$("a.menu").click(function(){
url = $(this).attr("title"); // here url is just a variable
$("#bodyContent").load(url);
});
});
Step 1: Add Jquery file into your html page.
Step 2: Use the above jquery code and change your menu link to the new what i said here.
Step 3: If you done it correctly, It will work for you.
How about a traditional iframe?
In your menu:
<a target="body" href="URL_to_your_Menu1_page">Menu1</a>
and then further in the document:
<iframe name="body" src="URL_to_homepage"></iframe>
You may use frameset and frames and organize you pages accordingly. So, frames containing menus can always be at display and while displaying contents on click of menu u may set target to frame in which you would like to load the contents.
I'm trying to figure out what the best practice is for using jQuery in an MVC app. Specifically, I would like to know what I should do so that I don't clutter all my views with individual document.ready statements.
As an example:
I have the following Views:
/Views/Shared/_Layout.cshtml
/Views/Home/Index.cshtml
/Views/Home/_Dialog.cshtml
/Views/Home/_AnotherDialog.cshtml
I have a controller action that will render the Home/Index View, which uses the Layout and renders two partial views (or editor templates, display templates, etc.). This one controller action has rendered 4 or more views. Each view is using some jquery document.ready code.
Currently, I have the code at the bottom of each view:
// In Index
<script type="text/javascript">
$(function() {
$('#tabs').tabs()
});
</script>
// In _Dialog
<script type="text/javascript">
$(function() {
$('#some-dialog').dialog( ... );
});
</script>
I know this isn't a very good practice because it is already getting unmanageable in my small project. What are some good practices to follow when I have tons of pages that all need some jQuery / javascript initialization code separated across dozens of views?
You could do something along the lines of what Telerik do with their javascript registrar. Basically, make this registrar available in your view model. At the simplest level, all it has to do is keep track of strings added to it:
public class JavascriptRegistrar
{
private StringBuilder jsBuilder_ = new StringBuilder();
public Add(string js)
{
builder.Append(js).Append('\n');
}
public string ToString()
{
return "<script type=\"text/javascript\">" + jsBuilder_.ToString() + "\n</script>";
}
}
Your partial views will then add to this when rendering:
<h1>In my view!</h1>
#Model.Registrar.Add("$function() { /* ... */ }")
Finally, at the bottom of your main view, when you're done:
#Model.Registrar.ToString()
Which will write out all the javascript it has collected during rendering.
If the initialisation is specific to a view and you know it definitely won't be used outside that view, for example some page specific behaviour, then just leave it in the view!
There is nothing wrong with having script tags in all your views, as long as you aren't replicating js between views. I think people tend to misunderstand 'separation of concerns' in this case and think that simply means 'keep different languages away from each other at all costs'...that is wrong, clearly if some page initialisation logic/behaviour is specific to a page, then the html and js intrinsically 'concern' each other, therefore moving the js into a separate file is not really 'good practice', if anything it makes your code more difficult to understand.
I personally like to open up a View, and be able to see all the js and css that is specific to that page as soon as I open it, makes it nice and readable. However, obviously if code needs to be shared then you need to bust it out your view and get in your scripts folder whwere it can be referenced by anything!
EDIT
In your example above I see in your Index view you initialise your tabs. This is fine as it is, however, if you added tabs somewhere else in the project then it might be better to create your tabs using a .tabs class rather than #tabs id, and then in an external js file initialise all your tabs at once by calling $('.tabs').
I have some JavaScript being returned by a url to jQuery. This JavaScript has document.write(...) statements in it. I would like to click on a link and have the output of the document.write(...) commands be inserted into a div.
It seems I've tried everything (jQuery load(), getScript(), get(), ajax(), inserting a script tag into the div with the url source specified, using JavaScript eval to try and capture the end-result of the JavaScript write(...) commands) and no matter what I do, the whole screen is taken over (blanks out/turns white) and the output of the JavaScript is the only thing on the screen, instead of that content ending up just in the div.
Any ideas of why this is happening and why it won't just load into the container element?
One more important detail. If I use the url in a script tag in HTML (e.g. ) it loads the content fine into the div.
???
Here is my current view code, which loads the generated JavaScript into the div, instead of the output of said JavaScript:
$(function($) {
$('#update_preview').click(function() {
event.preventDefault();
$('#preview').load('<%= url_for :controller => 'items', :action => 'preview', :id => #cf.id, :only_path => false %>');
})
})
});
You can use a innerHTML like this
document.getElementById("display").innerHTML = returnvariablehere;
<div id="display"> </div>
The screen was being redrawn because document.write(...) does not work after initial page load. Thus it was wiping the DOM and starting over when the JavaScript was evaluated.
I eventually had to rewrite the server-side code to output the raw HTML and use jQuery.html to replace the data returned by jQuery.ajax.
In the end, you can't load JavaScript that writes to the page in that manner unless it is guaranteed to load as the initial page is rendering.