How to Save/Create a contentitem with another part attached?

Topics: General, Troubleshooting, Writing modules
May 25, 2015 at 11:26 AM
Hey Guys, I know this is not the correct way (as in, it wont work) - but can't seem to find an example of how to do it correctly.
        [HttpPost, ActionName("Add")]
        public ActionResult AddPOST(AdminViewModel viewModel)
        {
            // Type has GooglePart attached
            var item = Services.ContentManager.New<HostThemePart>("HostTheme");

            item.FirstName = viewModel.FirstName;
            item.LastName = viewModel.LastName;

            //wrong from here...

            item.As<GooglePart>().SiteVerificationCode = viewModel.Google.SiteVerificationCode;
            item.As<GooglePart>().NoTranslate = viewModel.Google.NoTranslate;
            item.As<GooglePart>().NoSiteLinksSearchBox = viewModel.Google.NoSiteLinksSearchBox;
            item.As<GooglePart>().TrackingId = viewModel.Google.TrackingId;

            Services.ContentManager.Create(item);
            ...
        }
I know this must seem ridiculously easy for most, but I am just a wee lamb in the coding department - any help, pointers, greatly appreciated - Big thanks, Liv
Developer
May 25, 2015 at 1:22 PM
This doesn't seem wrong to me but generally you don't want to (because you don't need to) use view models with content items and then assign part properties one by one. Instead you can let drivers to their job and just update the item from POST values. See this example: https://orchardtrainingdemo.codeplex.com/SourceControl/latest#Controllers/ContentsAdminController.cs
May 26, 2015 at 12:10 AM
Thanks for the reply Piedone, very much appreciated...ok, so I create/have a driver with:
...
        //Display        
        protected override DriverResult Editor(HostThemePart part, dynamic shapeHelper) {
            var viewModel = new HostThemeViewModel {
                FirstName = part.FirstName,
                LastName = part.LastName,
                Google = GoogleViewModel.Map(part.Google)
            };
            return ContentShape("Parts_HostTheme_Edit", () => shapeHelper.EditorTemplate(TemplateName: "Parts/HostTheme", Model: viewModel, Prefix: Prefix));
        }

        //Post
        protected override DriverResult Editor(HostThemePart part, IUpdateModel updater, dynamic shapeHelper) {
            var viewModel = new HostThemeViewModel();
            if(updater.TryUpdateModel(viewModel, Prefix, null, null)) {
                part.FirstName = viewModel.FirstName;
                part.LastName = viewModel.LastName;
                GoogleViewModel.Map(viewModel.Google, part.Google, _metaRepository);
            }
            
            return Editor(part, shapeHelper);
        }
...
currently I populate a dropdownlist so users can select a theme via my AdminController:
        public ActionResult Add() {
            var model = new AdminViewModel();

            // fetches all available themes
            model.Themes = _tenantService.GetInstalledThemes().Select(x => new ThemeEntry { ThemeId = x.Id, ThemeName = x.Name }).ToList();
            return View(model);
        }
as I now wish to let 'drivers do their job', what is the best way to populate such a 'create/edit' view with the above themes list -- do I have to return some sort of shape from the Add action [as per 'I believe' many OrchardHUN.TrainingDemo.Controllers.ContentsAdminController.cs Actions] or should I do this from the first DriverResult Editor which I have commented as //Display?

Sorry to be an inept pain, but I find it hard trying to learn the best procedures - especially when I'm 'really' still learning to program - as it seems there are so many ways to harvest fruit from this orchard ;) - Huge thanks, Liv
May 26, 2015 at 2:28 AM
Edited May 26, 2015 at 2:29 AM
In the meantime, whilst awaiting your reply, I went with the latter -- I hope it's the correct "Orchard" way of things? Thanks for your time, Liv :)
using System.Linq;
using Test.Tenancy.Models;
using Test.Tenancy.ViewModels;
using Test.Tenancy.Helpers;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.Data;
using Orchard.MultiTenancy.Services; //New
using Orchard.MultiTenancy.ViewModels; //New

namespace Test.Tenancy.Drivers {
    public class HostThemePartDriver : ContentPartDriver<HostThemePart> {
        private readonly IContentManager _contentManager;
        private readonly IRepository<Meta> _MetaRepository;
        private readonly ITenantService _tenantService; //NEW

        public HostThemePartDriver(IContentManager contentManager, IRepository<Meta> MetaRepository, ITenantService tenantService)
        {
            _contentManager = contentManager;
            _MetaRepository = MetaRepository;
            _tenantService = tenantService; //NEW
        }

        protected override string Prefix {
            get { return "HostTheme"; }
        }

        protected override DriverResult Display(HostThemePart part, string displayType, dynamic shapeHelper) {
            return Combined(
                ContentShape("Parts_HostTheme", () => shapeHelper.Parts_HostTheme(
                    Google: _contentManager.BuildDisplay(part.Google, displayType))),
                    
                ContentShape("Parts_HostTheme_SummaryAdmin", () => shapeHelper.Parts_HostTheme_SummaryAdmin(
                    Google: _contentManager.BuildDisplay(part.Google, displayType)))
            );
        }

        //Display
        protected override DriverResult Editor(HostThemePart part, dynamic shapeHelper) {
            var viewModel = new HostThemeViewModel {
                FirstName = part.FirstName,
                LastName = part.LastName,
                Google = GoogleViewModel.Map(part.Google),
                Themes = _tenantService.GetInstalledThemes().Select(x => new ThemeEntry { ThemeId = x.Id, ThemeName = x.Name }).ToList() //NEW
            };
            return ContentShape("Parts_HostTheme_Edit", () => shapeHelper.EditorTemplate(TemplateName: "Parts/HostTheme", Model: viewModel, Prefix: Prefix));
        }

        //Post
        protected override DriverResult Editor(HostThemePart part, IUpdateModel updater, dynamic shapeHelper) {
            var viewModel = new HostThemeViewModel();
            if(updater.TryUpdateModel(viewModel, Prefix, null, null)) {
                part.FirstName = viewModel.FirstName.TrimSafe();
                part.LastName = viewModel.LastName.TrimSafe();
                GoogleViewModel.Map(viewModel.Google, part.Google, _MetaRepository);
            }
            
            return Editor(part, shapeHelper);
        }
    }
}