Content Part Widget Driver with ViewModel?

Topics: Writing modules
Sep 1, 2011 at 1:22 PM


I have a widget, its all working ish!  I want to be able to pass data to the view that is not part of the ContentPart, so a ViewModel really.

When I pass a viewmodel to my view in the Get Editor, its works fine, but when Posting to Edit the values from the form are not there...which makes sense as its a different model!

So I tried adding a property to my ContentPart class 


and not to the Record class.  That worked great until I wanted to add a new property to the record.  I added the code to migrations, the new property etc, the column was created, however it was never persisted to the database?

So I removed the "extra" property on my content class, ran the same code and the new property worked fine and was updated in the database, I then added in my "extra" property to the Part class again and its now working as before.

I'm concerned however that when I release this module to the live env. I'm going to have the same problem.

What I want to do really (I think) is pass a ViewModel to my Edit view and either get that viewmodel back in the post?  (The Part class is a property on my ViewModel).


What the best solution for achieving this?  I did consider using a Html helper in my view, but I need the Orchard Services and didn't think it would be possible to get a handle on that as the helper is a static class?






Sep 1, 2011 at 6:14 PM

It would be useful to see what you're doing in your driver. TryUpdateModel shouldn't care about your record, only about whatever you pass in.

Sep 2, 2011 at 9:55 AM

Hi Bertrand, thanks for your response.

Here is my Editor post method

protected override DriverResult Editor(PPCMediaViewerPart part, IUpdateModel updater, dynamic shapeHelper)
            if (!updater.TryUpdateModel(part, Prefix, null, null))
                _notifier.Error(T("There was a problem updating the Media Viewer Part"));
            return Editor(part, shapeHelper);

Here is my Editor get method

protected override DriverResult Editor(PPCMediaViewerPart part, dynamic shapeHelper)
// build view model

return ContentShape("Parts_MediaViewer_Edit",
                                () => shapeHelper.EditorTemplate(
                                    TemplateName: "Parts/MediaViewer.Edit",
                                    Model: part,
                                    Prefix: Prefix

You can see I am passing my Edit view the Part model.  I would like to give it a view model.  

But what model would the Editor POST method get back?

Do i give the VIewModel the same properties as the Part model and the framework will do the rest?

I see what you mean with the TryUpdateModel taking any object, but how would it know to update the correct record if I pass in a different type of object i.e. My View Model and not Part?



Sep 2, 2011 at 11:05 AM
Edited Sep 2, 2011 at 11:07 AM

It doesn't know about the current content part or record, all it really knows are the values submitted in the request from the browser, and some information about the type of the 'part' parameter. TryUpdateModel sees that the part parameter is of a certain type, looks at the available properties on part.GetType(), then looks at the available values submitted from the client (in HttpContext.Request.QueryString), and where there is a match on the name (and in some cases on a type, eg if your class has an int property, then the incoming value must convert to an int), and then it uses some reflection-style magic to set those values in the instance that you passed it. This reconciliation of submitted values to an actual object is called model binding.

That's a bit of a mouthful, so let me show you an example (ripped from the RoutePartDriver):

protected override DriverResult Editor(RoutePart part, IUpdateModel updater, dynamic shapeHelper) 
var model = new RoutableEditorViewModel();
updater.TryUpdateModel(model, Prefix, null, null);

part.Title = model.Title;
part.Slug = model.Slug;
part.PromoteToHomePage = model.PromoteToHomePage;

// *snip*
return Editor(part, shapeHelper);

The complementing Editor() method is emitting a shape which builds (part of) a form with the correct fields for RoutableEditorViewModel. We then use model binding to populate a new instance of RoutableEditorViewModel with whatever is submitted from the form, and then use the values from that object to update our actual part/part record.

Hope this helps.