Summary
How can different doctypes use the same layout (cshtml file)?
Setup
V7.8. modelsbuilder is on using AppData
DocTypes
There are 3 component doctypes:
internalFields
externalFields
content
These components are then used to build 3 composite doctypes:
webPage
blogSection
blogPost
The only difference between webPage and blogSection is that the latter has "listing" turned on. A single added field is all that makes a blogPost different from a webPage.
Templates
Each doctype is linked to a corresponding template. They then call the same layout.
The Issue
How do I bind my layout to all three models? If I use the same technique as above, I can get it to work only if the model matches the template that calls it. But then it only works for the corresponding doctype. Any node using a different doctype results in a binding error:
Cannot bind source content type
Umbraco.Web.PublishedContentModels.BlogSection to model content type
Umbraco.Web.PublishedContentModels.WebPage.
I am sure that there is something basic that I am missing here. Any help would be appreciated.
I think the simple answer is that you can create a new interface (e.g. IBaseCompositePage and have that interface inherit from your three composite interfaces e.g.:
using Umbraco.Web.PublishedContentModels;
namespace YourNamespaceHere {
public interface IBaseCompositePage : IInternalFields, IExternalFields, IContent
{ }
}
You'll still need to check the type of your model to get the field added to blogPost in a strongly typed way, but then again you could just us @Model.GetPropertyValue("myExtraProperty").
Two words of caution.
Having such a huge quantity of shared properties sounds like a bit
of an anti-pattern if they aren't actually relevant to every page
type.
I wonder if it might not be better sticking with your page model just being an IPublishedContent, and then use partials for each section of your page. Those are probably more likely to be compatible with passing in a model of just one of your composite interfaces.
Thanks for the reply. I have been reading up on the models builder and how to use it. But a follow-on questions to your answer: Is this interface the only place I declare my namespace (alluded to by YourNamespaceHere in your reply)?
I have looked through the automatically generated classes and interfaces, and they all set their namespace as Umbraco.Web.PublishedContentModels. Why would I not just add my interface to that namespace?
(I ask out of complete ignorance, not because I am puzzled by your answer.)
If you're create your own interface, then you can namespace it anywhere you like. But where you use the interface you'll need to include that namespace, as per any interface... I apologise if I misunderstand.
You can absolutely put your interface in Umbraco.Web.PublishedContentModels if you like.
That suggests that WtWebPage doesn't implement IWtComposite. Assuming both classes are generated by the models builder, do check that the composite has been correctly assigned and the models are up to date.
Layouts (master pages) and Models Builder
Summary How can different doctypes use the same layout (cshtml file)?
Setup V7.8. modelsbuilder is on using AppData
DocTypes There are 3 component doctypes:
These components are then used to build 3 composite doctypes:
The only difference between webPage and blogSection is that the latter has "listing" turned on. A single added field is all that makes a blogPost different from a webPage.
Templates Each doctype is linked to a corresponding template. They then call the same layout.
Here is the start of the webPage template:
The Issue How do I bind my layout to all three models? If I use the same technique as above, I can get it to work only if the model matches the template that calls it. But then it only works for the corresponding doctype. Any node using a different doctype results in a binding error:
I am sure that there is something basic that I am missing here. Any help would be appreciated.
I think the simple answer is that you can create a new interface (e.g.
IBaseCompositePage
and have that interface inherit from your three composite interfaces e.g.:Then you can have your view as:
You'll still need to check the type of your model to get the field added to
blogPost
in a strongly typed way, but then again you could just us@Model.GetPropertyValue("myExtraProperty")
.Two words of caution.
IPublishedContent
, and then use partials for each section of your page. Those are probably more likely to be compatible with passing in a model of just one of your composite interfaces.Thanks for the reply. I have been reading up on the models builder and how to use it. But a follow-on questions to your answer: Is this interface the only place I declare my namespace (alluded to by YourNamespaceHere in your reply)?
I have looked through the automatically generated classes and interfaces, and they all set their namespace as Umbraco.Web.PublishedContentModels. Why would I not just add my interface to that namespace?
(I ask out of complete ignorance, not because I am puzzled by your answer.)
If you're create your own interface, then you can namespace it anywhere you like. But where you use the interface you'll need to include that namespace, as per any interface... I apologise if I misunderstand.
You can absolutely put your interface in
Umbraco.Web.PublishedContentModels
if you like.Thanks David, that makes perfect sense.
Only problem is, I now get an error message about binding...
Any thoughts on how to handle this?
That suggests that WtWebPage doesn't implement IWtComposite. Assuming both classes are generated by the models builder, do check that the composite has been correctly assigned and the models are up to date.
is working on a reply...