Solved

AngularJS waiting for function to complete

Posted on 2015-02-07
3
124 Views
Last Modified: 2016-02-02
I have the following Function in my datacontext of an Angular app. It is being called from the Controller but returns before the array 'alarms' is populated. I need to find a way to return the array on completion but if I move my return into the success function I get an error.

This code in my controller:
function activate() {
            var promises = [getMessageCount(),getAlarms()];
            common.activateController(promises, controllerId)
                .then(function () { log('Activated Dashboard View'); });
        }

        function getMessageCount() {
            return datacontext.getMessageCount().then(function (data) {
                return vm.messageCount = data;
            });
        }

        function getAlarms() {
            return datacontext.getAlarms().then(function (data) {
                log("Return Array count: "+data.length);
                return vm.alarms = data;
            });
        }

Open in new window


Is calling this function in my datacontext but the log output in the controller code above return a length of 0 before the log in the datacontext return a length of 9 as it is happening async.

function getAlarms(){
            
            log("Getting Alarms");
            $.ajax("/enteliweb/wsalarm/active", {
                    data: {
                        dbQuery: "{}",
                        filterIds: "[]",
                        filterQuery: JSON.stringify(alarmQuery),
                        query: "",
                        start: 0,
                        limit: 100,
                        sort: JSON.stringify(alarmSort)
                    },
                    dataType: "xml",
                    error: function (xhr, textStatus, errorThrown) {
                        // handle error
                        var msg = "Unknown Error: " + JSON.stringify(xhr);
                        if (xhr.status && xhr.responseText) {
                            msg = "Error " + xhr.status + ": " + xhr.responseText;
                        }
                        log("Load Alarm List: " + msg);
                        //showError("Load Alarm List: " + msg);
                        //clearAlarmList();

                        // clean up after load
                        //postAlarmLoad();
                    },
                    success: function (data, textStatus, xhr) {
                        log("Got Alarms");
                        $(data).find("Alarm").each(function() {

                            // find the alarm attributes
                            var needsAck = false;
                            var objectName = "<strong>"+$(this).find('Property[name="InputName"]').text()+"</strong>";
                            var eventId = $(this).find('Property[name="EventId"]').text();
                            var groupColor = $(this).find('Property[name="GroupColor"]').text();
                            var evcText = "<span class='alarm-class'>"+$(this).find('Property[name="CategoryName"]').text()+" ("+$(this).find('Property[name="Priority"]').eq(0).text()+")</span>";
                            var alarm=({objectName: objectName,EVC: evcText});
                            alarms.push(alarm);


                        });
                        log("Alarm Object Count: "+alarms.length);

                    }
                }



            );
            return $q.when(alarms);

        }

Open in new window

0
Comment
Question by:wint100
3 Comments
 
LVL 25

Expert Comment

by:Kyle Hamilton
ID: 40597044
why are you using jQuery ajax in an angular app?

you should have a service that makes the ajax calls:

example:

angular.module('myApp', [])
.service('DataService', dataservice);
dataservice.$inject = ['$http'];
function dataservice($http){
  var ds = this;

  ds.getAlarms = function(){
        var params = {} // this is an oversimplification, you will need to provide your parameters
  	return $http.get('/enteliweb/wsalarm/active', params)
  }
  ds.getMessageCount = function(){
  	return $http.get('/path/to/api')
  }

}

Open in new window


In your controller:

angular.module('myApp', [])
.controller('MyController', mycontroller);
mycontroller.$inject = ['$scope', '$q', 'DataService'];
function mycontroller($scope, $q, DataService) {
  var promises = [DataService.getMessageCount(),DataService.getAlarms()];
            $q.all(promises)
                .then(function (response) { 
                  var msgCount = response[0];
                  var alarms = response[1];
                  // parse the data and assign to $scope if desired
                });
        }

}

Open in new window


$q.all will wait for both async calls to return a promise.
0
 
LVL 1

Author Comment

by:wint100
ID: 40597258
This is actually what I have, and it now works now I've changed that Ajax code to include a deferred variable. I should have mentioned this is my FIRST look at an AngularJS app, I've come from a C# Silverlight/WPF/.NET background:

Fully open to suggestions on why/if this is bad. It works, but I want to make sure I'm not producing dirty code.

Controller:
(function () {
    'use strict';
    var controllerId = 'dashboard';
    angular.module('app').controller(controllerId, ['common', 'datacontext', dashboard]);

    function dashboard(common, datacontext) {
        var getLogFn = common.logger.getLogFn;
        var log = getLogFn(controllerId);
        var vm = this;
        vm.news = {
            title: 'Hot Towel Angular',
            description: 'Hot Towel Angular is a SPA template for Angular developers.'
        };
        vm.messageCount = 0;
        vm.people = [];
        vm.alarms=[];
        vm.title = 'Dashboard';

        activate();

        function activate() {
            var promises = [getAlarms()];
            common.activateController(promises, controllerId)
                .then(function () { log('Activated Dashboard View'); });
        }


        function getAlarms() {
            datacontext.getAlarms().then(function (data) {

                vm.messageCount=data.length;
                return vm.alarms=data;

            });


        }
    }
})();

Open in new window


Service
(function () {
    'use strict';

    var serviceId = 'datacontext';
    angular.module('app').factory(serviceId, ['common','$http', datacontext]);

    function datacontext(common,$http) {
        var getLogFn = common.logger.getLogFn;
        var log = getLogFn(serviceId);
        var $q = common.$q;
        var alarms=[];
        var alarmSort = [{
            property: "TimeStamp",
            direction: "DESC"
        }];
        var alarmQuery = {
            eventClass: ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
        };
        var service = {
                     getAlarms: getAlarms
        };

        return service;




        function getAlarms(){
            var deferred = $q.defer();
            alarms.length=0;
            $.ajax("/enteliweb/wsalarm/active", {
                    data: {
                        dbQuery: "{}",
                        filterIds: "[]",
                        filterQuery: JSON.stringify(alarmQuery),
                        query: "",
                        start: 0,
                        limit: 100,
                        sort: JSON.stringify(alarmSort)
                    },
                    dataType: "xml"
                }).success(function(data, textStatus, xhr) {

                         $(data).find("Alarm").each(function() {

                            // find the alarm attributes
                            var needsAck = false;
                            var objectName = $(this).find('Property[name="InputName"]').text();
                            var eventId = $(this).find('Property[name="EventId"]').text();
                            var groupColor = $(this).find('Property[name="GroupColor"]').text();
                             var alarmText=$(this).find('Property[name="AlarmText"]').text();
                            var evcText = $(this).find('Property[name="CategoryName"]').text()+" ("+$(this).find('Property[name="Priority"]').eq(0).text();
                            var alarm=({objectName: objectName,EVC: evcText,alarmText:alarmText});
                            alarms.push(alarm);


                        });

                    deferred.resolve(alarms);
                    }).error(function(xhr, textStatus, errorThrown) {
                        // handle error
                        var msg = "Unknown Error: " + JSON.stringify(xhr);
                        if (xhr.status && xhr.responseText) {
                            msg = "Error " + xhr.status + ": " + xhr.responseText;
                        }
                        log("Load Alarm List: " + msg);
                    });
            return deferred.promise;

        }
    }
})();

Open in new window

0
 
LVL 3

Accepted Solution

by:
Kevin Robinson earned 500 total points
ID: 41420938
1) you should avoid using  $.ajax in an angular app where possible
2) $(this).find('Property[name="EventId"]').text()
    a) Where is this pointing to?
    b) again you are using jquery when you don't need to ( and shouldnt).
3) also what version of angular are you using.  if it is 1.4+ you can avoid using the $q $deffered and make the whole service simplier.  

If you post some of your HTML code and your data structure separately ( just so i am clear) i will help you clean up the code for you.
0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article will give core knowledge of JavaScript and will head in to your first JavaScript program. I am Durvesh Naik and I am here to deal with this series of JavaScript. I will teach you JavaScript in part wise , as its quite boring to read big…
OverviewThis article demonstrates a simple search form using AJAX. The purpose of the article is to demonstrate how to use the same code to render a page and javascript (JQuery) and AJAX to make subsequent calls to refine the results. The princip…
The viewer will learn the basics of jQuery, including how to invoke it on a web page. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery.: (CODE)
The viewer will learn the basics of jQuery including how to code hide show and toggles. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery…

856 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question