I actually worked this out in the end. Pretty convoluted, and let's just say I will not be involving myself with ExtJS again if I can help it.
I am using the Grid.RowExpander to place HTML inside the Grid using XTemplate.
My links are therefore fairly straight forward:
<a href="#" class="add_cart_btn" id="{product_id}" onclick="return false;">Add to Cart</a>
Where {product_id} is from JSON data loaded from an Ajax query. This is important, as you will see below.
Finding these events is much more difficult ... the Grid can tell you the row, but I actually needed to grab elements from a table inside the grid row. Long story, but I inherited some of this code.
Then in my parent component I have attached an event to the Grid itself.
this.on({
click :{scope: this, fn:this.actionGridClick}
});
To find the actual link, I search for the link in the target that has the correct class. In this case "add_cart_btn"
actionGridClick:function(e) {
// Looking for a click on a cart button
var addCartEl = Ext.get(e.getTarget('.add_cart_btn'));
if(addCartEl) {
productID = addCartEl.id;
// Once we have the ID, we can grab data from the data store
// We then call to the server to complete the "add to cart" functionality
}
}
Mpst of this is not very helpful except in my case, but it's here for posterity if anyone needs something similar in the future.