Function to ensure that at least one choice is selected
if (key === 'insight' || key === 'spike' || key === 'momentum') {


Instead of looping through and checking these specific keys using an if, why not just create an array with the keys you're interested in and loop through that?

var filterKeys = ['insight', 'spike', 'momentum'];


Running on this, you can easily use map to gather the values, filter to reduce to only those that are true. Then checking if it's the last true filter will just be a matter of checking if what remains from a filter is an array with 1 as length.

Additionally, this function can be made so that it doesn't introduce side-effects or reduces the surface area of a side-effect. You can simply split off the logic to another function and return a boolean, while leaving the logic with side-effects (one that alters settings) in the caller.

function isLastFilter(settings) {
  var filters = ['insight', 'spike', 'momentum'];

  return filters.map(filter =&gt; settings[filter])
                .filter(value =&gt; value === true)
                .length === 1;
}

function updateFilters(type) {
  var shouldUpdate  = !isLastFilter(settings);
  settings[type]    = shouldUpdate ? settings[type] : !settings[type];
  settings.errorMsg = !shouldUpdate;
}


On other things, settings.errorMsg shouldn't be part of the data. It's a computation of other settings. In this case, it's derived from a state where there's only one filter present. The problem here is that updateFilters is essentially a "sync" function, syncing settings.errorMsg to the state of the other settings. Lose this, and you'll get an invalid state.

Drop settings.errorMsg. If you're using an ng-if or something to toggle the error in the UI, it should be something like ng-if="isLastFilter(settings)".