I resolved this one on my own, though ESRI did also provide a solution. Both here.
Revised codepen:
https://codepen.io/lizeidsness/pen/zgOpBL
My problem was the watch wasn't set on the right thing. So there's an initial watch on the activeLayerInfos.length property. If there's a legend it will be > 0.
New: If there's a layer in the legend, set a watch on it's legendElements object. If this changes, it will update accordingly.
watchUtils.when(legend, "activeLayerInfos.length", setWatch);
function updateLegend(layer) {
var activeLayer = legend.activeLayerInfos.find(e => {
return e.layer.title == layer.title;
});
if (activeLayer.legendElements.length < 1) {
return false;
}
var element = activeLayer.legendElements.find(e => {
return e.type == "symbol-table";
});
element.infos.forEach(e => {
lookup.forEach(item => {
if (e.label == item[0]) {
e.label = item[1];
}
});
});
}
function setWatch() {
if (legend.activeLayerInfos.length > 0) {
legend.activeLayerInfos.forEach(al => {
watchUtils.when(al, "legendElements", function () {
updateLegend(al);
});
});
}
}
ESRI's solution would intercept the legend response from the service. It would work well enough, if there isn't an appropriate API property to watch instead (in this case)
esriConfig.request.interceptors.push({
urls: imageryLayerUrl + "/legend",
after: function (response) {
response.data.layers[0].legend.forEach(l => {
l.label = "not " + l.label;
});
}
});