1

I'm trying to get some information from a server in an html page of an AngularJS app. The method itself is working fine, however, when I call the function in my html file with $scope. I get a $rootScope:infidg Error.

Method in controller:

    $scope.getTranslation = function(){
        $http.get('https://producthero.com/index.php?option=com_hero&task=language.translate&s=SEARCH')
            .then(
                function (response) {
                    return response.data.translation;
                }
            );
    };

Call in html file with ng-app and ng-controller:

<div ng-controller="Product">
    <span>{{getTranslation()}}</span>
</div>

I'm using this way of translating because the initial backend of the site is running in Joomla, I know i18n, but we can't use it here.

The error is:

http://errors.angularjs.org/1.6.4/$rootScope/infdig?p0=10&p1=%5B%5D

angular.min.js:123 Error: [$rootScope:infdig] <http://errors.angularjs.org/1.6.4/$rootScope/infdig?p0=10&p1=%5B%5D>
    at angular.min.js:6
    at m.$digest (angular.min.js:147)
    at m.$apply (angular.min.js:149)
    at angular.min.js:21
    at Object.invoke (angular.min.js:44)
    at c (angular.min.js:21)
    at Sc (angular.min.js:22)
    at ue (angular.min.js:20)
    at HTMLDocument.<anonymous> (angular.min.js:331)
    at i (jquery.min.js:2)

I hope this is just me being stupid and that I'm missing something to make this kind of direct calls with http possible!

EDIT:

My solution on my translation problem is the following (thanks to @Aleksey Solovey for the answer):

Controller method

$scope.translations = {};

$scope.getTranslation = function(string){
    $http.get('https://producthero.com/index.php?option=com_hero&task=language.translate&s=' + string)
        .then(
            function (response) {
                $scope.translations[string] = response.data.translation;
            });
    };

View call

<div ng-app="products">

        <div ng-controller="Product">
            <span ng-init="getTranslation('SEARCH')">{{translations.SEARCH}}</span>
    </div>
</div>
1
  • The ng-init directive can be abused to add unnecessary amounts of logic into your templates. There are only a few appropriate uses of ngInit. See AngularJS ng-init API Reference.
    – georgeawg
    Commented Jul 12, 2018 at 10:53

2 Answers 2

1

$http request would return a Promise, not some value. So you need to populate a scoped variable first and then use it (asynchronously). Here is what it should look like:

var app = angular.module('myApp', []);
app.controller('Product', function($scope, $http) {
  $scope.getTranslation = function() {
    $http.get('https://producthero.com/index.php?option=com_hero&task=language.translate&s=SEARCH').
    then(function(response) {
      $scope.translation = response.data.translation;
    });
  };
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>

<div ng-app="myApp">
  <div ng-controller="Product">
    <span ng-init="getTranslation()">{{translation}}</span>
  </div>
</div>

4
  • Ah, sounds logic. Thank you, this is working perfectly! Commented Jul 12, 2018 at 10:21
  • The ng-init directive can be abused to add unnecessary amounts of logic into your templates. There are only a few appropriate uses of ngInit. See AngularJS ng-init API Reference.
    – georgeawg
    Commented Jul 12, 2018 at 10:48
  • Could you give a different answer providing an example without using ng-init? If there is a more clean less intensive solution I would be glad to hear that from you @georgeawg Commented Jul 12, 2018 at 12:29
  • @DavidKooijman 'init' is for initialisation, simply initialise it manually in the controller with $scope.getTranslation() Commented Jul 12, 2018 at 12:31
0

Could you give a different answer providing an example without using ng-init?

Simply initialise it manually in the controller:

app.controller('Product', function($scope, $http) {
  $scope.getTranslation = function() {
    $http.get('https://producthero.com/index.php?option=com_hero&task=language.translate&s=SEARCH').
    then(function(response) {
      $scope.translation = response.data.translation;
    });
  };
  //INSTEAD OF ng-init
  $scope.getTranslation();
});
<div ng-app="myApp">
  <div ng-controller="Product">
    ̶<̶s̶p̶a̶n̶ ̶n̶g̶-̶i̶n̶i̶t̶=̶"̶g̶e̶t̶T̶r̶a̶n̶s̶l̶a̶t̶i̶o̶n̶(̶)̶"̶>̶{̶{̶t̶r̶a̶n̶s̶l̶a̶t̶i̶o̶n̶}̶}̶<̶/̶s̶p̶a̶n̶>̶
    <span>{{translation}}</span>
  </div>
</div>

The ng-init directive can be abused to add unnecessary amounts of logic into your templates. There are only a few appropriate uses of ngInit. See AngularJS ng-init API Reference.


Use of functions in HTML interpolation bindings with {{ }} should be avoided for performance reasons. Those functions are called one or more times per digest cycle.

Erroneous

<div ng-controller="Product">
    <span>{{getTranslation()}}</span>
</div>

Asynchronous functions that return promises will cause infinite digest errors.

For more information, see

3
  • Ah, I get what you mean! But I have a lot of translations that I need to do on the fly with ng-repeat on a product list etc. That's why i want it to be generated in the view although it seems to be not the best solution! Thanks for you answer though Commented Jul 12, 2018 at 12:55
  • There are ways to avoid ng-init in ng-repeat. It is involves chaining promises and using $q.all. It avoids tangling Model and View. The result is code that is easier to understand, debug, test, and maintain.
    – georgeawg
    Commented Jul 12, 2018 at 13:05
  • I'll have a look into that as well. Thanks for all the info! Commented Jul 12, 2018 at 13:33

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.