Discussions

Ask a Question
Back to All

Related articles

Hi there,
Is there a way to have, in a OpenContent module using the Articles template, a detail page of an article including a list of related articles? The relation should be formed through a corresponding AdditionalData field, like Tags.

This is a functionality I have been missing for a while now.
I know I can have the admin do this manually, via a field in the article edit, but I am looking for automation...

Maybe there are workarounds?

Keston

Admin

The easiest way is to use a separate details page and place a related module on that page.

Thanks Timo! Can you elaborate a bit? 'A separate details page'... a page (tab) that you only use for the details.hbs template? 'Place a related module'... what do you mean exactly?

Admin(edited)

List page
Detail page, here you place the current module.
Now on the list page you place the module with existing data and point the details page to the "detail page"
As that will only show the details, you can place anything you want on that page.
Including a razor template that uses the id of the article to get related articles.
Another solution is to use a custom webapi call to get the related articles.
In that case a separate page is not needed.

// Get the related items

var moduleId = {{@root.Context.ModuleId}};
var sf = $.ServicesFramework(moduleId);
var api = new $.openContentRestApiV2(sf);

var filter = {
    rules: [{ field: "Tags", operator: "EQUAL", value: itemTags.replace(',',' ') }]
}
var relatedtemplate = Handlebars.compile($('#related-template').html());



api.getAll('Items', 0, 5, filter, null, function (data) {
    // success
    
	// Mark the current item (to exclude)
	for (var i=0 ; i < data.Items.length ; i++)
	{
		if(itemId == data.Items[i].Context.Id){
			data.Items[i].Context.Current = true;
		}
	}
	
    $('#related-items').html(relatedtemplate(data));
}, function () {
    // fail

});
(edited)

Wow, that would be great!!

Few questions (I have no experience using OC this way).

Where do I place this custom webapi script? in details.hbs? Just between script tags?

And where is sf ( in openContentRestApiV2(sf) ) defined?

And what html is used to build the related items?

Sorry for my confusion...

Admin

Yes inside the template in script tags (it's JS) and you need an element with an id="related-template"

I tried that but nothing happens. In the browser console an error that sf is not defined.

Timo, I followed your instructions but I see no html being build. I get an error that sf is not defined. Am I doing something wrong? I feel that I’m missing something πŸ˜”

sf stand for service framework
to create one :
var sf = $.ServicesFramework({{Context.ModuleId}});

thanks Sacha. I guess I also need to define somewhere the template to form the related items...

Admin

ok right I forgot a few lines higher in the document:

var moduleId = {{@root.Context.ModuleId}};
var sf = $.ServicesFramework(moduleId);

I'll add an example to https://github.com/40fingers/OpenContent-Demo-Templates
But that can take a while :-)

Thanks, yes I worked that out, but I was referring to the forming of the related items... In your example you use a 'relatedtemplate' and a filter. I don't see that in your example.

Admin(edited)

Ah, right, I have a file related.hbs which is a client side Handlebars template
Content:

<script id="related-template" type="text/x-handlebars-template">
	{{#each Items}}
        ..............
	{{/each}}
</script>

And is the manifest:

  "detail": {
    "template": "detail.hbs",
	"partialTemplates": {
      "related": {
        "template": "related.hbs",
        "clientside": true
      }
    }
   }
(edited)

So there are 3 elements that need changes:

"detail": { "template": "detail.hbs", "partialTemplates": { "related": { "template": "related.hbs", "clientside": true } } }
<script id="related-template" type="text/x-handlebars-template"> {{#each Items}} ... {{/each}} </script>
<!-- Added to top of details.hbs (or else it gives errors) --> {{registerscript "/DesktopModules/OpenContent/js/lib/handlebars/handlebars.min.js"}} {{registerscript "/DesktopModules/OpenContent/js/oc.jquery.js"}} <div id="related-items"></div> <script> $(document).ready(function () { var moduleId = {{@root.Context.ModuleId}}; var itemId = {{@root.Context.Id}}; // was missing in your example but I think this is needed var itemTags = "{{#each Tags}}{{Tag}}{{#unless @last}},{{/unless}}{{/each}}"; // was missing in your example but I think this is needed var sf = $.ServicesFramework(moduleId); var api = new $.openContentRestApiV2(sf); var filter = { rules: [{ field: "Tags", operator: "EQUAL", value: itemTags.replace(',',' ') }] } var relatedtemplate = Handlebars.compile($('#related-template').html()); api.getAll('Items', 0, 5, filter, null, function (data) { for (var i=0 ; i < data.Items.length ; i++) { if(itemId == data.Items[i].Context.Id){ data.Items[i].Context.Current = true; } } $('#related-items').html(relatedtemplate(data)); }, function () { // fail }); }); </script>

But still... no results... what am I doing wrong here?

Admin

Ok this is not working, I'll try to create working example somewhere next week. (not guaranteed, quite busy)

Sorry Timo, I'm really trying myself aswell... Thanks for taking the time!

Admin

np, one typo and it does not work..

(edited)

Tnx a million Timo. I see that you defined the field Tags as a text field. What needs to change in this script to call the Tags? I tried:

{{#if Tags}} $(document).ready(function () { var moduleId = {{@root.Context.ModuleId}}; var itemId = "{{@root.Context.Id}}"; var itemTags = "{{#each Tags}}{{Tag}}{{#unless @last}},{{/unless}}{{/each}}"; var sf = $.ServicesFramework(moduleId); // Get the related items var api = new $.openContentRestApiV2(sf); var filter = { rules: [{ field: "Tags", operator: "EQUAL", value: itemTags.replace(',',' ') }] } var relatedtemplate = Handlebars.compile($('#related-template').html()); api.getAll('Items', 0, 5, filter, null, function (data) { for (var i=0 ; i < data.Items.length ; i++) { if(itemId == data.Items[i].Context.Id){ data.Items[i].Context.Current = true; } } $('#related-items').html(relatedtemplate(data)); }, function () { // fail }); }); {{/if}}

but that probably doesn't work because it's not a text field??

(edited)

FYI: if I comment out the rules of the filter:

//rules: [{ field: "Tags", operator: "EQUAL", value: itemTags.replace(',',' ') }]

everything works and the last 5 articles are shown...
So the only thing I'm strugling with is to use the Tags field of the article, which is an array field.

ο»Ώ