This is in reference and related to my previous question here.
I am trying to read the Title of the part TitlePart as seen below code:
var query = Services.ContentManager.Query("SideBarLinks").List();
foreach (var sideBarLinks in query)
{
foreach(var part in sideBarLinks.Parts)
{
if (part is Orchard.Core.Title.Models.TitlePart)
{
// Below Line throws error
//string title = part.Title;
}
}
}
Each ContentPart has a title in orchard. So for the TitlePart, Iam trying to read the Title. Also is there any similar property that can be accessed like part.Name ?
Checked the code as well and there is a Public Title property as seen below:
Not all content types have the TitlePart attached. You can check this in your dashboard, and see if your content type has indeed the title part attached to it. For example, the Page content type:
In code you can check like this if the content item has a title part:
var query = Services.ContentManager.Query("SideBarLinks").List();
foreach (var sideBarLinks in query) {
// Cast to TitlePart
var titlePart = sideBarLinks.As<TitlePart>();
var title = titlePart != null ? titlePart.Title : string.Empty;
// Or:
// var title = sideBarLinks.Has<TitlePart>() ? sideBarLinks.As<TitlePart>().Title : string.Empty;
}
The safest and recommended way though to get the display text of a content item, is to use the item metadata:
var query = Services.ContentManager.Query("SideBarLinks").List();
foreach (var sideBarLinks in query) {
// Get display text of the item
var title = Services.ContentManager.GetItemMetadata(sideBarLinks).DisplayText;
}
This has multiple advantages. First one being that you don't have to check for the title part, the method itself will take care of that.
Another advantage is that you can override what you want to display as the title. Say you have a Movie content type, and you want the title to be displayed as "Some Movie Title (2001)". The only thing you then have to do is implement the ITitleAspect in your custom part:
public class MoviePart : ContentPart<MoviePartRecord>, ITitleAspect {
// Shortcut to get the title
public string MovieTitle {
get { return this.As<TitlePart>().Title }
}
public int ReleaseYear {
get { return Retrieve(x => x.ReleaseYear); }
set { Store(x => x.ReleaseYear, value); }
}
// other properties
// Implement Title from ITitleAspect
public string Title {
get { return string.Format("{0} ({1})", MovieTitle, ReleaseYear); }
}
}
The GetItemMetadata(theMovie).DisplayText of this item will then return the formatted title;
Related
Is it possible to use a foreach loop in a BLC to iterate through the fields of a PXResultSet to get the FieldNames?
Is this doable? I can't seem to find a good way.
Thanks...
The PXResultset records are selected from a view. You can get the field names from the View.
Here's a full example:
public class SOOrderEntry_Extension : PXGraphExtension<SOOrderEntry>
{
public override void Initialize()
{
// Get field list from data view
var dataView = new PXSelect<SOOrder>(Base);
string fieldNames = string.Join(",", GetFieldNames(dataView.View, Base.Caches));
// You don't need result set to get field names
PXResultset<SOOrder> resultSet = dataView.Select();
throw new PXException(fieldNames);
}
public string[] GetFieldNames(PXView view, PXCacheCollection caches)
{
var list = new List<string>();
var set = new HashSet<string>();
foreach (Type t in view.GetItemTypes())
{
if (list.Count == 0)
{
list.AddRange(caches[t].Fields);
set.AddRange(list);
}
else
{
foreach (string field in caches[t].Fields)
{
string s = String.Format("{0}__{1}", t.Name, field);
if (set.Add(s))
{
list.Add(s);
}
}
}
}
return list.ToArray();
}
}
When run, this example will show the fields names used in the data view in Sales Order screen SO301000 as an exception.
Field names are contained in Cache object. If you really need to get field names from PXResultset you need to iterate the cache types in the result set.
Example for first DacType (0) of result set:
public class SOOrderEntry_Extension : PXGraphExtension<SOOrderEntry>
{
public override void Initialize()
{
var dataView = new PXSelect<SOOrder>(Base);
PXResultset<SOOrder> resultSet = dataView.Select();
foreach (PXResult result in resultSet)
{
Type dacType = result.GetItemType(0);
foreach (var field in Base.Caches[dacType].Fields)
PXTrace.WriteInformation(field);
}
}
}
I just wondering how can I get an specific ContentItem in my controller.
I want to get the specific content Item and then display it's shape on my custom View..
PS: I also dont know how to get the ID of the content item should i use the ContentManager.Get(ID)
[HttpGet]
public ActionResult Index(string jobType, string location) {
var vm = new SearchForJobViewModel();
var items = new List<CustomPart>();
// Load the WhatsAround content items
IEnumerable<ContentItem> whatsAroundContentItems = ContentManager.Query().ForType("Custom").List();
foreach (ContentItem contentItem in whatsAroundContentItems)
{
ContentItemRecord contentItemRecord = contentItem.Record;
if (contentItem == null)
continue;
//CustomPart item = new CustomPart(contentItemRecord.Data);
//items.Add(item);
}
//Im also planning to pass the ContentItem in the view and then render it there
//return View("../JobSearchResults", items.Single(i => i.Name == "MyContentItem");
return View("../JobSearchResults", vm);
}
ADDITIONAL
[Themed]
[HttpGet]
public ActionResult Index(string jobType, string location) {
var vm = new SearchForJobViewModel();
vm.SelectedJobType = jobType;
vm.SelectedLocation = location;
//query all the content items
IEnumerable<ContentItem> items = ContentManager.Query().List();
foreach (ContentItem contentItem in items) {
ContentItemRecord contentItemRecord = contentItem.Record;
if (contentItem == null)
continue;
if (contentItemRecord.ContentType.Name == "CustomPage") {
// I just painfully search the contents just to get the ID of the specific content item that I want to display
// I dont know what table where I can see the ID on the content items
if (contentItemRecord.Id == 40) {
ContentItem ci = contentItem;
var test = ci.As<CustomPart>().Scripts; //custom part that I made
// the body part (raw html from the wysiwg editor)
// this I wil render it in my view
vm.Body = ci.As<BodyPart>().Text;
}
}
}
return View("../JobSearchResults", vm);
}
JobSearchResults.cshtml
#Html.Raw(Model.Body)
It's actually looks wierd but I'm trying something like utilizing Orchard CMS without using Orchard core (contentpart, drivers,handlers, etc)
Your can refer this.
http://skywalkersoftwaredevelopment.net/blog/getting-the-current-content-item-in-orchard
Or using the driver
protected override DriverResult Display(YourModulePart part, string displayType, dynamic shapeHelper){
var title = part.As<TitlePart>();
//here you can access the title part.
}
I want to create alternates for content item based on its tag value.
For example, I want to create an alternate called List-ProjectionPage-tags-special
Searching the nets directs me to implement a new ShapeDisplayEvents
Thus, I have
public class TagAlternatesFactory : ShapeDisplayEvents
{
public TagAlternatesFactory()
{
}
public override void Displaying(ShapeDisplayingContext context)
{
}
}
In the Displaying method, I believe I need to check the contentItem off the context.Shape and create an alternate name based off of that (assuming it has the TagsPart added to the content item).
However, what do I do with it then? How do I add the name of the alternate? And is that all that's needed to create a new alternate type? Will orchard know to look for List-ProjectionPage-tags-special?
I took a cue from Bertrand's comment and looked at some Orchard source for direction.
Here's my implementation:
public class TagAlternatesFactory : ShapeDisplayEvents
{
public override void Displaying(ShapeDisplayingContext context)
{
context.ShapeMetadata.OnDisplaying(displayedContext =>
{
var contentItem = displayedContext.Shape.ContentItem;
var contentType = contentItem.ContentType;
var parts = contentItem.Parts as IEnumerable<ContentPart>;
if (parts == null) return;
var tagsPart = parts.FirstOrDefault(part => part is TagsPart) as TagsPart;
if (tagsPart == null) return;
foreach (var tag in tagsPart.CurrentTags)
{
displayedContext.ShapeMetadata.Alternates.Add(
String.Format("{0}__{1}__{2}__{3}",
displayedContext.ShapeMetadata.Type, (string)contentType, "tag", tag.TagName)); //See update
}
});
}
}
This allows an alternate view based on a tag value. So, if you have a project page that you want to apply a specific style to, you can simply create your alternate view with the name ProjectionPage_tag_special and anytime you want a projection page to use it, just add the special tag to it.
Update
I added the displayedContext.ShapeMetadata.Type to the alternate name so specific shapes could be overridden (like the List-ProjectionPage)
My question is related to this one, but instead of changing a question I thought it Would be better to ask a new one.
I've now got a list of IContent items using the _taxonomyService.GetContentItems(term)
as suggested by #Bertrand Le Roy in the question mentioned above
But how do I turn this into a useful Html string, that I can update on the client via an ajax post?
public class HomeController : Controller
{
private readonly IOrchardServices _services;
private readonly IBlogService _blogService;
private readonly IBlogPostService _blogPostService;
private readonly IFeedManager _feedManager;
private readonly IArchiveConstraint _archiveConstraint;
private readonly ITaxonomyService _taxonomyService;
public HomeController(
IOrchardServices services,
IBlogService blogService,
IBlogPostService blogPostService,
IFeedManager feedManager,
IShapeFactory shapeFactory,
IArchiveConstraint archiveConstraint,
ITaxonomyService taxonomyService) {
_services = services;
_blogService = blogService;
_blogPostService = blogPostService;
_feedManager = feedManager;
_archiveConstraint = archiveConstraint;
T = NullLocalizer.Instance;
Shape = shapeFactory;
_taxonomyService = taxonomyService;
}
dynamic Shape { get; set; }
public Localizer T { get; set; }
public ActionResult Index()
{
return View();
}
[HttpPost]
public JsonResult ListByArchive(string path, IEnumerable<string> category)
{
try
{
// get year and month from path
path = path.ToLower().Substring(path.LastIndexOf(#"/archive/", StringComparison.Ordinal) + 9);
var date = path.Split('/');
var month = int.Parse(date[1]);
var year = int.Parse(date[0]);
// get list of terms ids from strings
var taxonomyPart = _taxonomyService.GetTaxonomyByName("Category");
var terms = category.Select(cat => _taxonomyService.GetTermByName(taxonomyPart.Id, cat)).ToList();
// get list of content items by term avoiding duplicates
var posts = new List<IContent>();
foreach (var term in terms)
{
var items = _taxonomyService.GetContentItems(term);
foreach (var item in items)
{
if (!posts.Select(p => p.Id).Contains(item.Id))
{
posts.Add(item);
}
}
}
// filter by date
var byDate = posts.Where(x =>
{
var publishedUtc = x.ContentItem.As<CommonPart>().CreatedUtc;
return
publishedUtc != null
&& publishedUtc.Value.Month == month
&& publishedUtc.Value.Year == year;
});
....
This gets me my list of IContent, but how do I get a the html for the rendered list ?
I've tried
var range = byDate.Select(x => _services.ContentManager.BuildDisplay(x, "Summary"));
var list = Shape.List();
list.AddRange(range);
dynamic viewModel = Shape.ViewModel().ContentItems(list);
var html = View((object)viewModel);
return Json(new { html = html });
but it returns an empty view,
{"html":{"MasterName":"","Model":[],"TempData":[],"View":null,"ViewBag":{},"ViewData":[],"ViewEngineCollection":[{"HostContainer":{}}],"ViewName":""}}
I have a view called ListByArchive.cshtml, that matches the one it the orchard.blog module.
As an aside, I should be returning a partial view result, instead of a jason result, but when I change the Action result type I get a 404. result from the server.
This is never going to work the way you think it does:
var html = View((object)viewModel);
The easiest way to return HTML representing the content item is to:
Mark your action with ThemedAttribute, ie. [Themed(false)]
Return new ShapeResult(this, viewModel) (full view) or new ShapePartialResult(this, viewModel) (partial view) instead of Json(new { html = html })
Rendering a shape/view to string inside the action is also possible, but way more tricky.
EDIT: I assumed you already have /Views/ViewModel.cshtml file in place. Like Bertrand Le Roy noted below - if it's not there, you need to add one to be able to create a shape using Shape.ViewModel().
I have created a new module in Orchard CMS, i have a new event part that has a whole bunch of custom fields. How do i change the heading displayed in the list of content?
Thanks
It is possible to set the meta data in the Handler
protected override void GetItemMetadata(GetContentItemMetadataContext context)
{
// We will set the display text, appears in content list
var e = context.ContentItem.As<EventPart>();
if (e != null)
{
context.Metadata.DisplayText = e.Name;
}
}
You could use the ITitleAspect method:
public interface ITitleAspect : IContent {
string Title { get; }
}
As seen in David Hayden's fine post.