Magnolia get content from children page in freetext - magnolia

I have a tree structure and want to use this as a category based faq.
I know there is a categorization module, but i want to use a file tree structure.
so i had the following:
faq
- first category
- first entry
- second entry
- second category
- first entry
...
each page has an dialog with an headline and a description. thats the content i want to get for each page.
so currently i get the current page, and loop through the childpages
[#local currentPage=cmsfn.page(content) /]
[#local pageChildren = cmsfn.children(currentPage, "mgnl:page")]
[#list pageChildren as page ]
{
"category": "${page.title}",
[#local pageContent = cmsfn.contentById(page)]
"headline": "${pageContent.headline!?json_string}",
"description": "${pageContent.description!?json_string}"
} [#if page?has_next],[/#if]
[/#list]
Now i get the category (the page title) for each entry. Thats fine. But headline and description are not filled.
I know, page is a node. page is the page and can access each page property (title, template).
I didn't find anything to get the content from a page via cmsfn. There are methods for contentById, contentByPath and also page() to get the page for a content.
But how i can get the content, from a page?
Update:
I made big step.
I get my pageContent from contentByPath, and use here the path of the page.
After this, i convert this to an JCR Node.
[#local pageContent = cmsfn.contentByPath(page.#path)]
[#local jcr = cmsfn.asJCRNode(pageContent)]
Now dumping shows my jcr.
Node (/my-website/faqs/kategorie1/question1)
footer = Node (/my-website/faqs/kategorie1/question1/footer)
mgnl:activationStatus = true (Boolean)
[...]
jcr:uuid = "a09d13da-3549-4b2a-8609-3b635e6f1c59" (String)
layers = Node (/my-website/faqs/kategorie1/question1/layers)
mgnl:activationStatus = true (Boolean)
[...]
jcr:uuid = "08b52c64-7327-4300-884c-047e42f560d0" (String)
overlays = Node (/my-website/faqs/kategorie1/question1/overlays)
mgnl:activationStatus = true (Boolean)
[...]
jcr:uuid = "9a78479b-0d25-4acf-9554-b9d626a7cc61" (String)
content = Node (/my-website/faqs/kategorie1/question1/content)
0 = Node (/my-website/faqs/kategorie1/question1/content/0)
description = "something" (String)
headline = "my example" (String)
mgnl:activationStatus = true (Boolean)
mgnl:created = Jul 24, 2019 11:20:40 AM UTC (Date)
What i really need, is here the content node, and the description and the headline.
But how to access this, and are there better methods to get this content?

You've already gotten the title of a page and any other property on the page node behaves just same as the title property. Hence, page.description will give you the description property of the given page node/object.
Let's also clarify what #contentById() method does. It is responsible to fetch a node by its identifier and returns a ContentMap e.g.
ContentMap (think as a Node object but mere Map) contentById(String identifierOfRequestedNode)
Update:
Via contentById method, you can directly access description and name, you do not need to convert it to the Node object.
E.g.
pageContent.description
pageContent.name
Hope that helps,
Cheers,

Related

2sxc Prefill datetime value in Manage Content Data

I created a Entity in Content-Types and Data and this entity have a field that is a datetime
When I click in the Plus button (+) I want to hide the field from user (this I got) and that default value be the current date (to be filled behind the scene)
Is there a way to achieve this ?
I read about prefill but I dont got how to do that with the default "Manage Content / Data"
I´m using 2sxc 10.24.0
Welcome to StackOverflow, #Alexandre ;)
The special buttons can only be done in the view. The internal manage-data doesn't provide options to customize. You can set default texts, but there is currently no mechanism to provide tokens, JS or something to get dynamic values as an initial value from the normal Admin-dialogs.
I got if I create a view and then use
#Edit.Toolbar(toolbar: new object[] { new { command = new { action = "new", contentType = "Articles", prefill = new { CreationDate = DateTime.Now } }}}
I believe that to do that in Manage Content / Data will be need to modify the "view" from the 2sxc

Keyword has incorrect values in custom meta

I have a category with keywords which in their tern have metadata schema. That schema consist of two fields and each of them is category. Very simple structure, but during publishing it resolves those metadata keyword fields into wrong tcm uris instead of title of the keyword, like the following:
2) Content of the deployer package
<tcmc:Topic rdf:about="tcm:10-11325-1024">
<rdfs:label>Analytics and optimization</rdfs:label>
<rdfs:comment>Analytics and optimization</rdfs:comment>
<tcmt:key>Analytics and optimization</tcmt:key>
<tcmt:isAbstract>false</tcmt:isAbstract>
<tcmt:isRoot>true</tcmt:isRoot>
<tcmt:metadata rdf:parseType="Literal">
<Metadata xmlns="uuid:a30b06d3-b6c5-4c2e-a53b-2b88771370ed">
<Divisions xlink:title="cma" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="tcm:0-17737-1024">cma</Divisions>
<InterestProfile xlink:title="CMAAnalytics" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="tcm:0-11175-1024">CMAAnalytics</InterestProfile>
</Metadata>
</tcmt:metadata>
</tcmc:Topic>
3) In code where I query Tridion it returns these uris:
TaxonomyFactory taxonomyFactory = new TaxonomyFactory();
TKeyword taxonomy = taxonomyFactory.GetTaxonomyKeywords(“tcm_of_the_category”);
if (taxonomy != null && taxonomy.KeywordChildren != null)
{
foreach (var item in taxonomy.KeywordChildren) //keyword metadata contains tcm uri with zero instead of title
{
Keyword keywordChildren = item as Keyword;
if (keywordChildren != null)
{
. . .
}
}
}
Does anyone have any ideas what might cause such an issue?
At a glance, my guess is that the internal template used to transform the categories is reading the metadata field data directly from the DB (or near enough in the BL layer) and not applying any blueprinting rules to it (likely for performance).
If you look at TCM Uris in content, when stored in the database, they all use 0 as their publication ID, and this ID is modified at "read" time.
Your call: You can call this a defect, ask Tridion to fix it, and it will degrade the performance of publishing a category, or you can deal with it in the delivery side - you know the publication Uri is 0, and you know you need to replace it with the current publication ID if you intend to use it for any purpose.
EDIT
So I went back and did some quick hacking. Indeed you can't load the keyword's content because, according to Tridion, the "Value" of field "Divisions" is the keyword URI. No way around that.
Quick way around this: load the keyword in question:
TaxonomyFactory tf = new TaxonomyFactory();
Keyword taxonomy = tf.GetTaxonomyKeywords("tcm:5-369-512");
if(taxonomy != null && taxonomy.KeywordChildren != null)
{
foreach (Keyword item in taxonomy.KeywordChildren)
{
NameValuePair key = (NameValuePair) item.KeywordMeta.NameValues["Field1"];
string correctUri = key.Value.ToString().Replace("tcm:0-", "tcm:5-");
Keyword theOtherKeyword = tf.GetTaxonomyKeyword(correctUri);
string title = theOtherKeyword.KeywordName;
}
}
Now... you probably want to be a bit smarter than me on that creative publication ID rewrite :)
You can see the field as a Component Link, you link to a specific Keyword item (object). Therefor you primarily get the URI, and I don't think that it resolves automatically to the Value property.
So the next step would be to obtain the Keyword object using the URI, and possibly construct the URI to include the right publication context.

Can I have flexible/catchall regions with Tridion XM/New UI/2012 UI

I am putting together a functional design for a site which will aims use the Tridion 2012 UI/XM to manage pages. There are 2 regions on the page, a main content area on the left and a side-bar on the right. Ideally users should be able to drag and drop content into and within these regions. In an ideal world I would like to define the regions along the lines of
Side Bar: any CP for which the CT has the text 'Right' in it.
Main: all other CPs
Looking at the documentation it seems that you need to explicitly use CT/Schema ID pairs to define regions. Is there any possibility to do this in any other way?
At the very least I would like to be able to define that the side bar allows a certain fixed set of CT/Schema ID pairs, but have the main region as a catchall bucket.. Is this possible?
It is also possible that the Side Bar is split into 2 regions, above and below an advertisement. Both regions should allow the same types of CP - as far as I understand this is not possible - is this correct? Are there any ideas for workarounds?
To configure regions that take all Content Types, You need to get Publication AppData and loop through the content types and build your json markup for enabling this.You could write C# TBB which includes on each page template and does this logic, you can define some metadata at CT level which determines which region it will go in and build the Region JSON markup.
Below is the snippet to get all Component types to add in one region. You could change the logic to get only right just by checking the template name.
// get the publication from the engine -- using TemplateBase Util..
Publication thisPub = GetPublication();
XmlElement seAppdata = thisPub.LoadApplicationData("SiteEdit").GetAs<XmlElement>();
XmlNamespaceManager seNsMgr = new XmlNamespaceManager(new NameTable());
seNsMgr.AddNamespace("se", "http://www.sdltridion.com/2011/SiteEdit");
seNsMgr.AddNamespace("xlink", "http://www.w3.org/1999/xlink");
XmlNodeList contentTypes = (XmlNodeList)seAppdata.SelectNodes("//se:ContentTypes/se:ContentType", seNsMgr);
List<String> contentTypeJson = new List<String>();
foreach (XmlNode contentType in contentTypes)
{
string templateId = contentType.SelectSingleNode("se:ComponentTemplate/#xlink:href", seNsMgr).Value;
string componentId = contentType.SelectSingleNode("se:Component/#xlink:href", seNsMgr).Value;
Component thisSchema = (Component)engine.GetObject(componentId);
string schemaId = thisSchema.Schema.Id;
// Add json formated string for Content Types
contentTypeJson.Add(string.Format("{{schema: \"{0}\", template: \"{1}\"}}", schemaId, templateId));
}
// Final Markup - JSON
String allRegionSeText = string.Format("<!-- Start Region: {{title: \"All Region\", allowedComponentTypes: [{0}], minOccurs: 1, maxOccurs: 5 }} -->", string.Join(",", contentTypeJson.ToArray()));
// Push to the package to use in DWT..
package.PushItem("ALL_REGION", package.CreateStringItem(ContentType.Text, allRegionSeText));
Hope this helps.
Have you tried creating a region without specifying CT/Schema pairs? I remember seeing in an early implementation that you could drop a content type anywhere because regions hadn't been configured properly (or perhaps at all).

How to link from an ASP.Net gridview column field to an .aspx page

I'm using an asp.net gridview to display a list of data from an mdb file. There are 5 columns displayed, with approximately 240 rows of data. Each row displays "first name", last name", "title", "genre", "issue", and "id".
Each "title" entry has corresponding .aspx page. There are approximately 180 actual .aspx pages that corresponds to the "title" entries in the grid.
An example of this relationship looks like: title = "Once upon a time in a long story"; and the aspx page might be /alongstory.aspx.
What I want to accomplish: Allow users to click the title field on the grid and open corresponding .aspx page.
What I've done so far: created a aspLabel on the "title" field - Text='<%#Eval("Title") %>'; and added C# code for label load event:
aspLabel l = sender as aspLabel;
l.ClientsideEvents.Click = String.Format("function(s,e) {{window.location = \"{0}"; }}, GetPageUrl(l));
And the GetPageUrl:
Private string GetPageUrl(aspLabel l)
{GridViewDataItemTemplateContainer c = l.NamingContainer as GridViewDataItemTemplateContainer:
var value = (string)DataBinder.Eval(c.DataItem, "Title");
string result;
switch (value) {
case "in the mirror":
result = "AnotherTitlePage.aspx";
break;
case "When your Eyes":
result = "AnotherTitlePage2.aspx";
break;
case "Her Delivery":
result = "ATitlePage1.aspx";
break;
case "You Never Know What You Might See":
result = "TitlePage3.aspx";
break;
default:
result = "TitlePageDoesNotHavesameNameAsDBEntry.aspx";
break;
}
return Page.ResolveUrl(result);
}
While this works, it requires all titles be hard coded into corresponding select statement along with the corrosponding url, which equates to 240 cases! Further, the only field which uniquely identifies each row is the "id" value, which in an integer - I've had a problem trying to set up a case select for int and return the proper url (casting error is the problem).
What I hope to accomplish:
Find the most efficient way to open the corrosponding url for the click on the "title" field of the grid view without hard coding both the field name from the grid column and the url into the case select.
So, given the information above, would a case select be the best approach for this requirement?
Any examples or suggestions of better approaches would be most appreciated!
Instead of making 180 actual .aspx pages, you must have to use concept of routing introduced in c# 4.0 and above.
here you can generate N number of pages dynamically and only one page will be work as template.
please refer below link for more details
URL Routing in asp.net as example www.jobdoor.in

Getting the values from a repeated Embedded Schema using TOM.NET API in an event handler in SDL Tridion 2011 SP1

I am working on the Event Handler for saving a component.
My objective is to perform some validations when the user creates and component based on a schema.
I have a schema with the name "Employee".
Employee has an embedded schema with the name "Experience" and it is multivalued.
Experience has 3 fields.
Role : Drop down with the values Manager, Lead.
Company: Text field
Years: Text field
When the user enters some data in these fields, I want to do some validations before save.
The high level design would look like this.
Load the instance of the Component
Navigate to embedded field "Experience"
For every "Experience". I need to get the value of the "Role", and check that appropriate value is entered in other two fields(By writing Component Save event)
For( all the repeated "Experience")
{
If (Role=="Manager")
check the values in the other two fields and do some validation
If (Role=="Lead")
check the values in the other two fields and do some validation
}
I am stuck at extracting the value and Names of subfields at the embeddded field.
I have tried:
Tridion.ContentManager.Session mySession = sourcecomp.Session;
Schema schema= sourcecomp.Schema;
if(schema.Title.Equals("Employee"))
{
var compFields = new ItemFields(sourcecomp.Content, sourcecomp.Schema);
var embeddefield = (EmbeddedSchemaField)compFields["Experience"];
var embeddedfields = (IList<EmbeddedSchemaField>)embeddefield.Values;
foreach(var a in embeddedfields)
{
if(a.Name.Equals("Role"))
{
string value=a.Value.ToString();
}
}
}
Actually I am stuck how to retrieve the values in the other fields at the same time.
Can any one explain how it can be done?
What you need to understand on a EmbeddedSchemaField class is that it represents both a schema and a field (as the name implies...)
I always find it helpful to look at the source XML of the component when writing code that targets its fields, you get a good visual representation of what your classes must do. If you look at a component XML like this:
<Content>
<Title>Some Title</Title>
<Body>
<ParagraphTitle>Title 1</ParagraphTitle>
<ParagraphContent>Some Content</ParagraphContent>
</Body>
<Body>
<ParagraphTitle>Title 2</ParagraphTitle>
<ParagraphContent>Some more Content</ParagraphContent>
</Body>
</Content>
Body is your embedded Schema field, which is multivalued, and contains 2 single-valued fields within it.
Addressing these fields in TOM.NET then:
// The Component
Component c = (Component)engine.GetObject(package.GetByName(Package.ComponentName));
// The collection of fields in this component
ItemFields content = new ItemFields(c.Content, c.Schema);
// The Title field:
TextField contentTitle = (TextField)content["Title"];
// contentTitle.Value = "Some Title"
// Get the Embedded Schema Field "Body"
EmbeddedSchemaField body = (EmbeddedSchemaField)content["Body"];
// body.Value is NOT a field, it's a collection of fields.
// Since this happens to be a multi-valued field, we'll use body.Values
foreach(ItemFields bodyFields in body.Values)
{
SingleLineTextField bodyParagraphTitle = (SingleLineTextField)bodyFields["ParagraphTitle"];
XhtmlField bodyParagraphContent = (XhtmlField) bodyFields["ParagraphContent"];
}
Hope this gets you started.

Resources