Solved

AngularJS waiting for function to complete

Posted on 2015-02-07
3
105 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

What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Introduction HyperText Transfer Protocol (http://www.ietf.org/rfc/rfc2616.txt) or "HTTP" is the underpinning of internet communication.  As a teacher of web development I have heard many questions, mostly from my younger students who have come to t…
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…

708 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

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now