4

I have been able to create a viewModel class which maps the fields of my schema using DD4T's "ViewModels" attributes:

[ContentModel("Content", true)]
public class ArticleViewModel
{
    [TextField(FieldName = "title")]
    public string Title { get; set; }
    [DD4T.Mvc.ViewModels.Attributes.RichTextField]
    public MvcHtmlString Body { get; set; }
}

I would now like to make use of this in my view. I have an action method in my controller:

public ActionResult Component(ComponentPresentation componentPresentation)
{
    return base.ComponentPresentation();
}

This gives me a Model of type DD4T.ContentModel.ComponentPresentation, while obviously I would like it to be an ArticleViewModel. I need to do something in my controller to instantiate my ArticleViewModel and have it populated with the fields from the component presentation, but it's not clear to me what the correct way to do this is. Obviously, I could just "new one up" and populate the fields manually, but then what would be the point of the annotations?

Actually - I'm not at all sure that I'm doing the right thing here, so any clarity anyone can add would be useful.

4 Answers 4

4

ViewModelFactory.BuildViewModel is able to transform/create a strongly typed model out of the DD4T model.

BuildViewModel() has 1 argument of type DD4T.ContentModel.IModel, Both DD4T.ContentModel.IPage and DD4T.ContentModel.IComponentPresentation are implementing IModel as a base.

Based on the type IPage or IComponentPresentation, the ViewModelFactory will try to find a ViewModel for the provided object. for IPage the Tridion PageTemplate Title is used and for ComponentPresentations the RootElementName of the component.

The mapping is done by annotation definition on the ViewModel Class.

PageModel:

[PageViewModel(TemplateTitle = "Home")]

ContentModel

[ContentModel("article", true)]

article = Schema's RootElementName

Home = PageTemplate Title

Within the Framework there is an default implementation for IViewModelFactory, and by calling the container.UseDD4T() in the global.asax the DefaultViewModelFactory is registers to you DI Container. which allows you to inject IViewModelFactory into your Controller:

public class MyController : Controller
{
    private readonly IViewModelFactory _viewModelFactory;

    public MyController(IViewModelFactory viewModelFactory)
    {
        _viewModelFactory = viewModelFactory;
    }

    public ActionResult Component(IComponentPresentation componentPresentation)
    {
        var model _viewModelFactory.BuildViewModel(componentPresentation)
        return View("viewName", model);
    }
}

The following code should be used, if the IComponentPresenation parameter could be of any type. if you're sure that IComponentPresenation has a component based on the schema Article. the following overload of BuildViewModel should be used as Katarina Stojanovski explains.

Article article = _viewModelFactory.BuildViewModel<Article>(cp);

Calling BuildViewModel with a IPage as parameter, the page and all it's ComponentPresentation will be transformed into ViewModels within a single call.

4

Long answer short... You can use IViewModelFactory to achieve this. For example:

Article article = _viewModelFactory.BuildViewModel<Article>(cp);

If you are going from a page down to component presentations, then it goes something like this:

You can have a class that is annotated with

[PageViewModel(TemplateTitle = "Home")]

and that has a property annotated with

[ComponentPresentations]

If your PageController inherits the aforementioned ModelControllerBase, then the mapping should be done automatically. You can see it on Github in PageModel action.

https://github.com/dd4t/DD4T.MVC/blob/develop/source/DD4T.Mvc/Controllers/ModelControllerBase.cs

Also note that your PageViewModel and ContentModel decorated classes need to implement IViewModel. That can be achieved by inheriting ViewModelBase which already exists in DD4T.

UPDATE! I have written a blog about this topic and included a link to VS example solution where you can check the code.

http://blog.trivident.com/dd4t-page-and-content-viewmodels/

2

Assuming this is DD4T 2, rendering partial views for Component Presentations, and that you have all the dependency injection etc setup, your most basic version of this method should be:

public class ComponentController : ModelControllerBase
{
    public ComponentController(IPageFactory pageFactory, IComponentPresentationFactory componentPresentationFactory, 
        ILogger logger, IDD4TConfiguration dd4tConfiguration, 
        IViewModelFactory viewModelFactory) 
        : base(pageFactory, componentPresentationFactory, logger, dd4tConfiguration, viewModelFactory)
    {
    }

    public override ActionResult ComponentModel()
    {
        return base.ComponentModel();
    }
}

With the following in your page layout

@foreach (var item in Model.Items)
{
   @Html.Render(item)
}
1

You need to have your PageController overrided with PageModel

public class PageController : ModelControllerBase
{

    public PageController(IPageFactory pageFactory, IComponentPresentationFactory componentPresentationFactory,
    ILogger logger, IDD4TConfiguration config, IViewModelFactory viewModelFactory)
        : base(pageFactory, componentPresentationFactory, logger, config, viewModelFactory)
    {

    }
    public override ActionResult PageModel(string url)
    {
        return base.PageModel(url);
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.