Convert RD (Rijksdriehoek) coordinates to Google Maps coordinates


, , , , , ,

In the Netherlands, there are a few databases that save geo-coordinates according to the “Rijksdriehoeks”-system (“Rijksdriehoekscoördinaten” or “RD-coördinaten”). Examples of these are the Dutch land register (Kadaster), but also Carerix (Recruitment Software) likes to save RD-coordinates for locations of job openings and employees.

However, Google Maps uses a different system, namely the WGS system (World Geodetic System 1984). So in order to try to show data from, say, Carerix on a map, we need to convert it.

google maps netherlands rd-coordinates

Continue reading

HTML5 Video: Track Google Analytics Events with Google Tag Manager


, ,

You have some videos on your website, and that’s great. But now you want to know how they perform, and how they are used. Which videos are the most watched? Are the videos viewed to the end? And how do they contribute to reaching the conversion goals of my site?

So we have a video control, and we want that to be flexible. We want to be able to keep measuring the videos, whether the site uses Google Tag Manager (GTM) or Google Universal Analytics. So we have a HTML5 video, that fires three events:

  • Play
  • Pause
  • Ended

These are the really insightful metrics. You could choose to also measure video progress (like David Vallejo does), but that does not really contribute to insights on how the video perform with regard to the goals of your site.

So we start with an HTML5 video. We give that video a “data attribute” that contains the title of the video, and the three events: Play, Pause, Ended. Each event has the same handler, and that handler is responsible for sending the event to Google Tag Manager or directly to Google Analytics.

<video controls data-title="The Video Title" onpause="sendEvent('Pause', this)" onplay="sendEvent('Play', this)" onended="sendEvent('Ended', this)">
	<source src="somevideo.mp4" type="video/mp4">

The handler sendEvent first checks if the dataLayer is present. If so, then we assume that Google Tag Manager is used on the site, and we send the event to the dataLayer. If there is no dataLayer, then Google Analytics must be present. It is the responsibility of the website, not of the video control, to either implement GTM or GA. You can see here that the contents of the “data-title” is used as the eventLabel in Google Analytics.

function sendEvent(action, element)
	var videoTitle = $(element).data('title');

	if (dataLayer && videoTitle) {
			'event': 'video',
			'eventCategory': 'Video',
			'eventAction': action,
			'eventLabel': videoTitle
	else if (ga && videoTitle)
		ga('send', 'event', 'Video', action, videoTitle);

Now if you use Google Analytics directly, you’re done. But if you use Google Tag Manager, then you have to make sure that the events received in GTM are passed to GA. So we make a Google Analytics tag of the tracktype “Event”:


This event uses three values from the dataLayer. We pass them in the function “sendEvent”. So we need three variables in GTM: eventCategory, eventAction and eventLabel. Add all these three to GTM like this:


The keen observer would also have noticed that the tag also needs a trigger in order to be fired. For that we make a new Trigger, and add it to the GA Tag. The Trigger listens to the dataLayer, and fires when an event comes in with event:video (as in the function “sendEvent”):


So now we have al we need:

  • A video control that passes events to GTM
  • A tag in GTM that passes events through to Google Analytics
  • Three variables in GTM that are used to read events from the dataLayer
  • A trigger in GTM that makes sure the new tag is fired

Happy coding!

DevExpress XPO: Foreign Keys are not removed when inheritance is removed


, , ,

DexExpress XPO Code First makes sure you spend a minimum amount of time in the Database, because you can manage the structure of your data solely in code. This is one of the stronger points of XPO compared to other Object-Relational Mapping frameworks.

However, there are some cases in which changes in code are not persisted in the database. This is unfortunate, because it weakens the Code First approach. The case of this article is: if you remove the inheritance of one object to the other in code, the Foreign Key relation in the database is not removed.

Database XPO foreign keys

Continue reading

DevExpress: Can not skip records without ORDER BY clause.


, , , , ,

When using the DevExpress.XPO.XPView to retrieve data, you could encounter an exception when trying to skip items with the “SkipReturnedRecords” property. (This property comes in handy when paging data, for example.)

The exception is an System.InvalidOperationException, and it message says: “Can not skip records without ORDER BY clause.”. The message is pretty clear, because you cannot skip records without first specifying in which way the list should be returned. This is explained pretty well for the XPQuery object.

However, for the XPView this works a bit differenty. Because setting the “Sorting” property of the XPView will not help here. The Sorting property is used to order the records after they have been fetched (so also after the SkipReturnedRecords has been evaluated).

The solution is to set the “Sorting” property on one of ViewProperty objects that have been added to the “Properties” of the XPView. This property will ensure that the query includes an ORDER BY clause when trying to skip records.

For example:

XPView xpView = new XPView();
xpView.Properties.Add(new ViewProperty("ID", SortDirection.Ascending, "ID", false, true));
xpView.SkipReturnedRecords = 5;

By the way, the company that I work at is looking for new ASP.NET developers. Especially DevExpress developers! So check the site or call me at: + 31 (0)30 677 32 01.

Sitecore DMS as Gamification Engine


, , , , , , ,

The Sitecore DMS (Digital Marketing System) is an outstanding tool for marketing automation, personalization, content targeting, and much more. However, the DMS could also be rebuilt to be used as a very powerful tool for Gamification.

Sitecore DMS tree

Continue reading

The Big Data (R)evolution


, , ,

Is Big Data the biggest information revolution since the invention of the Printing Press? The writers of The Big Data Revolution like to think so.

The available amount of data has grown exponentially, partially because of data colossi like Google and Amazon, but also because of small innovative companies that are focussed on collecing and analyzing Big Data. But will data be the main resource of our future economy, and change the way we work and live forever? There is a lot to say against this proposition, but when the hype is over the hill, Big Data will probably be a factor we can’t ignore.

Continue reading

Sitecore Webforms for Marketers HTML5 extensions: textbox with dropdown


, , , , , ,

As already mentioned in a previous article, the otherwise very decent Webforms for Marketers module of Sitecore is in need of an update. The release of HTML5 has had an especially great impact on how we build forms on the web. This is the reason why I have made some HTML5 extensions to the WFFM module.

In this article I will show how to add a textbox with an expandable dropdown list underneath it. It is still a textbox, so the user is able to enter free text. But at the same time it has a list of suggestions that expands when the users focusses on the form or begins typing.


Continue reading

Truncate Rich Text Fields in Sitecore


, , , ,

The Rich Text field type in Sitecore allows the user to create and store HTML-formatted content. Most of the time you want to display this content on the website as is, but sometimes you want to truncate it (for example in some kind of overview).

In that case you have to strip the HTML from the content. If you want to truncate the content at 300 characters for example, you will risk stripping the closing tag of an element while maintaining the opening tag. This will not good in any browser.

So we are going to use a very simple Regular Expression to strip the HTML from our Rich Text Field (you can use this of course for any type of database field that contains HTML): “<.*?>”. After that, we can take for example 300 characters, and add “…” after it, as this is a conventional visual signal that the text has been truncated.

Item item = Sitecore.Context.Database.GetItem("/sitecore/content/home/some item");

string richTextFieldRawValue = item["Some Rich Text Field"]

Regex htmlRemovalRegex = new Regex("<.*?>", RegexOptions.Compiled);

string richTextFieldWithoutHtml = htmlRemovalRegex.Replace(richTextFieldRawValue, string.Empty);

string truncatedRichTextField = richTextFieldWithoutHtml.SubString(0, 300) + "...";