0

My get_tracking() function returns an object with the summary property.

I tried a few different ways to make this work but I haven't had any luck. To solve this, I would either like to bind the summary property to the pack object or just have it appear in the table.

In this code I am first pulling all packs from the database and storing in $scope.packs. I would then either like to run the get_tracking() function on each one and have the summary attribute applied to each pack.

Is there a way to run a function on each pack once it is returned from the database? When I try to run function in angular I don't have any luck because the pack objects have not yet been returned.

html:

<tbody>
<tr data-ng-repeat="pack in packs"
 data-ng-show="((authentication.user) && (authentication.user._id == pack.user._id))">
<td data-ng-bind="pack.tracking_number"></td>
<td data-ng-bind="pack.description"></td>
<td data-ng-bind="pack.company"></td>
<td data-ng-bind=""></td>
<td data-ng-bind="get_tracking(pack).summary"></td>
<td ng-bind=""></td>
</tr>     
</tbody>

JS

   $scope.get_tracking = function (packet) {
        if (packet){
            $http.post('/tracking', packet).success(function(response) {
                return response.summary;
            }).error(function(response) {
            });
        } 
    };

3 Answers 3

1

Bind the summary property elsewhere, and use a two way binding on that, so that when the result is returned from the $http call, you can have it displayed.

<tbody>
    <tr data-ng-repeat="pack in packs"
         data-ng-show="((authentication.user) && (authentication.user._id == pack.user._id))">
       <td data-ng-bind="pack.tracking_number"></td>
       <td data-ng-bind="pack.description"></td>
       <td data-ng-bind="pack.company"></td>
       <td data-ng-bind="{{::get_tracking(pack)}}"></td>
       <td data-ng-bind="trackingSummary[packet]"></td>
       <td ng-bind=""></td>
    </tr>     
</tbody>

JS

$scope.trackingSummary = {};
$scope.get_tracking = function (packet) {
    if (packet){
        $http.post('/tracking', packet).success(function(response) {
            $scope.trackingSummary[packet] = response.summary;
        }).error(function(response) {
        });
    } 
 };

OR:

<tbody>
    <tr data-ng-repeat="pack in packs"
         data-ng-show="((authentication.user) && (authentication.user._id == pack.user._id))">
       <td data-ng-bind="pack.tracking_number"></td>
       <td data-ng-bind="pack.description"></td>
       <td data-ng-bind="pack.company"></td>
       <td data-ng-bind=""></td>
       <td data-ng-bind="get_tracking(pack)"></td>
       <td ng-bind=""></td>
    </tr>     
</tbody>

$scope.trackingSummary = {};
$scope.get_tracking = function (packet) {
    if (packet && !$scope.trackingSummary[packet.tracking_number]){
        $http.post('/tracking', packet).success(function(response) {
            $scope.trackingSummary[packet.tracking_number] = response.summary;
        }).error(function(response) {
        });
    } 
    return $scope.trackingSummary[packet.tracking_number];
 };

UPDATE

If you add a function to run when your $scope.packs have loaded in, you could ensure that things only get called once:


JS

$scope.trackingSummary = {};

$scope.get_tracking = function (packet) {
    if (packet){
        $http.post('/tracking', packet).success(function(response) {
            $scope.trackingSummary[packet.tracking_number] = response.summary;
        }).error(function(response) {
        });
    } 
 };

 //after packs loaded
var onLoadedFunc = function () {
    for (var i = 0; i < $scope.packs.length; i++) {
        $scope.get_tracking($scope.packs[i]);
    }
};

//when you know that the packs collection is loaded:
 onLoadedFunc();

This should prevent an infinite digest loop, as calling the property of the object would not cause a digest every time like a function would. and if your order of the packs would not change once loaded, you could also pass the index in and set the summary on the object itself:

var onLoadedFunc = function () {
    for (var i = 0; i < $scope.packs.length; i++) {
        $scope.get_tracking($scope.packs[i], i);
    }
};

$scope.get_tracking = function (packet, index) {
    if (packet){
        $http.post('/tracking', packet).success(function(response) {
            $scope.packs[i].summary = response.summary;
        }).error(function(response) {
        });
    } 
 };

Allowing for HTML like so:

[...]
<td data-ng-bind="pack.summary"></td>
[...]

You could also remove the get_tracking function from scope, as it would only be called by code in the controller, unless you need to update or change the summary without reloading the scope/view

Sign up to request clarification or add additional context in comments.

4 Comments

I didn't have easy access to some code in front of me, so this might have a few issues that would need resolving, to prevent multiple calls to the server, but take it more as a concept.
Thanks for the help, that is working better and I am able to retrieve the values I was looking for, but now I am getting the following error: Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Can you add some updated code that is causing the $digest loop? - I suspect that it is because the digest loop is checking for value change once a second, so when it calls the function, it is calling it every second, and you end up with multiple requests to the server queued up, personally I'd recommend calling the function for every item in $scope.packs when the controller is loaded rather than in-lining it in the ng-repeat, to ensure it is called only once per page load.
Thank you for you help, it was bad coding on my part. I should have never been trying to retrieve the data in the front end like that.
0

It's bad practice to use things like this <td data-ng-bind="get_tracking(pack).summary"></td>. You send request each time angular execute bindings. And in handler you update data that trigger bindings, that's why you have infinite loops in app.

Prepare all data before passing to views. Get tracking info for each pack, prepare well structured object and then pass to view. You will get much better performance.

1 Comment

Thanks for the advice. I am very new to angular and after doing a lot of reading I now see that this is horrible practice. I have since updated my code and have resolved the issue.
0

Your $scope.get_tracking function is use $http.post which is type of "promise" and "return response.summary;" dosn't return any value to your function "get_tracking"

1 Comment

Thank you for bringing that to my attention, I tried playing around with it some more but still couldn't get it to work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.