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.
}
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 have a custom action on screen CR304000 - OpportunityMaint in the Quotes tab of the grid view that marks a field called IsPrimary in the CRQuote DAC as true for the current record in the Quotes view. These project Quotes are associated with the current opportunity as well as with a related PMQoute in the PMQuoteMaint BLC. The PMQuoteMaint BLC has a view called Activties that has all the CRActivities associated with the PMQuote. I created a custom field in the CRActivity called IsPrimary and added it to the Activities view in the PMQuoteMaint BLC grid.
My goal was to override the Action in the OpportunityMaint to update the IsPrimary field in CRActivity to true or false depending on what the Action in OpportunityMaint is toggling. However, my IsPrimary field in PMQuoteMaint is not toggling. My code attempts to get Current Quote OpportunityMain and then create a PMQuoteMaint graph and set the Current record. Then iterate though Activies view and set the IsPrimary field accordingly. Like I said, not having success because I'm not sure that my code is successfully retrieving the correct Activities.
There might be a better way to access CRActivity associated with a PMQuote, but I'm not sure. Any help would be appreciated. Here is code:
public virtual IEnumerable PrimaryQuote(PXAdapter adapter)
{
foreach (CROpportunity opp in adapter.Get())
{
if (Quotes.Current?.IsPrimary != true)
{
var selectExistingPrimary = new PXSelect<CRQuote, Where<CRQuote.quoteID,
Equal<Required<CRQuote.quoteID>>>>(this);
CRQuote primary = selectExistingPrimary.Select(opp.DefQuoteID);
if (primary != null && primary.QuoteID != Quotes.Current.QuoteID && primary.Status ==
PM.PMQuoteStatusAttribute.Closed)
{
throw new PXException(PM.Messages.QuoteIsClosed, opp.OpportunityID,
primary.QuoteNbr);
}
var quoteID = Quotes.Current.QuoteID;
var opportunityID = this.Opportunity.Current.OpportunityID;
this.Persist();
PXDatabase.Update<Standalone.CROpportunity>(
new PXDataFieldAssign<Standalone.CROpportunity.defQuoteID>(quoteID),
new PXDataFieldRestrict<Standalone.CROpportunity.opportunityID>(PXDbType.VarChar,
255, opportunityID, PXComp.EQ)
);
this.Cancel.Press();
CROpportunity rec = this.Opportunity.Search<CROpportunity.opportunityID>
(opportunityID);
yield return rec;
}
yield return opp;
}
``` My OverRide
public PXAction<CROpportunity> primaryQuote;
[PXUIField(DisplayName = Messages.MarkAsPrimary)]
[PXButton]
public virtual IEnumerable PrimaryQuote(PXAdapter adapter)
{
// this is currently selected record in quotes grid
var currQuoteNbr = Base.Quotes.Current.QuoteNbr;
bool isPrimary2;
foreach (CRQuote quote in Base.Quotes.Select())
{
var quoteNbr = quote.QuoteNbr;
if(quoteNbr.Trim() == currQuoteNbr.Trim())
{
isPrimary2 = true;
}
else
{
isPrimary2 = false;
}
PXTrace.WriteInformation(string.Format("Quote: {0} Value:
{1}",quoteNbr.ToString(),isPrimary2.ToString()));
var PMQuoteMaintGraph = PXGraph.CreateInstance<PMQuoteMaint>();
PMQuoteMaintGraph.Quote.Current = PMQuoteMaintGraph.Quote.Search<PMQuote.quoteNbr>
(quoteNbr.Trim()); // this is the current quote
foreach (CRActivity activity in PMQuoteMaintGraph.Activities.Select())
{
CRActivityExt itemExt = PXCache<CRActivity>.GetExtension<CRActivityExt>(activity);
itemExt.UsrPrimary = isPrimary2;
PMQuoteMaintGraph.Activities.Cache.Persist(PXDBOperation.Update);
PXDatabase.Update<CRActivity>(new PXDataFieldAssign<CRActivityExt.usrPrimary>
(isPrimary2));
}
}
return Base.primaryQuote.Press(adapter);
}
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;
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().
Can anyone see why this should not work:
SPSite topNavigationSite = new SPSite("http://moss");
SPWeb topNavigationWeb = topNavigationSite.OpenWeb();
SPNavigationNodeCollection topNavigationBarNodes = topNavigationWeb.Navigation.TopNavigationBar;
SPNavigationNode updateNode = topNavigationBarNodes.Navigation.GetNodeByUrl("/about");
updateNode.Url = "";
topNavigationWeb.Update();
I can see debugging that the url get's set to "" but when the page renders, the navigation still shows the url as /about/default.aspx
I'm running this in page_load and expected it to update the moss database with the new url value.
I know this is 3years old! but as there is no where online about updating a current url!
I had to do some debugging and this is what iv come up with! By the way I got the hint from
topNavigationWeb.Update();
indicating that its updating a list! hint hint!
a bit of background! I wanted to update the quick links from a list when they add, update and delete an item from the list! On my list I have two columns Title and URL!
I then created a project in VS 2010, its an event receiver that is connected only to that list (done in the elements.xml file)
within the .cs file I added item added, item deleting(not deleted ;) ) and item updated
public override void ItemAdded(SPItemEventProperties properties)
public override void ItemUpdated(SPItemEventProperties properties)
public override void ItemDeleting(SPItemEventProperties properties)
now within each method you can simply call this method!
add/update
public static void AddQuickLaunchItem(string header, string url, SPWeb web)
{
SPNavigationNodeCollection quickLaunch = web.Navigation.QuickLaunch;
// try to get quick launch header
SPNavigationNode nodeHeader =
quickLaunch.Cast<SPNavigationNode>().Where(n => n.Title == header).FirstOrDefault();
//if header not found create it
if (nodeHeader == null)
{
nodeHeader = quickLaunch.AddAsFirst(new SPNavigationNode(header, url,true));
}
else
{
web.AllowUnsafeUpdates = true;
nodeHeader = quickLaunch.Cast<SPNavigationNode>().Where(n => n.Title == header).First() ;
nodeHeader.Url = url;
web.AllowUnsafeUpdates = false;
}
nodeHeader.Update();
web.Update();
}
the first part is checking if the node exists using the title (header)! I'm comparing between what headers there are and from the list item:
SPNavigationNode nodeHeader =
quickLaunch.Cast<SPNavigationNode>().Where(n => n.Title == header).FirstOrDefault();
this part is the comparison:
n.Title == header
I'm getting these values (header and url / spweb) like so:
public static void AddQuickLaunchItem(string header, string url, SPWeb web)
the method that is calling the above would look like this:
private void addloopweblinks(SPSite siteCollection, SPItemEventProperties properties)
{
// Enumerate through each site and apply branding.
foreach (SPWeb web in siteCollection.AllWebs)
{
AddQuickLaunchItem(properties.ListItem["Title"].ToString(), properties.ListItem["URL"].ToString(), web);
}
}
and the above method is called within the itemadded and itemupdated ;) passing the values like so:
public override void ItemAdded(SPItemEventProperties properties)
{
using (SPSite siteCollection = new SPSite(properties.WebUrl))
{
if (siteCollection != null)
{
addloopweblinks(siteCollection, properties);
}
}
}
similar things can be done for the delete ;)
SPNavigationNode nodeHeader =
quickLaunch.Cast().Where(n => n.Title == header).FirstOrDefault();
that will get the node!
nodeHeader.delete();
nodeHeader.update();
that will delete the item!
so in your case what you need, I don't know if you noticed it was this part:
web.AllowUnsafeUpdates = true;
nodeHeader = quickLaunch.Cast<SPNavigationNode>().Where(n => n.Title == header).First() ;
nodeHeader.Url = url;
web.AllowUnsafeUpdates = false;
nodeHeader.Update();
web.Update();
as you can see what i mean by the hint! nodeHeader.Update(); didnt update the url, when debugging it does change but when i go to the update part it doesnt work :( and it clicked in i need web.AllowUnsafeUpdates = true; loool only becuse I experienced a similar situation before!
for you it would be:
using(SPSite topNavigationSite = new SPSite("http://moss"))
{
using(SPWeb topNavigationWeb = topNavigationSite.OpenWeb())
{
web.AllowUnsafeUpdates = true;
SPNavigationNodeCollection topNavigationBarNodes =topNavigationWeb.Navigation.TopNavigationBar;
SPNavigationNode updateNode = topNavigationBarNodes.Navigation.GetNodeByUrl("/about");
updateNode.Url = "";
updateNode.Update();
web.Update();
web.AllowUnsafeUpdates = false;
}
}
If the user doesnt have the sufficent rights than you need to encapsulate the above with runwithelevatedprivalages :) hope this helps :)
Have you tried:
updateNode.Update();
topNavigationWeb.Update();
It doesn't look like you are updating the SPNavigationNode object. (Note: you may not need the second Update call.)