Skip to content

Commit

Permalink
Making the driver follow more generic conventions
Browse files Browse the repository at this point in the history
  • Loading branch information
Piedone committed Jun 29, 2020
1 parent d197757 commit 6958f27
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 32 deletions.
75 changes: 48 additions & 27 deletions Drivers/PersonPartDisplayDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,42 @@ public class PersonPartDisplayDriver : ContentPartDisplayDriver<PersonPart>

// A Display method that we already know. This time it's much simpler because we don't want to create multiple
// shapes for the PersonPart - however we could.
public override IDisplayResult Display(PersonPart part) =>
// Notice that there is no location given for this shape. There's another option of giving these locations
// using Placement.json files. Since it is not possible to put comments in a .json file the explanation is
// here but make sure you check the file while reading this. It's important to give a location somewhere
// otherwise to shape won't be displayed. The shape file should be in the Views folder by default, however,
// it could be outside the Views folder too (e.g. inside the Drivers folder).
public override IDisplayResult Display(PersonPart part, BuildPartDisplayContext context) =>
// Here you have a shape helper with a shape name possibly and a factory. The Initialize method will
// instantiate a view model from a type given as a generic parameter. It's recommended to use view models
// for the views like we're doing it here (sometimes you'd want a separate view model for the Display() and
// Edit().
// There are helper methods to generate the shape type. GetDisplayShapeType() in this case will generate
// "PersonPart" by default but this can be overridden form the part's settings under the content type's
// settings on the admin. In the factory we map the content part properties to the view model; if there is
// any heavy lifting needed to generate the view model (like fetching data from the database or an external
// API) then do it in that factory. That way the work will only be done if the shape is actually displayed.
Initialize<PersonPartViewModel>(GetDisplayShapeType(context), viewModel => PopulateViewModel(part, viewModel))
// Note that again we're referring to a display type here just as with Books, the Detail display type.
// While display types can be customized, by default Orchard uses "Detail" when the content item is
// opened in its entirety on the frontend, "Summary" when it's listed on the frontend, and
// "SummaryAdmin" when it's listed on the admin site. You can specify how a content part is displayed
// in these scenarios with these location settings.
// In this simple case, the same shape will be used both in Detail and Summary.

// NEXT STATION: Check out PersonPart.cshtml quickly and come back here.

// Note that we need the weight 1 to put our part's data above the Biography coming from a Text Field.
.Location("Detail", "Content:1")
.Location("Summary", "Content:1");

// This is something that wasn't implemented in the BookDisplayDriver (but could've been). It will generate the
// editor shape for the PersonPart.
public override IDisplayResult Edit(PersonPart part, BuildPartEditorContext context) =>
// Something similar to the Display method happens. GetEditorShapeType() will by default generate
// "PersonPart_Edit".

// Notice that there is no location given for this shape (no Location() method call). There's another
// option of giving these locations using Placement.json files. Since it is not possible to put comments in
// a .json file the explanation is here but make sure you check the file while reading this. It's important
// to give a location somewhere otherwise to shape won't be displayed. The shape file should be in the
// Views folder by default, however, it could be outside the Views folder too (e.g. inside the Drivers
// folder).
// In Placement files you can give specific locations to any shapes generated by Orchard. You can also
// specify rules to match when the location will be applied: like only for certain fields, content types,
// just under a given path. In our Placement file you can see that the PersonPart shape gets the first
Expand All @@ -41,29 +70,11 @@ public class PersonPartDisplayDriver : ContentPartDisplayDriver<PersonPart>
// https://docs.orchardcore.net/en/dev/docs/reference/core/Placement/#placement-files

// NEXT STATION: placement.json (needs to be lowercase) then come back here.
View(nameof(PersonPart), part);

// This is something that wasn't implemented in the BookDisplayDriver (but could've been). It will generate the
// editor shape for the PersonPart.
public override IDisplayResult Edit(PersonPart personPart, BuildPartEditorContext context) =>
// Something similar to the Display method happens: you have a shape helper with a shape name possibly and
// a factory. For editing using Initialize is the best idea. It will instantiate a view model from a type
// given as a generic parameter.
// There are helper methods to generate the shape type. GetEditorShapeType() in this case will generate
// "PersonPart_Edit" by default but this can be overridden form the part's settings under the content
// type's settings on the admin. In the factory you will map the content part properties to the view model.
Initialize<PersonPartViewModel>(GetEditorShapeType(context), viewModel =>
{
viewModel.PersonPart = personPart;
viewModel.BirthDateUtc = personPart.BirthDateUtc;
viewModel.Name = personPart.Name;
viewModel.Handedness = personPart.Handedness;
}).Location("Content:1");
Initialize<PersonPartViewModel>(GetEditorShapeType(context), viewModel => PopulateViewModel(part, viewModel));

// NEXT STATION: Startup.cs and find the static constructor.

// So we had an Edit (or EditAsync) that generates the editor shape now it's time to do the content
// So we had an Edit (or EditAsync) method that generates the editor shape. Now it's time to do the content
// part-specific model binding and validation.
public override async Task<IDisplayResult> UpdateAsync(PersonPart part, IUpdateModel updater, UpdatePartEditorContext context)
{
Expand All @@ -81,14 +92,24 @@ public override async Task<IDisplayResult> UpdateAsync(PersonPart part, IUpdateM

// Go and check the ViewModels/PersonPartViewModel to see how to do it and then come back here.

// Finally map the view model to the content part. By default these changes won't be persisted if there was
// Finally map the view model to the content part. By default, these changes won't be persisted if there was
// a validation error. Otherwise these will be automatically stored in the database.
part.BirthDateUtc = viewModel.BirthDateUtc;
part.Name = viewModel.Name;
part.Handedness = viewModel.Handedness;

return Edit(part, context);
}


private void PopulateViewModel(PersonPart part, PersonPartViewModel viewModel)
{
viewModel.PersonPart = part;

viewModel.BirthDateUtc = part.BirthDateUtc;
viewModel.Name = part.Name;
viewModel.Handedness = part.Handedness;
}
}
}

Expand Down
10 changes: 6 additions & 4 deletions Views/PersonPart.cshtml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
@model ShapeViewModel<PersonPart>
@model PersonPartViewModel
@* Not much interesting happening here, we just display data from the view model. Note that there's no need to display
anything from the Biography Text Field: The field has its own display already defined so it'll handle it for itself. *@

<div><strong>@Model.Value.Name</strong></div>
<div>@T["Birth Date: {0}", Model.Value.BirthDateUtc?.ToShortDateString()]</div>
<div>@T["Handedness: {0}", Model.Value.Handedness]</div>
<div><strong>@Model.Name</strong></div>
<div>@T["Birth Date: {0}", Model.BirthDateUtc?.ToShortDateString()]</div>
<div>@T["Handedness: {0}", Model.Handedness]</div>
2 changes: 1 addition & 1 deletion placement.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"PersonPart": [
"PersonPart_Edit": [
{
"place": "Content:1"
}
Expand Down

0 comments on commit 6958f27

Please sign in to comment.