Simon Miller Team : Web Development Tags : Web Development Umbraco

Unique value validation in Umbraco back office

Simon Miller Team : Web Development Tags : Web Development Umbraco

It seemed like a simple proposition – add a unique constraint to a single property in an Umbraco doctype.

I had the basic requirement to ensure that a Product ID field on a Product doctype could not be the same as a Product ID on another product. In a traditional .NET website with SQL back end, this is accomplished within minutes and without thinking. It seems, however, that the Umbraco core team have not thought of this basic requirement before. I would envisage that a checkbox against a property on a doctype “Enforce Unique Constraint” (alongside the “Mandatory” checkbox) would cover 95% of developer’s requirements – throw an error to the UI when attempting to save a node. Alas…

What I tried

My first approach was to go down the path of hooking into the Events system as I have done before. This seemed to be perfect, but there appears to be either bugs or unfinished functionality involving publish cancelations, or inconsistencies with the bubble message box in the UI. After much investigation following many leads and forum questions with no answers, it seems that there is no way to prevent the publish event cancellation from displaying a generic message to the user: “The publish event was cancelled by a 3rd party”. This is not user friendly and in my opinion, not good enough for providing to a client.

There are events in place to supposedly provide a custom message in the bubble, but making them work in Umbraco 6 is another matter.

What I did

In the end, I went for a different approach entirely. While this method will not prevent a publish call if the validation fails, it does alert the user after save or publish. The message also becomes a permanent fixture on the page until the error is taken care of. In many ways this approach could be superior to handling this in events, as there could potentially be situations where you only want the information and not be prevented in saving; plus I have full control over the messaging and can include a link to found duplicates.

Starting with the custom user control approach outlined on the Wiliam blog previously, I simply bolted on a uQuery lookup that searches the Internal index for all “Product” doctypes and checks for duplication in the “productID” property. As uQuery runs off Examine, this method is very fast. The method will compare the current “productID” value with all others and if any are found, render an error label next to the field including a link to the duplicate product. You can use this to compare two published documents, or a draft against a published document, but it will not compare two draft documents.

Front End:

 <asp:TextBox ID="txtProductID" runat="server" />  
 <asp:Label ID="lblError" ForeColor="Red" runat="server" />  

Back End:

   public partial class uniqueProductId : System.Web.UI.UserControl, IUsercontrolDataEditor  
   {  
     private string UmbracoValue;  
     protected void Page_Load(object sender, EventArgs e)  
     {  
       int id = int.Parse(Request.QueryString["id"].ToString());  
       if (Page.IsPostBack)  
       {  
         UmbracoValue = txtProductID.Text;  
       }  
       else  
       {  
         txtProductID.Text = UmbracoValue;  
       }  
       var existing = uQuery.GetNodesByType("Product").Where(x => x.GetProperty("productID").Value == UmbracoValue && x.Id != id).FirstOrDefault();  
       lblError.Text = existing != null ?   
         string.Format(@"The entered Product ID is a duplicate with product <a href='/umbraco/editContent.aspx?id={0}'>{1}</a>", existing.Id, existing.Name) :   
         string.Empty;  
     }  
     public object value  
     {  
       get  
       {  
         return UmbracoValue;  
       }  
       set  
       {  
         UmbracoValue = value.ToString();  
       }  
     }  
   }  

UI: