Reusable HTML snippets and sub-views in web2py - view

I have some reusable HTML snippets that I want to 'include' in a number of web2py views.
Using components with LOAD means having to write separate controller functions which need to load their own data.
Is there a way to:
Reuse dumb (no data) html snippets across views?
Reuse sub-views that would inherit the variables of the parent view, so that they can be inserted without calling controller functions and reloading data?

Reuse dumb (no data) html snippets across views?
You can use the {{include}} directive to include any view inside any other view. If you have /views/snippets/my_snippet.html, just do:
{{include 'snippets/my_snippet.html'}}
Reuse sub-views that would inherit the variables of the parent view, so that they can be inserted without calling controller functions and reloading data?
Views included as above will have access to the variables returned by the controller and any variables defined in the parent view prior to the include (as well as global variables defined in the models, just like any view).

Related

Orchard CMS Render module view in homepage

I'm trying to render a view, defined in a module, in the main site homepage (~/) as it's main content. If the user is not authenticated, i need to show a login/register view instead.
The logged-in view lives in one module (Product Module) and the login/register view lives in another (Account Module). The logged-in view requires a service call to fetch data based on the user's products. I'm currently using standard mvc to render these views and fetch the data they require in their controllers.
Can this be accomplished by treating these views as shape templates? If so, are there any examples of pulling in views to the homepage like this? Or is there a better way of achieving this?
I have tried implmenting IHomePageProvider to return my own homepage ViewResult within the Product module, but without any success.
Cheers.
First, you might want to look into widgets and layers. You could define a layer for authenticaed users, and one for anonymous users, and attach widgets to those layers to achieve what you want. That might be the best way for you to accomplish this. Look in the Orchard docs for examples on how to do this.
I have done a similar thing before using custom controller and a lot of custom logic. Because of my specific requirements widgets and layers would not work for this. All the content on the page needed to change depending on some inputs, and widgets and layers were not going to be well suited for this. What I did was create a custom controller, and a corresponding Route with a high priority (so the Route takes precedence over any others that want to be the home page). I didn't mess with IHomePageProvider at all.
In the controller action I pulled the data necessary, and created the shapes I wanted, and then returned a result like this: return new ShapeResult(this, homePageShape);
homePageShape is constructed like this, right before the return statement:
// Create personalized home page shape:
var homeShape = _orchardServices.New.CustomHome(
SomeShape1: someShape1
, SomeShape2: someShape2
, SomeModel1: someModel1
...
);
This creates a shape called CustomHome, and orchard will automatically look for a template called CustomHome.cshtml in the views folder of your module.
I created several shapes (all the "someShapeX" vars you see above). Mostly they are created from content parts via the BuildDisplay() method. The content parts are queried using IContentManager, and the shapes are created like this (this example is for a slide show shape):
dynamic sliderShape = _contentManager.BuildDisplay(sliderPart, "Detail");
You can put logic in the controller to build the shapes you want depending on whether or not the user is logged in. In CustomHome.cshtml you would render a shape like this:
#Display(Model.SomeShape1)

How does Orchard get away with no call to RenderBody?

I’ve been dissecting the Orchard CMS rendering and view engine in an effort to understand how it’s put together. I have discovered that neither RenderBody nor RenderSection are ever called. It is my understanding that the Razor view engine requires a call to one or the other.
What is it that gets around the requirement that RenderBody or RenderSection have to be called or an exception is thrown by Razor?
Is it the fact that there’s a custom view engine (ThemeAwareViewEngine)? If so, how does it handle parsing Razor syntax to generate the content?
Thank you.
It's actually the other way around. Razor itself doesn't require that RenderBody be called it's the RazorViewEngine that has this requirement. There can definitely be another view engine that uses Razor that has a completely different way of working. Take a look at https://github.com/Antaris/RazorEngine or https://github.com/Buildstarted/RazorSharp I've also written a markdown view engine that uses razor for some simple layouts.
From reading the source it looks as if they've created a few custom view engines. Their RazorViewEngine replaces the base class for razor generated files with their own custom WebViewPage which has a method Display of which Zone is an alias for. This is what allows them to render child views in addition it seems as if there are several types of Zones within the LayoutAwareViewEngine such as DocumentZone, ContentZone and so forth.
So in the end they've done a lot of custom code.

joomla add view into another view

Im using joomla MVC and I want to build a form that has different tabs which are different sections of the form with inputs in it. There are some tabs that are common to other forms that I need to include.
I would like to be able to load this common content from a separate file or view so i dont have duplicate code, plus is easier when I need to do a change to the form so I dont have to do it in all the forms. It's like displaying a view inside another view.
Is there a way to accomplish this?
A Joomla! provides the loadTemplate method to views.
So if you're currently in a tmpl file loaded for layout edit (ie. tmpl/edit.php ) you can call $this->loadTemplate('tab1'); and Joomla! will load the tmpl/edit_tab1.php file in the same view as your edit.php.
In that same view if you wanted to include say tmpl/other_tab1.php you would have to temporarily set the layout to other, eg. in one of our components during the Run template we need a tab from the Edit template, so we use:
<?php $this->setLayout('edit'); // This is ugly
echo $this->loadTemplate('plan');
$this->setLayout('run'); ?>
To load a template from another view alltogether, I think you would have to temporarily over-ride the view value, load the template then restore the view. eg.
$jinput = JFactory::getApplication()->input;
$jinput->set('view', 'other');
$this->loadTemplate('tab2');
$jinput->set('view', 'original');
NB: this last bit I haven't had time to test but it should work.
You can load a different template file for a different view manually, by simply requiring it. The following is for a view called "nameofotherview" with the layout "layoutname". If this is for an admin view use JPATH_COMPONENT_ADMINSTRATOR instead.
require(JPATH_COMPONENT_SITE . '/views/nameofotherview/tmpl/layoutname.php');
Remember that the data set up in the view class needs to be compatible with the main layout as well as the layout you're loading from elsewhere.
A side effect of doing this is that template overrides won't work. The loadTemplate function is doing a require but it checks the template paths for overrides first.
You can use vews in other views as described in Joomla documentation: Sharing layouts across views or extensions with JLayout

With regards to Html helpers, does data access code go into the helper class too?

I am writing a helper class to query my Zenfolio feed, return and display the images. Right now this code is split between a viewmodel and code in my controller. I want to pack it up into a helper class. Would all the code go into the helper or do i still split the code among different class with the helper only responible for generating the html? I have googled but not found an answer to my question.
Within the MVC pattern there is a clear separation between Model (data), View (html) and Controller (what gives the Model to the View).
To answer your question, No. Load your models in your Controller. Display them in your View. Html Helpers should only generate html for your view.
You may want to consider using a DisplayTemplate, which allows you use the same View template for every model of a particular type.
I wouldn't do any data access from the view. This sounds like a good use case for an action, and reusing code via the RenderAction method. You can mark the action as a child action using the [ChildActionOnly] attribute, which ensures it can't be invoked directly from the HTTP request, and return a PartialView result.
HTML helpers should really be used to generate HTML tags from data taken from the ViewData or Model (i.e. your view model in this case).
Data access in an HtmlHelper is only pain.
I've had the misfortune to inherit a project that had ad-hoc SQL placed into the HtmlHelpers by the 2nd developer on a project. The HtmlHelpers were beautifully written by the first developer, and the ad-hoc SQL pretty much nullified all of the time and effort put into having an service oriented architecture, having an ORM (the 2nd level cache became worthless), the unit of work pattern(transactions, worthless), and every aspect of design. Eventually, this 2nd developer had to make larger and larger HtmlHelpers so that different elements could share access to the data.
This was originally done for a display mode, and editing was accomplished through a pile of ugly custom javascript. All told, when the page rendered, it made 600 synchronous calls to the database.

Question on using content from other cshtml pages in razor

I've read a couple of articles on using asp.net mvc3 razor (which I am fairly new to). I have a couple of .cshmtl pages which are like shared content (e.g. header). They are basically just html pages with one or two divs etc.
To embed this in my main page, do I just use #renderPage("page address"). Do I also need a call to #renderbody? Do I need to specify the/a page in the layout property?
Thanksa
I would put the common elements in a layout (or perhaps a partial view rendered by the base layout). In fact, that's what I did in an application I am now building and it works quite nicely. The one issue is whether or not you need View Model data populated by the controller and passed to that partial view. I did, so I used a base controller and populated the common elements in the view model (all of those also inherited from a base class that had the common properties) and used sections and then in the sections renderered the partial view or not, depending on the view's need.
You can create a Partial View for each of these and call:
#Html.Partial("ViewName")
Or you can use sections, or this article on sections might help too.
As you may or may not know, ASP.NET accepts HTML tagging.
So why not include your .aspx file with the HTML include tag?
Here's how:
<!-- #include virtual="path to file/include-file.html" -->
Ex:
<!--#include virtual="header.aspx"-->
I do this all of the time when writing an ASP.NET website.
Just place it wherever you want the code, from the included page, to show up.

Resources