RoutePart Title null after UpdateEditor

Topics: Writing modules
Oct 6, 2011 at 6:54 PM
Edited Oct 6, 2011 at 7:01 PM

I have a custom ContentType called Project with Route part attached.

ProjectController.cs CreatePOST method:

var project = _orchardService.ContentManager.Create<ProjectPart>("Project", VersionOptions.Draft, p => p.JobPart = job); 
var projectModel = _orchardService.ContentManager.UpdateEditor(project, this);

also on the ProjectController.cs, which implements IUpdateModel:

bool IUpdateModel.TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) {
    return TryUpdateModel(model, prefix, includeProperties, excludeProperties);
}

ProjectPart.cs:

public string Title {
    get { return this.As<RoutePart>().Title; }
    set { this.As<RoutePart>().Title = value; }
}

When I try to create a Project it will hit the setter and the value is correct (what the user entered). The immediate line after the UpdateEditor in the ProjectController has the project.Title value at null.

It does successfully create a RoutePartRecord in the database with a null Title, Slug, and Path.

Am I trying to use this wrong?

VersionOptions.Draft, (o) => { o.ForumPart = forum; });
Coordinator
Oct 6, 2011 at 7:07 PM

Did you try to put breakpoints in there and see in particular if your TryUpdateModel gets hit?

Oct 6, 2011 at 7:21 PM

Yes, and I've stepped into it pretty deep and watched the ProjectPart.Title setter get hit, with the correct value to set.

Coordinator
Oct 6, 2011 at 7:45 PM

Did you try to publish the content item through the content manager once you're done updating it?

Oct 6, 2011 at 7:50 PM

Yeah, I should have mentioned that in my original. This is after the UpdateEditor and some other stuff:

 

_orchardServices.ContentManager.Publish(project.ContentItem);


If I alter to this (adding the third line only) , it all works fine:

var project = _orchardService.ContentManager.Create<ProjectPart>("Project", VersionOptions.Draft, p => p.JobPart = job); 
var projectModel = _orchardService.ContentManager.UpdateEditor(project, this);
project.Title = ValueProvider.GetValue("ProjectPart.Title").AttemptedValue;

 

 

Nov 10, 2011 at 1:38 PM

I think I've pinpointed what's going on. The RoutePartDriver's Editor function is being called after the ProjectPartDriver's Editor function.

The ProjectPartDriver successfully sets the Title.

But then, because I'm suppressing the RoutePart's edit template with the placement.info, the RoutePart doesn't have any values to apply thus overriding the Title with a null value.

 

<Placement>
  <Match ContentType="Project">
    <Place Parts_Routable_Edit="-"/>
  </Match>
</Placement>

Any red flags as to what I'm doing wrong here? Thanks.

 

Nov 10, 2011 at 2:19 PM

This sounds like a tricky situation to resolve. Let's just reduce this down to your initial requirements;

- Why do you need a Title property on ProjectPart?

- Are you trying to establish some kind of connection between ProjectPart and RoutePart?

- Do you need routing on your Project content type? In which case you shouldn't be suppressing RoutePart's editor UI under any circumstances...

- What is the overall aim of what you're trying to do here?

Nov 10, 2011 at 2:21 PM

Got it to work by updating the cshtml for my ProjectPart's editor template. I had to manually create the text input for the title and name it Routable.Title so the value would be there when the driver needed it. The Html.TextBox helper kept prepending the input with Project_ so I couldn't use it. Some insight on if I'm doing it wrong would be great. Thanks again!

<input type="text" id="Routable_Title" class="large text" name="Routable.Title" value="@Model.Title" />

Nov 10, 2011 at 2:25 PM

If you're just trying to use the Title functionality without Routable, then all you need is Orchard 1.3 - it includes a separate TitlePart that you can use where you don't need routing.

Nov 10, 2011 at 2:32 PM
Edited Nov 10, 2011 at 2:32 PM
randompete wrote:

This sounds like a tricky situation to resolve. Let's just reduce this down to your initial requirements;

- Why do you need a Title property on ProjectPart?

For the project's title. I could remove the tie from the Routable Part but it just made sense, and I was looking at Orchard.Blogs for reference and that's how it's done there.

- Are you trying to establish some kind of connection between ProjectPart and RoutePart?

Exactly. I'd like for the Title to be a shared field. You can see in my first post that instead of Title being backed in the Project table I'm backing it in the Route table with .As<RoutePart>().Title

- Do you need routing on your Project content type? In which case you shouldn't be suppressing RoutePart's editor UI under any circumstances...

I tried to not show my ProjectPart's Title and show the RoutePart's editor UI but I don't want the user to mess with any of the slug stuff. Is there a way to override the RoutePart's editor in my module? Or just suppress the slug and homepage promotion inputs in its Editor?

- What is the overall aim of what you're trying to do here?

Have a ContentType with a ProjectPart and RoutePart (and whatever other arbitrary ContentParts, like Contrib.Voting) that can be created in the front end of the site by authenticated users.

I've learned a whole lot working through this problem, but still feel like I'm not doing it right.

Nov 10, 2011 at 3:03 PM
Edited Nov 10, 2011 at 3:04 PM

I think the problem is that at the moment there's no real "right way" to do this. But it does seem like you're going slightly "um die Ecke" (around the mountain) to solve this.

Since Orchard 1.3 (as I said above) there's a separate TitlePart - but that doesn't solve the problem of removing the Slug editor while leaving routable in place.

You can place an override in your module for EditorTemplates/Parts.Routable.RoutePart.cshtml - and remove the bits from that you don't need. Although I don't know if this will cause an error in the RoutePartDriver!

This kind of behaviour should be a lot easier to control once we have Autoroute - your users will choose from a fixed list of routing templates instead of manually editing the slug.

Coordinator
Nov 10, 2011 at 7:44 PM

The right way of getting the title or the next best thing is to call GetItemMetadata on the content manager. The metadata you get out of it has a DisplayText property. That is what you want, I think.

Developer
Nov 10, 2011 at 7:53 PM

Very important to note (I don't know what's the cause of this, however it's the experience): routing data (the RoutePart) is only filled (i.e. it could only be requested from the content item's RoutePart, however perhaps it gets saved anyway) if requested after calling ContentManager's UpdateEditor() but before calling ContentManager.Create()!

Nov 11, 2011 at 3:00 PM
randompete wrote:

You can place an override in your module for EditorTemplates/Parts.Routable.RoutePart.cshtml - and remove the bits from that you don't need. Although I don't know if this will cause an error in the RoutePartDriver!

I tried this earlier and it didn't override the template.

@model Orchard.Core.Routable.ViewModels.RoutableEditorViewModel

<fieldset>
    @Html.LabelFor(m => m.Title, T("Title"))
    @Html.TextBoxFor(m => m.Title, new { @class = "large text" })
</fieldset>

Nov 11, 2011 at 3:04 PM

I tested something similar and it worked; make sure your module has a dependency on Routable in its manifest (so Orchard knows the right inheritance order for overrides)

Nov 16, 2011 at 12:21 PM
randompete wrote:

I tested something similar and it worked; make sure your module has a dependency on Routable in its manifest (so Orchard knows the right inheritance order for overrides)

That was it. Worked a charm after I added the dependency. Thanks randompete!