i'm bit confused about Razor in MVC. I am newbie to RAZOR and MVC and has just created LOGIN and register page for practice. My boss asked me to put some Theme/Template and then integrate it with this code. My questions is:
Is it possible to integrate a theme being designed in HTML/CSS with Razor based syntax, i mean that i created my VIEWS of MVC RAZOR but now if i put HTML/CSS based theme with it then what complications or things are gonna arise ?
yes. Super possible. Views are basically dynamic HTML.
simply copy the html to the view and once the view is rendered, you will see the entire html.
any place in the html you need to be dynamic while being rendered, you can use "#" sign and that will start c# code. then you may create c# code and add html in it too.
example:
#{
string name = "Jovan";
var dateOfBirth = new { Day = 8, Month = 12, Year = 1980 };
string[] skills = new string[] { "MVC", "C#", "JQuery", "ASP.NET" };
}
<h2>#name</h2>
<p>Born in year: #dateOfBirth.Year</p>
<ul>
#foreach(skill in skills){
<li>skill</li>
}
</ul>
in this example, you first fill up the values you are showing, and then you show them. here a for each runs against the number of skills that you filled in the array meaning 4 times can creates a "li" tag each and every time it runs.
Of course in most cases you dont do this. you create the values on the controllers or better yet service or business layers and then you pass it through a model to the view. so basically view just renders the information that is recieved from the controllers.
here is another example:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Web Pages Demo</title>
</head>
<body>
<h1>Hello Web Pages</h1>
<p>The time is #DateTime.Now</p>
</body>
</html>
in this example, the page will always render the current time and date of the server.
another example:
<select id="fieldStaffUsersListBox" multiple size="10">
#foreach (var user in Model.Users)
{
<option value="#user.UserName">#user.FullName</option>
}
</select>
here you are dynamically creating a select box which renders the list of the users that you have passed from the controller throgh the Viewmodel to the view.
you can use this tutorial to learn more:
http://www.asp.net/mvc/tutorials/older-versions/javascript/creating-a-mvc-3-application-with-razor-and-unobtrusive-javascript
you'd have a whole lot to learn.
good luck :)
Related
I'm setting up Umbraco 7.7 for the first time and creating the document types and templates for a page that displays the people that work at our organization (includes their names, photos, and bios).
How do I configure it such that the content manager can add another "person"—effectively a cluster of divs with user-editable images and text—without having to manually add another "person" to the template? Using Partial Views seems like part of the solution, but I'm unclear on how to fit it all together.
My template (simplified) currently looks something to the effect of:
#inherits Umbraco.Web.Mvc.UmbracoTemplatePage
#{
Layout = null;
}
<!doctype html>
<html>
<body>
<div class="person-bio">
<img src="/media/person-01-photo.jpg">
<p>#Umbraco.Field("person-01-name")</p>
<p>#Umbraco.Field("person-01-title")</p>
<p>#Umbraco.Field("person-01-bio")</p>
</div>
<div class="person-bio">
<img src="/media/person-02-photo.jpg">
<p>#Umbraco.Field("person-02-name")</p>
<p>#Umbraco.Field("person-02-title")</p>
<p>#Umbraco.Field("person-02-bio")</p>
</div>
<div class="person-bio">
<img src="/media/person-03-photo.jpg">
<p>#Umbraco.Field("person-03-name")</p>
<p>#Umbraco.Field("person-03-title")</p>
<p>#Umbraco.Field("person-03-bio")</p>
</div>
<!-- etc., etc. -->
</body>
</html>
Thank you! Any help would be much appreciated.
You'll probably will want to use the Nested Content control for this. It allows you to add a list of entities (in your case persons) on a document
More documentation about the nested content control can be found here: https://our.umbraco.com/documentation/getting-started/backoffice/Property-Editors/Built-in-Property-Editors/Nested-Content
So from my understanding you don't need a partial view. If it's that simple and you want to output only the div I see you're repeating, then loop it:
#foreach (var person in whateverYourCollectionIs) {
<div class="person-bio">
<img src="/media/person-01-photo.jpg">
<p>#person.GetPropertyValue<string>("pseudoNameFieldAlias")</p>
<p>#person.GetPropertyValue<string>("pseudoTitleFieldAlias")</p>
<p>#person.GetPropertyValue<string>("pseudoBioFieldAlias")</p>
</div>
}
That loop will create the exact same html for each person, but with the appropriate names, Titles, Bio etc. This is not the actual code you get to use but it hopefully leads you to the correct direction.
This is the documentation that will help
I minimized the problem to this simple reproduction. Create new Asp.net MVC app, add Angular.js via nugget.
_Layout.cshtml:
<head>
<!-- Other stuff -->
#RenderSection("JavascriptInHead", required: false)
</head>
_Index.cshtml
#section JavascriptInHead {
<script src="~/Scripts/angular.min.js"></script>
}
<div ng-app>
{{2 + 2}}
</div>
So this works (obviously), however when I click, say About or Contact menu to reload another view and then go back to Home, I get
{{2 + 2}}
Then I click page reload two times and I get
4
Please help me understand this..
Angular bootstraps when the document loads. So if you are loading html that contains angular into your page without doing a full page refresh, you'll need to bootstrap angular manually. Try adding this script to your partial page:
angular.element(document).ready(function() {
angular.bootstrap(document);
});
btw, I for one appreciate you posting a concise example rather than 100 lines of code from your actual project. If your actual project has an app name, however, like this...
<div ng-app="myApp">
then the js you put into your partial page should look like this...
angular.element(document).ready(function() {
angular.bootstrap(document, ['myApp']);
});
Documentation for manually bootstrapping Angular can be found here: https://docs.angularjs.org/guide/bootstrap
I used PHP years ago but have since been developing in C#/VB.Net.
In ASP.Net MVC 2, you can provide a master page which defines content areas eg:
<html>
<head>
<title>Overshare | <?=$Title?></title>
<ContentArea name="Head"/>
</head>
<body>
<ContentArea name="Body"/>
</body>
</html>
Your view would then have something like:
<Content name="Head">
<!-- Some Head Content -->
</Content>
<Content name="Body">
<h1>Some Body Here</h1>
</Content>
I don't seem to be able to emulate the same functionality with Code Igniter. The options seem to be:
manually pre-set some associative array of variables (eg in the controller) and then simply substitute the values into a template file - This is a lot of code to repeat in each view and doesn't belong in the controller. It also means it's a real pain to put large bodies of html into one of the ContentAreas - It's either string concatenation or something equally nasty with almost no chance of HTML intellisense in any IDE.
Use a templating library - I haven't found one which doesn't fundamentally work as described above
Now, I haven't used CodeIgniter before and am about to start a large PHP project so want to make sure it's the correct tool before actually starting work. Am I missing something obvious or is this templating functionality difficult to replicate?
Edit: Libraries tested:
Phil Sturgeon's Template Library
CI Smarty
PHXView
If you have a good idea of how your pages are to be built then you can write a set of functions to deal with it either in a MY_Controller.php file or in a library.
So you could have a routine which calls
$this->mypagetemplates();
Which calls data out of a class's properties eg $this->page->title;
I split my data as I create it into
$this->page->head,
$this->page->header,
$this->page->content,
$this->page->aside
$this->page->footer
Which corresponds with the HTML5 sections we use in 90% of our projects
My $this->mypagetemplates() function (or method if you prefer) can take a number of arguments and calls various views as a result eg:
$contentview = 'shop/products';
$asideview = 'shop/basket';
Which, if populated, are then called thus
If ($asideview) {
$this->load->view($asideview, $this->page->aside);
}
Overall Though, I'd say don't design your biggest ever project on a framework that us new to you. Play around first.
I ended up creating 3 files which represented the following
OpenHeader:
<html>
<head>
<Head Stuff/>
OpenBody:
</head>
<body>
<html>
<Templating Stuff>
Close:
</Templating Stuff>
</html>
</body>
</html>
And then modified my views to include these three at the appropriate time.
It's inelegant but flexible and powerful so it'll do for now - especially since I can pass varuables eg Page title into the files during the include if I use the CodeIgniter view engine to retrieve them
I've got an issue with MVC routing(or at least I think it's w/routing :) )...
Just upgraded to MVC RC1, but I'm not sure that it's related as this is my first attempt at setting a MapRoute and corresponding RouteLink.
here's the route:
routes.MapRoute("Test1",
"Forecast/CurrentLineItems/{propertyID}/{forecastYear}/{forecastMonth}",
new { controller = "Forecast", action = "CurrentLineItems", propertyID = "", forecastYear = "", forecastMonth = "" }
);
here's the RouteLink...in the view it's wrapped in a table cell:
Html.RouteLink(Html.Encode(myProperty.Description),"Test1", new { controller = "Forecast", action = "CurrentLineItems", propertyID = myProperty.PropertyID.ToString(), forecastYear = "2008", forecastMonth = "10" })
here's a snippet from the controller:
namespace AnApplication.Controllers
{
[HandleError]
[Authorize]
public class ForecastController : Controller
{
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult CurrentLineItems(string propertyID, string forecastYear, string forecastMonth)
{
//Some code
}
Now for the strange behavior, when I click the link specified by the RouteLink, the app enters the CurrentLineItems method and all the method arguments are correct...
then it enters the CurrentLineItems method again!
with, for instance, these arguments:
propertyID = "scripts"
forecastYear = "jquery-1.2.6.js"
forecastMonth = ""
It then repeats this several times as it seems to run through all the scripts on this view and the Site.Master and then the last one is the .css file for this page!
What is going on!
The Call Stack is of no help as it lists the above-mentioned CurrentLineItems method and then below that is the dreaded [External Code]
When I profile the page/view in FireFox/FireBug all I see are the jQuery calls
Here's the html from the Site.Master re the scripts
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title><%= Html.Encode(ViewData["Title"]) %></title>
<script type="text/javascript" src="../../scripts/jquery-1.2.6.js"></script>
<script type="text/javascript" src="../../scripts/calculations.js"></script>
<script type="text/javascript" src="../../scripts/common.js"></script>
<style media="all" type="text/css">#import "../../Content/all.css";</style>
<!--[if IE]><link rel="stylesheet" type="text/css" href="../../Content/ie.css"media="screen"/><![endif]-->
<!--<link href="../../Content/Site.css" rel="stylesheet" type="text/css" />-->
</head>
here's a snippet from the view re the scripts
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"AutoEventWireup="true" CodeBehind="CurrentLineItems.aspx.cs" Inherits="AnApplication.Views.Forecast.CurrentLineItems" %>
<asp:Content ID="lineItemsContent" ContentPlaceHolderID="MainContent" runat="server">
<!--<script type="text/javascript" src="../../scripts/MicrosoftAjax.debug.js"></script>-->
<script type="text/javascript" src="../../scripts/lineItems.js"></script>
<script type="text/javascript" src="../../Scripts/jquery.formatCurrency.js"></script>
<!--<script type="text/javascript" src="../../scripts/jquery-1.2.6.min.js"></script>-->
Note that this ActionLink works fine(It's basically just a menu item used for testing and the three arguments are set in the code inside the controller...):
<%= Html.ActionLink("Line Items", "CurrentLineItems", "Forecast")%>
Any help in solving this issue is greatly appreciated.
Thanks,
Greg
There were in fact two subtle, yet annoying bugs in the recently release ASP.NET MVC Release Candidate. These were the two bugs:
We changed all our URL-rendering methods to render relative URLs instead of absolute URLs. While we feel this might be the right decision in general, we found that it breaks an awful lot of scenarios. AJAX scenarios were especially affected since the URLs for retrieving data asynchronously are often different from the original URL as seen in the browser's address bar.
Html.RouteLink specifically (and not Html.ActionLink) had a bug in it (so it is not in fact a red herring - at least not necessarily). Html.RouteLink would erroneously take the "current" controller and action and pass those values into the routing system. Only Html.ActionLink is supposed to do that. Html.RouteLink is not supposed to do any processing at all. It's supposed to just take the values you give it and pass it along to the ASP.NET Routing system.
Since these two bugs were both pretty bad, we decided to roll back the change that caused #1 and to fix the issue that caused #2 and release an updated ASP.NET MVC Release Candidate Refresh.
You'll see some posts on ScottGu's blog, Phil Haack's blog, and the ASP.NET MVC Forums detailing the refresh.
Thanks,
Eilon
It could be caused by the usage of relative paths to include the scripts.
When you click on the link the URL of the new page will be something like http://[server]/Forecast/CurrentLineItems/xxx/2009/1
Now check the html code in the browser: If the URLs are in the form of '../../scripts/jquery-1.2.6.js', this will cause the browser to load it from http://[server]/Forecast/CurrentLineItems/scripts/jquery-1.2.6.js - and so your controller gets called again.
If that is the case you could either use absolute paths ('/scripts/jquery-1.2.6.js') or use a path relative to the application root ('~/scripts/jquery-1.2.6.js') and resolve it on the server side with Page.ResolveClientUrl().
Maybe there has been a change from Beta to RC1, so that the URLs in the head, even with runat="server", don't get remapped.
RouteLink versus ActionLink is a red herring here. The only thing that matters is the rendered a href="[something]". You would get exactly the same results if you wrote the a href manually instead of generating it via RouteLink.
So, yes, now we're down to routing. Inside your controller action, inspect RouteData in the debugger, and see which route name was matched. Chances are very likely it's the wrong one, and that is causing other things to misbehave. Either change the order of your reps, or add constraints to prevent the wrong one from being matched.
RouteLink works very well to prevent finding the wrong route when you're generating a URL. But when your application is consuming a URL, you still need to have your routes in order in global.asax.
I have tried to use ASP.NET MVC for a while, then I face a problem that I don't want to include all of my js and css in master page. But how can I register it in head of master page from my specific view?
The default master page template includes a Content PlaceHolder for the head. If it doesn't you can easily add one:
<head runat="server">
<title></title>
<asp:ContentPlaceHolder ID="head" runat="server" />
</head>
Your views can then put anything they want in the head:
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
<script src="Scripts/myScripts.js" type="text/javascript"></script>
<link href="Styles/myStyles.css" rel="stylesheet" type="text/css" />
</asp:Content>
It doesn't look like there's a simple option 'built-in' to the ASP.NET MVC framework just yet. If you are using a user control (.ascx), which you may be if you are creating self-contained controls which also want to manage their own JavaScript requirements, then you can't even use the placeholders to help you out.
In the end I created a helper class and in it there are a couple of methods:
private static SortedList<int, string> GetRegisteredScriptIncludes()
{
var registeredScriptIncludes = System.Web.HttpContext.Current.Items["RegisteredScriptIncludes"] as SortedList<int, string>;
if (registeredScriptIncludes == null)
{
registeredScriptIncludes = new SortedList<int, string>();
System.Web.HttpContext.Current.Items["RegisteredScriptIncludes"] = registeredScriptIncludes;
}
return registeredScriptIncludes;
}
public static void RegisterScriptInclude(this HtmlHelper htmlhelper, string script)
{
var registeredScriptIncludes = GetRegisteredScriptIncludes();
if (!registeredScriptIncludes.ContainsValue(script))
{
registeredScriptIncludes.Add(registeredScriptIncludes.Count, script);
}
}
public static string RenderScripts(this HtmlHelper htmlhelper)
{
var registeredScriptIncludes = GetRegisteredScriptIncludes();
var scripts = new StringBuilder();
foreach (string script in registeredScriptIncludes.Values)
{
scripts.AppendLine("<script src='" + script + "' type='text/javascript'></script>");
}
return scripts.ToString();
}
That's a basic form of it anyway to try and show the way it works. It could be enhanced in many ways, but at the moment it just filters out duplicate script insert requests for you. Whenever you want to add a new script in the ascx (or aspx for that matter) you can do it this way:
<%
Html.RegisterScriptInclude(Url.Content("~/Scripts/MapLayers/MapLayer.js"));
Html.RegisterScriptInclude(Url.Content("~/Scripts/MapLayers/Vehicles.js"));
%>
Then you need to remember to output them once you're done. This is achieved by making the following call at the place in your page where you want to output the script tags:
<%=Html.RenderScripts() %>
Seems to work so far for me. I did half expect to have rendering issues depending at what point RenderScripts was called, especially if not all of the RegisterScriptIncludes had been called yet, but so far it seems to do the job. If you render the scripts last then you should have no problems.
#Jason: WARNING, you shouldn't be using static variables like this... In a web context static variables are shared across all users and all page requests. I am amazed that you haven't run into trouble with your code. The principle is fine but the code is wrong and will give you trouble. In this case you should be using System.Web.HttpContext.Current.Items. See http://www.hanselman.com/blog/ATaleOfTwoTechniquesTheThreadStaticAttributeAndSystemWebHttpContextCurrentItems.aspx for more.
Here is a solution similar to the one Jason gave, but takes vdh_ant's comments into consideration:
http://frugalcoder.us/post/2009/06/29/Handling-Scripts-in-ASPNet-MVC.aspx
technically you should be putting all your js at the bottom of the page for the best performance.
I think the only way you could do this though would be to include the javascript in the VIewData and have the ViewData displayed on the masterpage (not a great solution).
MVC Futures now has built in helpers for this...
1.<head>
2. <title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
3. <%= Html.Css("BlueTheme/site.css") %>
4. <%= Html.Script("jquery-1.3.2.js") %>
5.</head>
More information here: http://blog.osbornm.com/archive/2009/10/12/mvc-script-css-helpers.aspx
Mathew,
I took a look at your blog on Html.Css and Html.Script helpers. I don't mean to be critical but I do not see any mention in the blog about how the Css and Script helpers would address the problem discussed here. The problem here is one of needing to "registered" script references at any point during the rendering process, and possibly multiple times (in the case of an template or partial view that is used several times and registers its own scripts), and then outputting the aggregate results, sans duplicates, in a single location.
If your solution addresses this, please correct me with some clarification.
--Regards,
Ken
I wrote just such a manager for MVC, and wrote about it on my blog:
"JavascriptHelper–Managing JS files for ASP.NET MVC"
UPDATE: I added bundling:
"JavascriptHelper:Managing JS files for ASP.NET MVC (With Bundling)"