Portal Engine Questions on portal engine and web parts.
Version 7.x > Portal Engine > Best way of implementing complex conditions in transformations View modes: 
User avatar
Certified Developer 10
Certified Developer 10
varinder-kudosweb - 9/29/2013 5:16:21 AM
   
Best way of implementing complex conditions in transformations
Possible duplicate of this

I see its quiet straight forward to write conditional text in a transformation like below
<%# IfCompare(1, 2, "The values are different", "The values are equal") %>

But it seems to be quiet a bit of a pain in the neck to do some decent switch-a-roo at the markup level.

Heres how im approaching it ( might aswell help explain what im trying to explain )

well, a document type with a bunch of fields

- IsNewsItem [ checkbox - bool ]
- NewsItemTitle [ string ]
- NewsItemText [ string ]
- NewsItemImageUrl [ string ]
<!-- if current item is a newsItem -->
<asp:Placeholder runat="server" visible='<%# "True".Equals( Eval( "IsNewsItem" ).ToString() ) %>' >

<div class="news-item">
<h1><a href="<%# GetDocumentUrl() %>">Eval( "NewsItemTitle" )</a></h1>
<div class="news-item-body">

<!-- if image exsists - then render a two column layout -->
<asp:Placeholder runat="server" visible='<%# !String.IsNullOrEmpty( Eval( "NewsItemImageUrl" ).ToString() ) %>' >

<div class="image-and-text">
<a class="image" href="<%# GetDocumentUrl() %>">
<img src="<%# Eval( "NewsItemImageUrl" ) %>" />
</a>

<!-- another troll-logic of checking if the "NewsItemText" field contains "<p>" tags ( hope theres a better way of doing it ) -->
<asp:Placeholder runat="server" visible='<%# Eval("NewsItemText").ToString().Trim().StartsWith("<") %>'>
<%# Eval( "NewsItemText" ) %>
</asp:Placeholder>

<asp:Placeholder runat="server" visible='<%# !Eval("NewsItemText").ToString().Trim().StartsWith("<") %>'>
<p><%# Eval( "NewsItemText" ) %></p>
</asp:Placeholder>
</div>

</asp:Placeholder>

<!-- if image doesnt exsists - then simply show body copy -->
<asp:Placeholder runat="server" visible='<%# Eval("NewsItemText").ToString().Trim().StartsWith("<") %>'>
<%# Eval( "NewsItemText" ) %>
</asp:Placeholder>

<asp:Placeholder runat="server" visible='<%# !Eval("NewsItemText").ToString().Trim().StartsWith("<") %>'>
<p><%# Eval( "NewsItemText" ) %></p>
</asp:Placeholder>

</div>
</div>

</asp:Placeholder>

<!-- if current item is not a newsItem -->

... imagine a completly different markup with whole bunch of asp:Placeholders sprinkled as above

While the above approach works and is certianly better than wasting half of my happy life trying to escape quotes in "IfCompare" method.

But, It feels hacky.

For example, if now the next requirement was to not to render any markup at all if any of the fields ( lets say "NewsItemTitle" or "NewsItemText" ) are blank.

In the above approach, i'd have add another placeholder with fancy conditions ( Ugly! )
<asp:Placeholder runat="server" visible='<%# !String.IsNullOrEmpty( Eval( "NewsItemTitle" ).ToString() ) && !String.IsNullOrEmpty( Eval( "NewsItemText" ).ToString() ) %>' >

<!-- if current item is a newsItem -->
<asp:Placeholder runat="server" visible='<%# "True".Equals( Eval( "IsNewsItem" ).ToString() ) %>' >

... same markup as above

</asp:Placeholder>

<!-- if current item is not a newsItem -->

... some other markup no one really cares about

</asp:Placeholder>

Well above is still a simplified example,

Heres a scenario where above approach went from fine-to-f*kd-up
User image

So the Ultimate Question: How to handle complex conditons in kentico transformations?

I wonder if it is possible to use If/Else thingies?
<% if ( Eval("Field") == SomeValue ) { %>
.. stuff ..
<% } elseIf { %>
.. some other stuff ..
%>

Offtopic: Although kentico forums is quiet a great place to get help and I love posting here but the process of posting a thread is quiet frustrating ( no tab spacing and syntax highlighting for code etc ). Took me half an hour to post it - maybe im spoilt by Zen Mode.

Anyway folks, thanks in advance
Varinder

User avatar
Kentico MVP
Kentico MVP
Brenden Kehren - 9/30/2013 7:47:53 AM
   
RE:Best way of implementing complex conditions in transformations
varinder-kudosweb wrote: So the Ultimate Question: How to handle complex conditons in kentico transformations?
Create your own custom method to handle this. OR create an event within you transformation that will allow you to do those checks for each item as they are loaded.

User avatar
Kentico Support
Kentico Support
kentico_janh - 10/9/2013 2:00:39 AM
   
RE:Best way of implementing complex conditions in transformations
Hello,

There are a few options how to simplify your complex transformation code:

1) As it was mentioned, you can add your own transformation functions to handle complex statements:

Adding custom functions to transformations

2) In case you can take advantage of the portal functionality, you can switch the transformation type from ASCX to Text/XML where you can use K# for complex conditions and statements and you can split your transformation to more smaller pieces and apply them using the ApplyTransformation method according to results of your if statements.

Best regards,
Jan Hermann

User avatar
Certified Developer 10
Certified Developer 10
varinder-kudosweb - 10/11/2013 5:50:20 PM
   
RE:Best way of implementing complex conditions in transformations
Thanks to the response guys,

ApplyTransformation method does seem to be shenanigan ive been waiting for but lack of docmentation got me frustrated and for the life of me i could not figure out how to fit it into my problem. Further to that, as you say - it doesnt seem to support ASCX transformations

Writing custom functions will surely reduce the complexity but im not sure if it helps remove un-necessary asp:Placeholders

For example, a sample transformation without custom functions:


<asp:Placeholder runat="server" visible='<%# !String.IsNullOrEmpty(Eval("SomeField").ToString()) && !String.IsNullOrEmpty(Eval("SomeField2").ToString()) && ... %>' >

... some transforation code ...

</asp:Placeholder>



Which will change to below if i use a custom function



<asp:Placeholder runat="server" visible='<%# CustomCode.IfNotEmpty( ["SomeField", "SomeField2", "SomeField3", ...] ) %>' >

... some transforation code ...

</asp:Placeholder>




Yes, alot cleaner but, again, asp:Placeholders doesnt seem to be the right thing for conditional structure.


Heres how ive approaced it recently

- Passed all transformations to local directory

- code in ParentTransformation.ascx ( this transformation gets linked from some webpart - repeater etc )


<%@ Register TagPrefix="cms" TagName="Template" Src="ChildTransformation.ascx" %>


... some html structure before ...

<cms:Template id="TemplateControl" runat="server" visible='... some condition similar to asp:Placeholders above ...'></cms:Template>

... some html structure after ...



- code in ChildTransformation.ascx



<p class="item-body"><%# Eval("Title") %></p>




Above approach is alot cleaner and transformation code can be reused which solves one of the problems i mentioned earlier on transformations here


Taking it a step further

Heres how im approaching it if there are more than 1 child transformations that needs to be controled by the same condition



<%@ Register TagPrefix="cms" TagName="ChildTransformation" Src="ChildTransformation.ascx" %>
<%@ Register TagPrefix="cms" TagName="ChildTransformationA" Src="ChildTransformation2.ascx" %>

... some html structure before ...

<cms:ChildTransformation id="TemplateControl" runat="server" visible='false'></cms:ChildTransformation>

... some html structure after ...

<cms:ChildTransformationA id="TemplateControl2" runat="server" visible='false'></cms:ChildTransformationA>


<script runat="server">
protected override void OnDataBinding(EventArgs e)
{
base.OnDataBinding(e);

string Title = DataBinder.Eval(this.DataItem, "Title" ).ToString();

if ( Title.Contains("A") )
{

ChildTransformation.Visible = false;
ChildTransformationA.Visible = false;

}
}
</script>





Next Question:

While the above approach is butt-loads better than what ive been doing before,
i wonder if showing-hiding cms:ChildTransformation on data binding can be more dried up?

Im struggling to figure out a way to dynamicaly find out all the controls whose id starts with, lets say "ChildTransformation"

- heres an approach that does the similar thing on dataItems but i cant seem to get this work on controls.
Simply put - is there a way to access all the controls on dataBind event ?



<script runat="server">
protected override void OnDataBinding(EventArgs e)
{
base.OnDataBinding(e);
for (int i = 0; i <= 9; i++)
{
FieldValue = DataBinder.Eval(this.DataItem, "FieldName" + i.ToString()).ToString();
}
}
</script>




appreciate your help gus.

Cheers
Varinder

User avatar
Certified Developer 11
Certified Developer 11
kentico-jx2tech - 10/11/2013 9:02:32 PM
   
RE:Best way of implementing complex conditions in transformations
If you can use Text/XML transformations, you can try something like this...
{% if (IsNewsItem) { ResolveMacros("\r\n  <div class=\"news-item\">\r\n    <h1><a href=\"{% NodeAliasPath %\}\">{%NewsItemTitle%\}</a></h1>\r\n    <div class=\"news-item-body\">\r\n    {% if (NewsItemImageUrl.ToString().Length > 0) { %}

User avatar
Certified Developer 10
Certified Developer 10
varinder-kudosweb - 10/11/2013 10:04:12 PM
   
RE:Best way of implementing complex conditions in transformations
Hi Man,

Thats exactly what i was envisioning. A solution without hacks like a boss! -You're awesome!

However, my approach for handling complex conditions has evolved a bit.

The idea is to abstract transfomations into smaller chuncks which can be resused:

For example in a pesudo-code below:

File: SomeBigTransformation.ascx


<%@ Register TagPrefix="cms" TagName="NewsLayout" Src="NewsLayout.ascx" %>

<%@ Register TagPrefix="cms" TagName="BasicLayout" Src="BlogLayout.ascx" %>

<div class="page">

.. some markup ..
<cms:NewsLayout runat="server" visible='.. some condition ..'></cms:NewsLayout>

.. some markup ..
<cms:BasicLayout runat="server" visible='.. some condition ..'></cms:BasicLayout>

</div>




The biggest benifit in above approach is that Newslayout is abstracted away in NewsLayout.ascx file which can be used anywhere else independently or again in some other transformation.

Which means changing markup in NewsLayout.ascx will reflect in SomeBigTransformation.ascx or any other transformation where its being referenced which is super cool.

And above all it makes the transformation code look alot cleaner as it abstracts away alot of markup leaving behind only a condition and reference to the file that will be used if that condition is matched. Big win.

Anyway, thanks for the help man.

Cheers,
Varinder

User avatar
Certified Developer 11
Certified Developer 11
kentico-jx2tech - 10/11/2013 10:34:59 PM
   
RE:Best way of implementing complex conditions in transformations
That is a good approach. As Jan mentioned the ApplyTransformation above, here is a similar way to do the SomeBigTransformation using a Text/XML transformation.
<div class="page">

{% if (true) {
return CurrentDocument.Children.ClassNames("CMS.NewsItem").WithAllData.ApplyTransformation("cms.newsitem.newitemlist");
} %}

</div>

User avatar
Certified Developer 10
Certified Developer 10
varinder-kudosweb - 10/11/2013 11:05:09 PM
   
RE:Best way of implementing complex conditions in transformations
Hello again,

Well thats awesome. I need to try it.

Just before i dig into it, a few questions, sorry:

- "CurrentDocument", is this the current item a repeater is on or the page where the repeater is placed?

- If "CurrentDocument" refers to the the page ( which makes more sense ) then ..Children.ClassNames("CMS.NewsItem").WithAllData ... is actually fetching news items placed right under the page where the repeater is added? and moreover, correct me if im wrong, because this is being called from within a transformation of that repeater - does it mean that when the condition is matched - we're pulling all the newsItem documents all over again in order to be able to render a different markup?

User avatar
Certified Developer 11
Certified Developer 11
kentico-jx2tech - 10/12/2013 7:05:45 AM
   
RE:Best way of implementing complex conditions in transformations
In the case above, I placed the macro in a Static text web part on the page. the CurrentDocument.Children will act as the "repeater" displaying a list of the NewsItems under the CurrentDocument.

User avatar
Kentico Support
Kentico Support
kentico_janh - 10/17/2013 6:09:55 AM
   
RE:Best way of implementing complex conditions in transformations
Hello,

Exactly, the CurrentDocument is the document you currently on (the one with a repeater) so the CurrentDocument.Children are child documents of your that document (you can also use the Where method like CurrentDocument.Children.Where("your condition")). If you want to get children of an item in the transformation you need to use different entry -> Documents[NodeAliasPath].Children,

Best regards,
Jan Hermann