Search code examples
c#htmlektron

How to hide elements when a smartform field is null


I have an alert bar that gets its text from a smartform. I'm trying to set this up so when the smartform field "Alert" is null then the alert bar will be hidden. Here's my Code:

<div runat="server" ID="alertBox"  class="alert alert-danger">
    <a href="#" class="close" data-dismiss="alert" aria-label="close">×</a>
       <center>
           <CMS:ContentBlock ID="alert" runat="server" Visible="true" DisplayXslt="/xmlfiles/Alert.xslt" DefaultContentID="2147499035" CssClass="text" />
    </center>
</div>

Here's my Code Behind for this so far:

   XmlDocument al = new XmlDocument();
    if (al.SelectSingleNode("/root/Alert") != null)
    {
        alertBox.Visible = false;
    }
    else
    {
        alertBox.Visible = true;
    }

Solution

  • Let's start out making sure your XmlDocument is referencing the smartform xml from your content block control.

    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.LoadXml(alert.EkItem.Html);
    

    With that out of the way, here's how I would test to verify that (a) the node exists and (b) the node contains text.

    string alertContent;
    
    // If dealing with a plain-text field...
    var txtAlertNode = xmlDoc.SelectSingleNode("/root/txtAlert");
    alertContent = txtAlertNode?.InnerText;
    if (string.IsNullOrWhiteSpace(alertContent))
    {
        Console.WriteLine("No txtAlert content.");
        // alertBox.Visible = false;
    }
    else
    {
        Console.WriteLine("ALERT: " + alertContent);
        // alertBox.Visible = true;
    }
    
    // If dealing with a rich-text field...
    var rtfAlertNode = xmlDoc.SelectSingleNode("/root/rtfAlert");
    if (string.IsNullOrWhiteSpace(rtfAlertNode?.InnerText))
    {
        Console.WriteLine("No rtfAlert content.");
        // alertBox.Visible = false;
    }
    else
    {
        alertContent = rtfAlertNode.InnerXml;
        Console.WriteLine("ALERT: " + alertContent);
        // alertBox.Visible = true;
    }
    

    But since you have the content block control rendering the actual alert content, you could get away with something like this.

    var alertNode = xmlDoc.SelectSingleNode("/root/Alert");
    if (string.IsNullOrWhiteSpace(alertNode?.InnerText))
    {
        alertBox.Visible = false;
    }
    else
    {
        alertBox.Visible = true;
    }
    

    In Ektron SmartForms, there is the option of making a field optional, so it's possible that the /root/Alert node will be null. But it's also possible that the node will exist in the xml and simple not have any content. If it is configured as a rich-text field, then it can be difficult to completely clear out the field's HTML - often you end up with xml that looks like the following:

    <root>
        <Alert>
            <p></p>
        </Alert>
    </root>
    

    That's why I'm testing the InnerText property of the node. I'm using the Null-Conditional Operator ?. to account for the fact that the node itself might be null. If your Ektron site is not using the newer C# language features (I know, null-conditionals have been around for a few years now.), then you'd have to check for null separately.

    var alertNode = xmlDoc.SelectSingleNode("/root/Alert");
    if (alertNode != null && string.IsNullOrWhiteSpace(alertNode.InnerText))
    {
        alertBox.Visible = false;
    }
    else
    {
        alertBox.Visible = true;
    }
    

    I'd like to suggest an alternative, if I may. I see from your code that you are already using an XSLT to display the content of the alert. You could move the markup of the alertBox div into your XSLT and perform the "null-or-empty" test in there. Then you wouldn't need any code-behind for this particular feature.

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
    >
      <xsl:output method="html" indent="yes"/>
    
      <xsl:template match="/">
    
        <xsl:call-template name="alertBox">
          <xsl:with-param name="content" select="root/txtAlert/text()"/>
        </xsl:call-template>
    
        <xsl:call-template name="alertBox">
          <xsl:with-param name="content" select="root/rtfAlert/node()"/>
        </xsl:call-template>
    
      </xsl:template>
    
      <xsl:template name="alertBox">
        <xsl:param name="content"/>
        <xsl:if test="$content and (string-length(translate(normalize-space($content/text()), ' ', '')) &gt; 0 or string-length(translate(normalize-space($content), ' ', '')) &gt; 0)">
          <div runat="server" ID="alertBox"  class="alert alert-danger">
            <a href="#" class="close" data-dismiss="alert" aria-label="close">×</a>
            <center>
              <xsl:copy-of select="$content"/>
            </center>
          </div>
        </xsl:if>
      </xsl:template>
    </xsl:stylesheet>
    

    Note that the alertBox template in this XSLT will work for both plain-text and rich-text fields. It is using copy-of to display whatever is passed in, so when calling the template, care needs to be taken to pass in either the text() (plain-text) or node() (html/rich-text) of the element according to its type.