Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Angular translate within controller, for data brought by service

I have the following scenario:

I have a JSON file with this kind of data:

"IOS_TABLET_DOWNLOAD_URL": {
  "type": "string",
  "minLength": "5",
  "title": "IOS_TABLET_DOWNLOAD_URL",
  "description": "$filter('translate')('configuration.IOS_TABLET_DOWNLOAD_URL')"
},

The description field needs to be translated using Angular Translate, I'm injecting the service to my controller like this

ConfigController.$inject = ['$scope', '$filter', '$compile', 'MyService'];
function ConfigController($scope, $filter, $compile, MyService) {

  // And using compile
  $scope.schema = elements; // Where element is the object from MyService
  $compile($scope.schema)($scope);

}

However the $filter is being printed unprocessed as the description in the view

"$filter('translate')('configuration.IOS_TABLET_DOWNLOAD_URL')"

EDIT

I'm using Angular Schema Form to generate the forms. So basically I have in the view something like this

<div ng-controller="FormController">
   <form sf-schema="schema" sf-form="form" sf-model="model"></form>
</div>

How can I do it?

like image 913
Danny22 Avatar asked Nov 30 '15 19:11

Danny22


1 Answers

Full working fiddle is at https://jsfiddle.net/dqhwzksx/, its a bit long so I'll take apart the relevant sections here.

The main issue is that neither angular-schema-form nor angular-translate know what to do with "description": "$filter('translate')('configuration.IOS_TABLET_DOWNLOAD_URL')" on their own. We need to do the translation ourselves.

First, our schema now no longer needs to deal the filter itself:

var schema = {
    "type": "object",
    "title": "Sample Schema",
    "properties": {
        "IOS_TABLET_DOWNLOAD_URL": {
          "type": "string",
          "minLength": "5",
          "title": "IOS_TABLET_DOWNLOAD_URL_TITLE",
          "description": "IOS_TABLET_DOWNLOAD_URL_DESCRIPTION"
        }
    }
};

The title and description fields can now directly reference the translation tokens. Next, we're going to write an angular service that will retrieve this schema, but with the translations already made. I think this was the intention of your MyService:

.factory('Schema', function ($q, $translate) {
    return {
        elements: function() {
            var a = [];
            var result = angular.copy(schema);
            angular.forEach(result.properties, function (value, key) {
                a.push($translate([value.title, value.description]).then(
                    function (translations) {
                        value.title = translations[value.title];
                        value.description = translations[value.description];
                    }
                ));
            });
            return $q.all(a).then(function() { return result; });
        }
    }
})

Lets break that down a little bit:

var a = [];
var result = angular.copy(schema);

First, we setup an array a into which we're going to put a bunch of promises (one for each field in the schema), and we make a copy of the original schema since we'll be modifying it.

angular.forEach(result.properties, function (value, key) {
    a.push($translate([value.title, value.description]).then(
        function (translations) {
             value.title = translations[value.title];
             value.description = translations[value.description];
        }
    ));
});

Here we're iterating over each property in the schema (just the one in this sample), requesting a translation for that property's title and description fields. Since $translate returns promises, we need to attach a .then handler to apply the translations direct into the copy of the schema once that promise resolves. Finally, the promise is also appended onto the a array whose job it is to remember the list of all of these promises we're running.

return $q.all(a).then(function() { return result; });

Finally, we wait for all of those promises to have resolved (i.e. the translations are all complete), then return the fully translated schema object.

.controller('FormController',function ($scope, Schema) {

    Schema.elements().then(function (elements) {
        $scope.schema = elements;
    })
    $scope.model = {};
    $scope.form = [
        "IOS_TABLET_DOWNLOAD_URL"
    ];

});

The actual controller itself is rather simple, and not much different from your original. The markup in the template is not altered either.

For fun, try changing the preferred language from en to de:

$translateProvider.preferredLanguage('de');

EDIT

If you wanted to retrieve the schema contents from another file or service, replace the elements method with something like:

elements: function() {
    return $http.get('path/to/schema.json').then(function(response) {
        var a = [];
        var schema = response.data;
        angular.forEach(schema.properties, function (value, key) {
            a.push($translate([value.title, value.description]).then(
                function (translations) {
                    value.title = translations[value.title];
                    value.description = translations[value.description];
                }
            ));
        });
        return $q.all(a).then(function() { return schema; });
    });
}
like image 169
nicknystrom Avatar answered Oct 28 '22 19:10

nicknystrom