1
\$\begingroup\$

For the over eager people: check out this plunker

I create a directive which has to add buttons on top of input fields, to select the language you want to input.

This is used on forms, such as a product form. A product has translations (i.e. has a description that is language dependant).

Things I am not really happy with:

  • I use $scope.$parent to get the required translation for the given field
  • The use of the timeout to handle model info that arrives with a delay (from a web service)

for the people that took the time to read this: check out the example on plunker

Let me know if you need any more information / explanation.

The directive in question:

app.directive('translationMenu', function($compile, $timeout) {
  return {
    restrict: 'E',
    scope: {
      languages: '=',
      defaultLanguage: '='
    },
    templateUrl: 'translation-menu.html',
    controller: function($scope, $element, $attrs) {
      // check if the current field is available in the given dictionary
      var checkFieldAvailability = function(l) {
        return $scope.$parent[$attrs.dictionary] && $scope.$parent[$attrs.dictionary][l] && $scope.$parent[$attrs.dictionary][    l][$attrs.field];
      }

      // check if the language is available in the dictionary, and if so, if the field is already translated.
      // is used to color the button text red
      var dictionaries = {};
      $scope.languages.forEach(function(l) {
        dictionaries[l] = checkFieldAvailability(l);
      });

      // the muscles of this operation
      // it will replace the input field with a clone of the original (and with ng-model filled out)
      var inputElementTemplate = $element.next().clone();
      var setInputField = function(lang) {
        var inputElement = inputElementTemplate.clone();
        inputElement.attr('ng-model', $attrs.dictionary + '.' + lang + '.' + $attrs.field);
        $element.next().replaceWith(inputElement);
        $compile(inputElement)($scope.$parent);
      };

      // function used in the ng-click.
      // when navigating away, it will also check again if it needs transalation.
      var selectLanguage = function(lang) {
        var oldLang = $scope.selectedLanguage;
        dictionaries[oldLang] = checkFieldAvailability(oldLang);
        $scope.selectedLanguage = lang;
        setInputField(lang);
      };

      // Dirty fix, this "ensures" that the dictionary is returned from the ajax request.
      $timeout(function() {
        console.dir(dictionaries);
        for (var lang in dictionaries) {
          dictionaries[lang] = checkFieldAvailability(lang);
        }
      }, 300);

      $scope.selectedLanguage = $scope.defaultLanguage;
      $scope.selectLanguage = selectLanguage;
      $scope.dictionaries = dictionaries;

      selectLanguage('en');
    }
  }
});

The View:

<div class="col-sm-5">
  <translation-menu languages="allLanguages" default-language="currentUser.DefaultLanguage" field="name" dictionary="desc" ></translation-menu>
  <input class="form-control" type="text" />
</div>

the controller:

function MyController($rootScope, $scope,$timeout) {
  $rootScope.allLanguages = ['en', 'nl', 'fr'];
  $rootScope.currentUser = {
    DefaultLanguage: 'en'
  };

  // Simulate slow-ish web service
  $scope.desc = {};
  $timeout(function(){
    $scope.desc = {
      'en': {
        'name': 'Joseph',
        'code': 'EN123'
      },
      'nl': {
        'name': 'Jos',
        'code': 'NL123'
      }
    };
  }, 200);
}
\$\endgroup\$
  • 1
    \$\begingroup\$ You are basically reading your attributes, then why not simply using $attrs provided instead of the fragile $scope.$parent? \$\endgroup\$ – Dmitri Zaitsev Apr 19 '14 at 7:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.