Сортировка ng-опций с помощью переведенных значений

Очень легко выбрать варианты выбора, переведенные с помощью angular -translate:

<select name="languageId"
  ng-options="p.id as ('LANGUAGE.'+p.id)|translate for p in Const.languages | orderBy:'name'">

Но таким образом параметры сортируются по их исходному ключу, а не по переводу. Есть ли способ, которым я могу иметь список, упорядоченный по их переведенному значению, без подготовки этого списка вперед в контроллере?

Ответ 1

Самый простой способ, который работал у меня (angular 1.2.24 и angular -translate 2.14.0):

<select name="nationality" ng-model="person.nationality" ng-options="c.id as c.name | translate for c in Const.countries | orderBy:'name | translate' ">

Кредит для этого принадлежит писателю этого комментария: https://github.com/angular-translate/angular-translate/issues/1064#issuecomment-267357441

Ответ 2

Вы можете предоставить функцию предиката до orderBy и вернуть эту функцию в переводу. Это означает, что вам также нужно передать службу $filter вашему контроллеру, потому что вам нужно будет вызвать translate внутри вашего JS-кода.

Итак, чтобы предложить некоторый код в качестве руководства:

// CONTROLLER
// * Don't forget to inject the $filter service

$scope.translated = function(p) {
    return $filter('translate')('LANGUAGE.' + p.id);
}

И затем вы измените выражение orderBy:

... | orderBy:translated

Я понимаю, что предложение кажется несколько запутанным, потому что одна попытка перевода происходит внутри ng-options, а затем другая в orderBy, но она должна сортировать параметры select, как вы ожидали.

Ответ 3

У меня была такая же проблема, и я рекомендую использовать собственный фильтр, потому что вы не хотите испортить свой контроллер! Это мое текущее решение:

/**
 * orderByTranslated Filter
 * Sort ng-options or ng-repeat by translated values
 * @example
 *   ng-options="country as ('countries.'+country | translate) for country in countries | orderByTranslated:'countries.'"
 * @param  {Array} array
 * @param  {String} i18nKeyPrefix
 * @param  {String} objKey
 * @return {Array}
 */
app.filter('orderByTranslated', ['$translate', '$filter', function($translate, $filter) {
  return function(array, i18nKeyPrefix, objKey) {
    var result = [];
    var translated = [];
    angular.forEach(array, function(value) {
      var i18nKeySuffix = objKey ? value[objKey] : value;
      translated.push({
        key: value,
        label: $translate.instant(i18nKeyPrefix + i18nKeySuffix)
      });
    });
    angular.forEach($filter('orderBy')(translated, 'label'), function(sortedObject) {
      result.push(sortedObject.key);
    });
    return result;
  };
}]);

Обратите внимание, вам нужно передать префикс i18n 'LANGUAGE.' и я видел, как вы использовали объект вместо простого строкового массива, чтобы вы могли его использовать следующим образом:

<select name="languageId"
  ng-options="p.id as ('LANGUAGE.'+p.id)|translate for p in Const.languages | orderByTranslated:'LANGUAGE.':'id'">

Ответ 4

Я знаю, что это старый вопрос, но наткнулся на это сегодня и здесь, как в этом случае вы могли его решить (работает только для Array):

<select name="languageId"
  ng-options="p.id as name=('LANGUAGE.'+p.id)|translate for p in Const.languages | orderBy:'name'">

Фокус в том, чтобы назначить перевод и использовать это назначение для сортировки.