Giedrius
Giedrius

Reputation: 8550

Orchard and master detail editing

I was reading http://www.orchardproject.net/docs/Creating-1-n-and-n-n-relations.ashx and could not get the idea, if it is possible to easily make master detail editing, to give you concrete example i've attached screenshot from wordpress: enter image description here

So there is post and post contains set of custom fields, simple 1:N relationship, everything edited in one page - you can add/edit custom field without leaving post page.
May be someone saw similar example for Orchard on internet, or could shortly describe path to achieve this by code, would be really helpful (I hope not only for me, because this is quite common case I think).

Upvotes: 3

Views: 951

Answers (1)

mdm
mdm

Reputation: 12630

This should be possible, although not in the most 'Orchardy' way.

I've not tested any of the below so it is probably full of mistakes - but maybe Bertrand or Pszmyd will be along later today to correct me :-)

As you have probably seen you can pass a view model to a view when creating a content shape in your editor driver:

protected override DriverResult Editor(CatPart part, dynamic shapeHelper)
{
    // Driver for our cat editor
    var viewModel = new CatViewModel
    {
        Cats = _catService.GetCats() // Cats is IEnumerable<Cat>
    };

    return ContentShape("Parts_CatPart_Edit",
        () => shapeHelper.EditorTemplate(
           TemplateName: "Parts/CatPart",
           Model: viewModel,
           Prefix: Prefix
        ));
}

So we can pass in a list of items, and render it in our view like so:

@foreach(var cat in Model.Cats)
{
    <span class="cat">
        <p>@cat.Name</p>
        <a href="...">Delete Cat</p>
    </span>
}

The problem here would be posting back changes to update the model. Orchard provides an override of the Editor method to handle the postback when a part is edited, and we can revive the viewmodel we passed in the previous method:

protected override DriverResult Editor(CatPart part, IUpdateModel updater, dynamic shapeHelper)
{
    var viewModel = new CatViewModel();
    if (updater.TryUpdateModel(viewModel, Prefix, null, null))
    {
        // Access stuff altered in the Cat view model, we can then update the CatPart with this info if needed.
    }
}

This works really well for basic information like strings or integers. But I've never been able to get it working with (and not been sure if it is possible to do this with) dynamic lists which are edited on the client side.

One way around this would be to set up the buttons for the items on the N-end of the 1:N relationship such that they post back to an MVC controller. This controller can then update the model and redirect the client back to the editor they came from, showing the updated version of the record. This would require you to consistently set the HTML ID/Name property of elements you add on the client side so that they can be read when the POST request is made to your controller, or create seperate nested forms that submit directly to the contoller.

So your view might become:

@foreach(var cat in Model.Cats)
{
    <form action="/My.Module/MyController/MyAction" method="POST">
        <input type="hidden" name="cat-id" value="@cat.Id" />
        <span class="cat">
            <p>@cat.Name</p>
            <input type="submit" name="delete" value="Delete Cat" />
        </span>
    </form>
}
<form action="/My.Module/MyController/AddItem" method="POST">
    <input type="hidden" name="part-id" value="<relevant identifier>" />
    <input type="submit" name="add" value="Add Cat" />
</form>

Another possibility would be to create a controller that can return the relevant data as XML/JSON and implement this all on the client side with Javascript.

You may need to do some hacking to get this to work on the editor for new records (think creating a content item vs. creating one) as the content item (and all it's parts) don't exist yet.

I hope this all makes sense, let me know if you have any questions :-)

Upvotes: 2

Related Questions