CodeIgniter equivalents of ASP.NET MVC Master pages and content areas? - asp.net-mvc

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

Related

Angular2: optional component selectors

I have an ASP.NET MVC 4.x application that I'm rewriting to make use of Angular2.
Due to compatibility and time constraints it isn't possible to make it a single page application and therefore I need to use the routing of ASP.NET. Due to the fact that parts of the page will still be generated serversided by ASP.NET.
Basically what I want to do is sprinkle angular2 components in a static website(as far as Angular is concerned).
An example:
<html>
<body>
<my-appmenu>Loading menu...</my-appmenu>
some static text
<my-appselectproduct>Loading the select product</my-appselectproduct>
</body>
</html>
Would be one page, but another would look like this:
<html>
<body>
<my-appmenu>Loading menu...</my-appmenu>
some other static text
<my-appselectuser>Loading the select product</my-appselectuser>
</body>
</html>
Angular2 will crash doing this because it can't find the my-appselectuser selector in the first page and the my-appselectuser selector in the second page.
I found this earlier question which the answer seems to make it work, but it will still show a lot of errors like:
EXCEPTION: Error in :0:0 caused by: The selector "my-appselectuser" did not match any elements
Does anyone know how to fix these errors? I would really like to do this withouth having to create seperate angular2 apps for each component.
Thanks in advance, Victor

asp.net mvc working without view file

I have a plugable scenario on asp.net mvc. My Layout file contains a method for Head and body. Methods are rendering related plugin. So I have only one Controller/Action (Page/Index) and I dont need any view file for this action. Is that posible working without View file or only Layout file?
Thanks.
Layout example.
<html>
<head>
<title></title>
</head>
<body>
<div> MENU </div>
<div>
Plugin.Render("body"); //Render plugin method.
</div>
</body>
</html>
It seems an odd situation, but regardless:
It all depends on what you expect your one method to return. If it returns non-HTML (e.g. JSON, any primitive type, ...), you don't need it, obviously.
A HTML-layout is generally rendered via Views. I'm not sure if you can address your Master/Layout page as a view in and of itself. What I would suggest is adding a View file, setting it up with the correct Master/Layout page, and then basically empty out the view file.
So you'd have a View file, but it wouldn't have any content in it (except for the Master/Layout page setting).
It'd be slightly more understandable for future developers (although not that much), and I don't see any real downside to this (performance-wise or other).

Using wildcard for custom HTML tags in Rubymine

I'm developing a lot of RadiantCMS applications, and this CMS uses custom radiant tags which are translated to content and html at runtime. So, my HTML templates have a markup like this:
<body>
<div class="content">
<r:content />
</div>
...
</body>
This is all fine, but Rubymine complains about all the <r:content /> tags being invalid html. The effect is that my html-templates are loaded with error-notifications.
I know that you can customize the Rubymine Inspections, and allow Custom HTML Tags, but there are almost unlimited <r:... /> tags available. To add all possibilities in the customtags field would be hours of work and not very flexible, because new tags come and go by the month.
What I want to do is pass in a wildcard for the r: so that all those tags are allowed as valid html tags. I tried some REGEX options but gave me no results.
Does anyone have experience with Rubymine Inspections and how to overcome this issue?
There is a feature to define inspections per Scope. You can add a new Scope for all your project files except these template files (they can be excluded either by directory or name pattern). Then in the Inspection settings you can add this scope and configure the inspection reporting invalid HTML tags to trigger only in the custom scope, not for all the files. As your templates with <r:... /> are excluded from this scope, inspection will not report such files.
It's not ideal, as it will not report other possibly invalid tags in the template files, but right now there is no way to ignore tags by pattern, but you can submit a feature request.

How can I make code indentation behave correctly in vbhtml razor files?

This is driving me round the bend. I'm a long time VB.NET forms developer, quite new to ASP.NET and completely new to MVC. I'm creating vbhtml pages that use the VB.NET Razor syntax, and I seem to be constantly fighting against the UI which is trying to indent my code incorrectly. Take the following example, based on the template page for a new Razor view:
#Code
Layout = Nothing
End Code
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div>
#If True Then
#<ul>
#For x = 1 To 2
Next
</ul>
End If '<-- Randomly indented too far
</div>
</body>
</html>
In the above example, as soon as I hit return after Next, End If two lines below randomly jumps two tabs forward from where it should be. In other examples I've hit a circle where pushing one line to the correct place throws another line out of position and vice versa.
I'm so annoyed at this point I'd be happy to disable auto-indentation completely and just manage it myself, but I can't even find out how to do that! Following advice on another thread I disabled indentation for HTML pages but all that stops is indentation of HTML tags - the code blocks still slide around all over the place.
I thought an extension might be causing the problem but I disabled them all and restarted and the problem remains. Am I doing something fundamentally wrong? I find it hard to believe Microsoft would release something so poor so it seems more likely I'm just not using it right.
I found a solution (of a fashion) on another question (I really did search hard before posting this question and couldn't find anything): Why doesn't Visual Studio code formatting work properly for Razor markup?
Essentially the solution seems to be to ensure that your code uses spaces instead of tabs for the whitespace. Whilst increasing the overall size of the page because of increased whitespace, it does lessen the problem (whilst not eliminating it completely). On the linked thread, someone who appears to be connected with Microsoft has acknowledged it is indeed a bug related to the overlapping formatters for HTML and VB.NET which they hope to improve in a new release. I've dropped to 2 spaces per indent to lessen the bandwidth impact.
Thanks to the guys who contributed.
A better alternative here(rather than using spaces for tabs), is to change the block indenting for HTML and C#/VB to "Block" instead of "Smart". This isn't a full solution, but IMO is a far less painful work-around than using spaces!

Script & CSS Registration Helper in ASP.NET MVC?

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)"

Resources