Is it possible to change a web2py view on the fly? - view

Can you change the view being used by web2py in the controller? Ideally I'd be interested in doing something like:
response.view = 'NewViewName'

You've got it exactly, though be sure to include the relative path to the view within the /views folder. So, if you have /views/default/other_view.html, you can do:
response.view = 'default/other_view.html'
You can also directly render any view:
def myfunc():
context = dict(...)
return response.render('default/other_view.html', context)
See here and here.

Related

Get the file name BLADE of LARAVEL

is it possible to know which BLADE page you are on? I would like to include a different menu where my VIEW is the MAIN, how can I do this in the template? I check if it is my MAIN and add my different menu there if in case. example: #if(config('page.layout') == 'top-nav');
Is that possible? but with another code, of course
To me it seems like you are thinking with the wrong way. You should know what(which controller, which method) has loaded that view instead of what is this view. And you can pass control variables from there if you want.
In you question, the example you have shown:
#if(config('adminlte.layout') == 'top-nav')
So top-nav is coming form config adminlte.layout which has no relation with blade template or anything else. You can definitely do that if you set your config file based on your intention.
I wanted to pick up which file or URL my BLADE was, I got it this way:
#if(Route::current()->getName() == 'name') ....
##codeHTML
#endif

Rendering a partial in the parent directory in Ramaze

How do I render a partial that's in a different directory (in my case, the parent) than the current view?
<%=render_partial :sidebar%> #looks in the current dir and works as expected
<%=render_partial "/view/sidebar"%> #doesn't work!
Thanks!
You have to specify the right controller that is responsible for the right view:
TheRightController.render_partial :sidebar
If you don't specify the controller class, render_* works for the current action (controller) only, except render_full that does real internal HTTP request.
So, the answer is: If you need shared templates, just create special controller, i.e. called Shared, without any action methods inside, just with many templates in an appropriate view folder and call Shared.render_partial.
Shared.render_partial works like internal request. It renders contents of the controller's action and even the action's method is executed. If you want to render just the view (without executing Shared's action method), use Shared.render_view instead.
Moreover, you can use the internal requesting to prepare some data in the Shared controller's method. For instance, if your sidebar consists of #articles, let's load them in the Shared's sidebar() method. You don't need to load #articles in any other controller that displays the sidebar! You only call "Shared.render_partial :sidebar" in there. This is how to build widget-like web with Ramaze :-)
I found following api in apidock.com, maybe useful for u
# Renders a collection of partials located in a view subfolder
# outside of our current controller. In this example we will be
# rendering app/views/shared/_note.r(html|xml) Inside the partial
# each element of #new_notes is available as the local var "note".
render :partial => "shared/note", :collection => #new_notes
#rebnoob may use (without view directory name, because Rails search on app/view directory)
<%= render "/sidebar" %>
instead of
<%=render_partial "/view/sidebar"%> #doesn't work!

CleintDependency path with no Layout specified

I have an ASP.NET MVC 3 site that makes use of a ClientDependency framework for dep. resolution (CSS/JS).
My base path's are defined in /Shared/_Layout.cshtml like this:
#MvcHtmlString.Create(Html.RenderCssHere(new List<IClientDependencyPath> {
new BasicPath("Base", "~/Content/themes/base"),
new BasicPath("Content", "~/Content")
}))
I want to have one page without a standard layout. I force it by calling
#{
Layout = null;
Html.RequiresCss("FileUpload/fileUpload.css", "Content", 20);
}
However, I can no longer request a dep. like shown above, since "Content" path isn't defined.
I am rather new to ClientDependency framework, so which is the best way for me to get my dependencies in a non-layout view?
I need to have the Path declared somewhere in the View, as well as the RenderCss/JsHere element, so if I don't use a shared layout, I had to re-declare it in my custom page all together.

Change layout in controller depending on url

I have controller PlayerController and actions inside: View, Info, List.
So on urls "/Player/View" i get result with default Layout.
I want to get result with different Layout on request "/External/View".
How can i achieve this?
Although you can override the layout from the controller as has been suggested in another answer, in my opinion this means the controllers are getting just too involved in determining what the UI will be. Best to leave this purely to the Views to decide.
The closest to what you're asking is to do this in your current "~/Views/_ViewStart.cshtml":
#{
if(Context.Request.Path.StartsWith("/External", StringComparison.OrdinalIgnoreCase))
Layout = "~/Views/_ExternalLayout.cshtml";
else
Layout = "~/Views/_Layout.cshtml";
}
Where "~/Views/_ExternalLayout.cshtml" is your alternative layout.
Might want to check the leading "/" is correct on there, I can't remember if it is.
If you put this in the existing _ViewStart, then any view that is being rendering in response to a url starting with "/External" will use this new layout, otherwise the 'normal' one will be used.
Another approach is to use the routing table to add a route value that can be used here to make a layout decision; but I've gone for this approach to keep it simple.
You can specify which layout should be used when returning a view inside your 'ExternalController' controller action.
return View("View", "~/Views/Shared/_AnotherLayout.cshtml")

Inject selected view path as HTML comment to start and end of action's output

I'm currently putting together a multi-tenancy web app using MVC 3. At least 30 different Web sites will share a common codebase, and while also sharing similar under-the-hood functionality, they are need to look significantly different. As a consequence I'm using the URL to internally separate out clients, and an overridden Razor view engine (at least in terms of finding the view) to automatically select either a customised view for a given action, or the default view.
To help 'compartmentalise' a complex page, any particular view will make use of several partials, usually rendered as self-contained actions, so that generally a custom view or partial view will only have small HTML differences, helping to minimise any code specific to a client's site.
I hope you followed that background!
So one HTML page might be made up of lots of little smatterings of HTML partial views, which could come from specific folders for the client, or a general-purpose version. I'm hoping to make it easier for our designer to make minor changes to a page by easily seeing where in the folder structure the bit of HTML he wants to change are.
My proposal then is that each partial will be 'bracketed' with HTML comments such as:
{ Content of partial }
Obviously I could put these in manually, but that's just asking for trouble, for typos, for copied and then modified client versions not being updated with the correct URL. It should be possible to get this from some context and inject it, I think.
At the same time, I need to be able to not do this for certain Actions. Eg, a partial might be generating text inside a textarea, say, so the comments wouldn't be appropriate there. On the whole I'm happy to put these comments in unless I specify that it's not appropriate.
For me this suggests an ActionFilter on an Action, which I can apply site wide and then turn off for certain Actions. I'd hope that one of the overridable events would let me ascertain this path, but I can't seem to find anywhere it's stored. Furthermore, OnResultExecuting seems to fire before the Partial has been selected, and OnResultExecuted seems to have already written out the contents of the Partial, so I can't insert the starting comment here. I also can't find any reference to the path of the selected partial.
Just for completeness, it's my intention that this attribute would only write these comments when compiled in Debug mode.
So, does anyone know how I might be able to get the path to the selected View without any kind of hack between FindPartialView and the Attribute? Is my Attribute method the best choice or is there an easier way to do this? Perhaps something's built in already!
Many thanks for your help.
Well, I've never forgotten about wanting this, and always hoped I'd solve it one day, and thankfully I have.
I've overridden the default WebViewPage (I use the Razor engine), and in particular ExecutePageHierarchy to inject the comments:
public abstract class PaladinWebViewPage : PaladinWebViewPage<dynamic>
{
}
public abstract class PaladinWebViewPage<TModel> : WebViewPage<TModel>
{
public bool DisplaySourceCodeComments
{
get { return ((bool?) ViewBag.__DisplaySourceCodeComments) ?? false; }
set { ViewBag.__DisplaySourceCodeComments = value; }
}
public override void ExecutePageHierarchy()
{
base.ExecutePageHierarchy();
// Filters can be used to set and clear this value so we can decide when to show this comment
if (!DisplaySourceCodeComments) return;
var sw = Output as StringWriter;
if (sw == null) return;
var sb = sw.GetStringBuilder();
sb.Insert(0, string.Format("<!-- Start of {0} -->", VirtualPath));
sb.AppendFormat("<!-- End of {0} -->", VirtualPath);
}
VirtualPath tells us the exact file used to build the HTML, so we can inject the filename before and after. This isn't doing anything at the moment, since the default is to not show comments (the "?? false" in DisplaySourceCodeComments).
Also to use this view page you need to edit Views/Web.config and change the pageBaseType to this type.
I want to selectively turn these comments on and off so I've created an ActionFilter:
public class DisplaySourceCodeCommentsAttribute : ActionFilterAttribute
{
private readonly bool _displaceSourceCodeComments;
public DisplaySourceCodeCommentsAttribute(bool displaceSourceCodeComments)
{
_displaceSourceCodeComments = displaceSourceCodeComments;
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
var viewResult = filterContext.Result as ViewResultBase;
if (viewResult == null) return;
viewResult.ViewBag.__DisplaySourceCodeComments = _displaceSourceCodeComments;
}
}
I'm slightly unhappy that I've had to use the ViewBag here and also separately in the view page override, as they aren't tightly linked, but I can't find a way for the filter to directly interact with the view page, so this is something of a necessary fudge. It does have the benefit that displaying source code for a view or partial also automatically displays it for any child partials until you turn it off again, since the ViewBag is passed down the chain.
With this in place, any action can turn on the source code comments with
[DisplaySourceCodeComments(true)]
or, obviously turn it off again with false
The Attribute checks that the context result is a ViewResultBase, which means just Views and Partials, so Json or Content or redirects aren't affected, which is very handy too.
Finally, I make this action filter a global when running in debug mode so that every view, and partial has the source comment included, by adding the following line to global.asax.cs:
[#]if DEBUG
// When in debug mode include HTML comments showing where a view or partial has come from
GlobalFilters.Filters.Add(new DisplaySourceCodeCommentsAttribute(true));
[#]endif
I'm really happy I've finally got it sorted so I hope this is useful for someone else.

Resources