Using Angular translate within controller, for data brought by service
Asked Answered
G

2

6

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?

Graehme answered 30/11, 2015 at 19:24 Comment(6)
What are you putting in your view? We can only guess until you give us that.Irascible
Updated the questionGraehme
@DannyG do you still a solution for this?Wendt
@Wendt yes, bounty is on for thatGraehme
Is the schema JSON being fetched via ajax? Or is it just a structure within your static javascript?Wendt
No, its on a .json file, brought by a service using $http, and that service is injected within the controllerGraehme
W
3

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; });
    });
}
Wendt answered 15/12, 2015 at 5:14 Comment(6)
@DannyG: Does this solution help you out?Wendt
I'm at work atm when, and this is not a project for work, I'll try and then provide you feedbackGraehme
I'm using an external .json file, how in this factory can you read from an external file? that's why i got a service, i forgot to mention thatGraehme
Replace the elements function with a modified version that uses $http.get to retrieve the schema contents.Wendt
So, i just get rid of the .service.js file and use the factory only?Graehme
Thank you @Wendt your answer with slight mods, worked flawleslyGraehme
I
0

I just realized, the description property is a string. There's no reason that I can see that it would print anything else. JSON isn't really meant to carry functions, just data (otherwise it'd just be plain JS). Just pass the data that you want to filter and replace it with the final result.

Irascible answered 30/11, 2015 at 20:13 Comment(7)
What do you mean exactly?Graehme
In IOS_TABLET_DOWNLOAD_URL, the property description is in quotes; JSON can't transmit usable functions unless you're going to use eval() (don't do that). I'd suggest that instead of including a literal string of the function call you want to make, transmit keywords that you can either pick apart in a flowchart or perform some predetermined operation on.Irascible
I thought about the eval function also, but didn't want to use that at all. but you are right, i must think a proper solutionGraehme
Do you know for a fact that the description might need to be put through a translate filter, or is the possible type of contents very diverse? At the very least, do you have control over the resource that's providing it in the first place?Irascible
I have to try it as unknown, the idea is that one integration team (some sort of backend, mod the schema and the form, they also have access to modify the json file with the i18n keys, so it can be N quantity of unknown keysGraehme
A few more questions: 1. Is IOS_TABLET_DOWNLOAD_URL a placeholder URL you're giving, or does it refer to some property you need to reference? 2. Are all the instances of it in your example referring to the same thing? 3. If it is a URL, is it supposed to translated directly, or is it supposed to be called, and its contents put through translate?Irascible
In this specific schema I'm not translating the titles but the description tags. That's the title but as it's a technical title it's not being translatedGraehme

© 2022 - 2024 — McMap. All rights reserved.