Hide Field From Local Block

There are times when you have a local block that is shared across multiple blocks or pages and you want to hide a specific field based on the content type. Here is a guide on how you can achieve this with a custom attribute.

Imagine that you have a block which used by other content types (no matter if they are other blocks or pages) but there is a field that you want to hide on a specific page because it won’t be needed but you want to avoid creating another block type. So this blog post will help you with that approach.

First, let’s create our block that will be referenced by other content types.

[ContentType(DisplayName = "Navigation Links",
	GUID = "b2b0da2a-dda4-4d8d-807b-d22c8771fe2c",
	GroupName = CmsGroupNames.Account, //Recommendation: create a constant class for Group Names
	AvailableInEditMode = false)]
public class NavigationLinksBlock : BlockData
{
	[Required]
	[Display(Name = "Title", Description = "Manage a title for the Navigation.",
		GroupName = CmsTabNames.Content, Order = 10)]
	public virtual string NavigationTitle { get; set; }

	[Display(Name = "Link", Description = "Manage the value for the Link.",
		GroupName = CmsTabNames.Content, Order = 20)]
	public virtual string LinkTitle { get; set; }

	[Display(Name = "Additional Link 1", Description = "Manage the value for the Additional link 1.",
		GroupName = CmsTabNames.Content, Order = 30)]
	public virtual string AdditionalLink1 { get; set; }

    [Display(Name = "Additional Link 2", Description = "Manage the value for the Additional link 2.",
		GroupName = CmsTabNames.Content, Order = 40)]
	public virtual string AdditionalLink2 { get; set; }
}

In this case, we will have a Navigation Links block and we want to have the Additional Link as visible/hidden based on the content type.

Then, let’s assume we have two blocks that will use this shared block.

[ContentType(DisplayName = "Product Navigation A",
	GUID = "95f57ff2-418d-41db-bc2c-78429eb41234",	
	GroupName = CmsGroupNames.Navigation,
	AvailableInEditMode = false)]
public class ProductNavigationABlock : BlockData
{
	[Required]
	[Display(Name = "Title", Description = "Manage a title.",
		GroupName = CmsTabNames.Content, Order = 10)]
	public virtual string Title { get; set; }
	
	[Display(Name = "Navigation Links", Description = "Manage the Navigation Links.",
		GroupName = CmsTabNames.Content, Order = 20)]
	public virtual NavigationLinksBlock NavigationLinks { get; set; }
}
[ContentType(DisplayName = "Product Navigation B",
	GUID = "3cb0da2a-dda4-4d8d-f07b-d22c8771fe2c",	
	GroupName = CmsGroupNames.Navigation,
	AvailableInEditMode = false)]
public class ProductNavigationBBlock : BlockData
{
	[Required]
	[Display(Name = "Title", Description = "Manage a title.",
		GroupName = CmsTabNames.Content, Order = 10)]
	public virtual string Title { get; set; }
	
	[Display(Name = "Navigation Links", Description = "Manage the Navigation Links.",
		GroupName = CmsTabNames.Content, Order = 20)]
	public virtual NavigationLinksBlock NavigationLinks { get; set; }
}

Now that we have our two blocks that are using the same NavigationLinksBlock, let’s hide the AdditionalLink1 from the NavigationA and hide the AdditionalLink2 from the NavigationB.
In order to execute that requirement, we have to create a custom attribute with metadata so we can modify the editing experience of a property. You can read more about it here

public class HideFieldAttribute : Attribute, IMetadataAware
{
	private readonly string[] _fieldNames;

	public HideFieldAttribute(string[] fieldNames)
	{
		_fieldNames = fieldNames;
	}

	public void OnMetadataCreated(ModelMetadata metadata)
	{
		var contentMetadata = metadata as ContentDataMetadata;

		if (contentMetadata == null)
		{
			return;
		}

		foreach (var property in contentMetadata.Properties)
		{
			if (_fieldNames.Contains(property.PropertyName))
			{
				property.ShowForEdit = false;
			}
		}
	}
}

This attribute will loop through all the properties, grabbed from the metadata, and will look at the fieldnames list defined by the developer, if the field name is found on the property collection, it will be hidden and won’t be visible to the editor.
property.ShowForEdit = false; this flag is read by the UI and will not render the field on the editing view.

Finally, we have to add a new line to our ProductNavigation blocks to specify which field we want to hide.

Then, let’s assume we have two blocks that will use this shared block.

public class ProductNavigationABlock : BlockData
{
	....
    [HideField(new[] { nameof(NavigationLinksBlock.AdditionalLink1) })]	
	public virtual NavigationLinksBlock NavigationLinks { get; set; }
}
public class ProductNavigationBBlock : BlockData
{
	....
    [HideField(new[] { nameof(NavigationLinksBlock.AdditionalLink2) })]	
	public virtual NavigationLinksBlock NavigationLinks { get; set; }
}

And this is the final result where you can see that AdditionalLink1 is hidden in Product Navigation A and the AdditionalLink2 is not visible in Product Navigation B:

There could be other alternatives on how to implement this approach but this is a good solution and hope it’s useful for your projects.

2 thoughts on “Hide Field From Local Block

  1. I’ve tried other similar solutions recently for hiding properties. They all failed in two particular use cases. When creating a block from a content area’s “create new block” link, the properties were not hidden. And when using the “Quick Edit” feature, properties were not hidden.

    Does your attempt work in those scenarios?

    Like

Leave a Reply to Brian S Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: