How to render a template by name? - servicestack

I am trying to get my head around ServiceStack self-hosted app and the new API.
Adding two views of the same name in separate folders results in an error at startup. Is this not allowed?
Foo\
Index.cshtml
Bar\
Index.cshtml
Is there a way to specify a template via a decorator on a method or directly as a return value? I know about the convention of naming views after DTOs. I prefer to be more explicit or follow a convention closer to Sinatra/Express.
return Render(typeof(Views.Foo.Index), new { Name = "Nelly" });

The ServiceStack's Razor Rockstars website which holds the documentation for Razor support in ServiceStack lists some options for selecting a different template:
If it doesn't follow the convention (i.e. Request or Response DTO name) then you can dynamically specify which view or layout template gets used by returning a decorated HttpResult like:
return new HttpResult(dto) {
View = {viewName},
Template = {layoutName},
};
If you're using a static view (i.e. service always uses the same view) then you can specify what view to use by decorating it with the [DefaultView] attribute
[DefaultView("Rockstars")]
public object Get(Rockstars request) {
...
return responseDto;
}
In either case, if you want it strong-typed you can use something like typeof(RequestDto).Name.
View names must be unique
Unlike MVC, heirachy's does not influence view selection in ServiceStack and because each View Page (i.e. razor pages in the /Views folder) must be unique, you're free to lay them out in any flat or nested folder structure you wish.

Related

Alternate shape for EditorTemplate of Field is not being recognized

I need an alternate for the EditorTemplate of an Enumerator Field that's used when the Field has a particular name (PublishingMethod).
Based on the docs, I created a view with the pattern [ShapeType__FieldName] in the same folder as the original shape:
This is not working and still uses the original. I've thought of changing the Editor method in the Driver, but I think that defeats the purpose of alternates, which is that Orchard automatically detects the correct shape as I understand from the docs:
The Orchard framework automatically creates many alternates that you can use in your application. However, you can create templates for these alternate shapes.
Note: I can't use the Shape Tracing module, it never worked even with a clean Orchard install.
The editors in Orchard work different to how Display works. I guess it is so you get a MVC-style experience. Basically, the actual shape returned is of type EditorTemplate, which then binds your model and prefix then renders a partial view with the template name you gave it. What this means is alternates wont work as expected, or as the docs state. The alternates for your field name are actually added to the EditorTemplate shape. So what you can do is add a view called EditorTemplate-PublishingMethod.cshtml with contents like:
#{
var m = (Orchard.Fields.Fields.EnumerationField)Model.Model;
}
#Html.Partial("PublishingMethodEditor", m, new ViewDataDictionary {
TemplateInfo = new TemplateInfo { HtmlFieldPrefix = Model.Prefix }
})
Then add another view called PublishingMethodEditor.cshtml with the overrides you want for your editor. All these views should go in the root of your Views folder.
Another approach would be to implement the IShapeTableProvider interface and adjust the TemplateName property on a certain condition but, meh, that requires code...
Edit 1
If you have that field name on other content types that you don't want to override you can use the override EditorTemplate-ContentTypeName-PublishingMethod.cshtml

ServiceStack.Razor PartialViewResult equivalent?

Is there a way to return the ASP.NET MVC equivalent of a PartialViewResult (stand-alone partial) in ServiceStack.Razor?
In my service, I would like to return the response DTO as a rendered Partial as opposed to a complete View; again, I just need some rendered HTML snippets for this service.
The use case is to make an AJAX call to a service and then have the service returned the rendered partial.
In one of my views, I just tried the following, but it is still returning the full HTML markup and not just the small snippet.
inside travel.cshtml...
#model TravelScenarioResponse
#Model.Name
You can specify to not use any Layout with #layout "", e.g:
#layout ""
#model TravelScenarioResponse
#Model.Name
Otherwise if you want the same view to be used with multiple layouts and as a partial you can add an Views/Empty.cshtml that just contains:
#RenderBody()
And use that layout in any of the View/Template overrides documented in EmailContacts. E.g. you can decorate your Service or action with a [ClientCanSwapTemplates] attribute, e.g:
[ClientCanSwapTemplates]
public class MyService : Service { ... }
And then the client can specify what view they want to render service with, so you can view a partial by specifying ?Template=Empty on the query string, e.g:
http://razor.servicestack.net/rockstars?Template=Empty
http://razor.servicestack.net/rockstars?View=AngularJS&Template=Empty
http://razor.servicestack.net/rockstars?Template=SimpleLayout

Overriding editor template in theme affects admin view

I created a form using the CustomForms module and need to control the markup of the input fields I've included on the form (to add bootstrap specific classes). I added a view to my theme at the location /Views/EditorTemplates/Fields/Input.Edit.cshtml and that allowed me to update the markup for the input fields.
My problem is that the view in my theme is also being picked up in the admin views. I didn't expect this behavior but it's happening. I tried scoping the view override to the url (Input.Edit-url-contact.cshtml) and content type (Input.Edit-ContactRequest.cshtml) using the alternate naming conventions but they do not appear to work in this case.
Is there a way to scope the Input.Edit.cshtml view in my theme so it only applies to the front-end of the site? Or is there a better way to achieve what I'm trying to do?
I ended up working around this issue by implementing a shape table provider (based on Bertrand's suggestion) to specify different template names in my theme so they weren't picked up in the admin. Here's what it looks like:
public class EditorFieldShapeProvider : IShapeTableProvider
{
public void Discover(ShapeTableBuilder builder)
{
builder.Describe("EditorTemplate")
.OnDisplaying(displaying =>
{
var shape = displaying.Shape;
if (shape.ContentField is InputField) {
shape.TemplateName = "CustomInputField";
}
});
}
}
Just drop that class somewhere in your theme and create your view at /ThemeName/Views/EditorTemplates/CustomInputField.cshtml

Seam page actions and conversation

I have created my application using seam-gen. Seam-gen has created all the crud operations & forms for all my objects. They all inherit from seam's EntityHome.
I have this requirement that I need to create from an object A another object B (A has a List). So I need to redirect the user to the B form, save a new B object, and then redirect him to the original A form with the updated List contents.
I am a newbie in Seam and I am not sure how to implement this properly.
Edit: I am using seam version 2.2.2 final.
You can create an action class (similar to how entityHome works without the baggage that comes with it) to manage your contained entities and their behaviors. If no relationship exists between the entities you can make one here.
Refreshing the original list can be tricky, but once you have some code started post it.
So I would start with something like:
Class ActionBean {
ClassAObj classA;
List<ClassBObj> classBList;
public void methodThatLinksAandB() {
// ... stuff happens here
}
// getters and setter for view
// private worker methods
}

JSF portlet generating different Id for different environment

I am creating a dynamic form which hides/unhides fields based on selection of radio buttons.
I was using normal javascript function as given below which is working fine in my portal environment(the ids are the JSF ids which i get by viewing source).
function printHiddenValue(){
alert("hello");
alert(document.getElementById('A1938:j_idt4:create-ticket:hiddenId').value);
if(document.getElementById('A1938:j_idt4:create-ticket:j_idt19:0').checked){
alert("incident sellected")
} else
{
alert("change sellected")
}
}
but fails when i deploy the war in different environment as differnrt ids are generated by the portal environment.
You should not rely on dynamic ids, not just A1938 part of id but also j_idt4 may change if you change structure of your page for example. You should assign id to component j_idt4, and for first part you can use EL #{facesContext.externalContext.response.namespace} to get namespace of your portlet:
document.getElementById('#{facesContext.externalContext.response.namespace}:j_idt4:create-ticket:hiddenId')

Resources