Showing posts with label Sitecore MVC. Show all posts
Showing posts with label Sitecore MVC. Show all posts

Sunday, October 5, 2014

Sitecore MVC: Globalization for Model Attributes

There is an ability to create fields, fields labels and fields validation basing on model attributes in ASP.Net MVC:

public class SampleModel
{
[StringLength(50)]
[Required(AllowEmptyStrings = false)]
[DisplayName("Test")]
public object Name { get; set; }
}

In this case while you creating page you can use helpers:

@Html.LabelFor(m => m.Name)
@Html.TextBoxFor(m => m.Name)
@Html.ValidationMessageFor(m => m.Name)

You will get HTML form:



Everything will work with Sitecore MVC. However if you need provide translation of labels and messages on you form in Sitecore way you need to customize model attributes.


For DisplayNameAttribute it is easy to achieve with inheriting from standard attribute with adding Translate.Text:

public class DisplayNameAttribute : System.ComponentModel.DisplayNameAttribute
{
public DisplayNameAttribute(string displayName)
: base(displayName)
{
}


public override string DisplayName
{
get
{
return Translate.Text(base.DisplayName);
}
}
}

In this case when you will use new attribute for you model you will receive translated text for your labels. Same thing could be done for ValidationMessageFor, Required and other attributes.

Wednesday, September 17, 2014

Sitecore MVC Request Pipeline Execution Lifecycle

When I looked for description of Sitecore.MVC pipelines I faced with great post of David Morrison where was shown Sitecore MVC request pipeline execution lifecycle. I extended this diagram with Sitecore Analytics pipelines.

Sitecore.Mvc

When you’ll look at your showconfig.aspx you’ll find out that you have more Sitecore Mvc pipeline processors. Diagram does not include Sitecore Mvc pipelines for Experience Editor.

Thursday, September 4, 2014

AJAX Lazy Loading with Sitecore MVC

There was request to implement search with lazy loading for Sitecore MVC project. Unfortunately there is no such option in Sitecore out of the box. But I found great article how it could be done on Sitecore project with web forms. That idea works fine for web forms, but it does not work for MVC.

I modified processor proposed in article to work with MVC layouts.

var url = "http://myurl/myItem?UseAjax=true&PresentationId=BACBFEE1-C0BB-4D8E-BA1A-D9F50CCA5B7F";  

$.ajax({
type: 'GET',
url: url
}).done(function (data) {
//Your code
});

We will also need a MVC layout for the ajax queries (in the following code the MY_AJAX_LAYOUT_ID is the id of this layout) and this layout will only contain one placeholder (MY_AJAX_PLACEHOLDER in the code)

Now here is the custom layout resolver (look at the comments into the code):

namespace MyNamespace
{
using System;
using System.Linq;
using System.Web;
using Sitecore.Diagnostics;
using Sitecore.Mvc.Pipelines;
using Sitecore.Mvc.Pipelines.Response.GetPageRendering;
using Sitecore.Mvc.Pipelines.Response.GetRenderer;
using Sitecore.Mvc.Presentation;
using System.Web.Routing;

public class GetAjaxLayoutRendering : GetPageRenderingProcessor

{
public override void Process(GetPageRenderingArgs args)

{
bool useAjax;
//First of all let's check if we are in ajax mode or not if not don't continue
var result = bool.TryParse(HttpContext.Current.Request.Params["UseAjax"], out useAjax);
if (!result || !useAjax)
{
return;
}

//The second parameter we need to pass is the PresentationId if not present the query if not valid -> don't continue
var presentationId = HttpContext.Current.Request.Params["PresentationId"];
if (string.IsNullOrEmpty(presentationId))
{
return;
}

//If the current item is null return
if (Sitecore.Context.Item == null)
{
return;
}

//Let's resolve the rendering
try
{
//Get the list of rendering for the current item
var renderings = args.PageDefinition.Renderings;
//If found
if (renderings != null && renderings.Any())
{
//Get the first rendering corresponding to the requested one
var rendering = renderings.First(r => r.RenderingItem.ID.ToString().Equals(presentationId));

if (rendering != null)
{
args.PageDefinition.Renderings.Remove(rendering);
//Put this rendering into ajax layout
rendering.Placeholder = "MY_AJAX_PLACEHOLDER";

rendering.LayoutId = new Guid(JetstreamShops.Business.Constants.Ids.AjaxLayoutItemId);
var layout = renderings.First(x => x.RenderingType == "Layout");
if (layout != null)
{
args.PageDefinition.Renderings.Remove(layout);
for ( int i=0; i< args.PageDefinition.Renderings.Count; i++)
{
args.PageDefinition.Renderings[i].Placeholder =
args.PageDefinition.Renderings[i].Placeholder.Split('/').Last();
args.PageDefinition.Renderings[i].LayoutId =
new Guid(MY_AJAX_LAYOUT_ID);
}
layout.LayoutId = new Guid(MY_AJAX_LAYOUT_ID);
var getRedererArgs = new GetRendererArgs(new Rendering());
getRedererArgs.LayoutItem =
Sitecore.Context.Database.GetItem(MY_AJAX_LAYOUT_ID);

layout.Renderer = PipelineService.Get().RunPipeline<GetRendererArgs, Renderer>(PipelineNames.GetRenderer, getRedererArgs, a => a.Result);

args.PageDefinition.Renderings.Add(layout);
args.PageDefinition.Renderings.Add(rendering);
}
}
}
}
catch (Exception exception)
{
Log.Warn("Cannot render this!", exception, this);
}
}
}
}

Configuration will look in next way:
<mvc.getPageRendering>
<processor patch:after="*[@type='Sitecore.Mvc.Pipelines.Response.GetPageRendering.GetLayoutRendering, Sitecore.Mvc']" type="MyNamespace.GetAjaxLayoutRendering, MyAssembly"/>
</mvc.getPageRendering>
Many thanks to Vangansewinkel Benjamin whose idea was modified.