0

I've searched on Google but can't find information on how to do this properly. Seems like all the answers on Google are now outdated (using older versions of AngularJS).

I'm trying to setup two controllers on my AngularJS module. For example, the first controller is handling $http GET requests. And the second controller is displaying either a 'success' or 'error' message. I want to be able to call a method from the second controller with the success/error message that is to be displayed.

Or am I supposed to use a service/factory for this? I've read about services but can't figure out how to make something like this work.

var module = angular.module('app', []);

module.controller('ApiController', ['$scope', '$http', function ($scope, $http) {
    $http.get('/api').
        success(function(data){
            // call AlertController('success')
        }).
        error(function(data){
            // call AlertController('failed')
        });
}]);

module.controller('AlertController', ['$scope', function ($scope) {
    $scope.message = {
        show_message: true,
        type: 'info',
        message: "Display message!"
    };
}]);

Either doing it that way, or perhaps I would like to push the incoming alert onto a global object variable, and then remove it after it has been displayed.

Anyone know the proper way to set this up?

BuildTester1
  • 625
  • 1
  • 7
  • 22
  • 1
    Possible duplicate of http://stackoverflow.com/q/11252780/2503246 – Alireza Ahmadi Sep 20 '14 at 06:31
  • Hi, Your can write on your own and inject it to your controller with module injection: angular.module('application', ['AlertModule']) After that you can use it. But there are some stuff like this https://github.com/Foxandxss/angular-toastr . – Chrissx Sep 20 '14 at 06:33
  • 1
    @AlirezaAhmadi - that post is over 2 years old, the code is completely different now. – BuildTester1 Sep 20 '14 at 07:26
  • @master994 - once I drop in the 'AlertModule', can I call the method just like AlertModule.queue("New error message!")? As for toastr, looks too complex for my use. Thanks though! – BuildTester1 Sep 20 '14 at 07:32
  • Yes. This is dependency injection :) Read about in this article http://tutorials.jenkov.com/angularjs/dependency-injection.html – Chrissx Sep 21 '14 at 20:09
  • @master994 For some reason it wouldn't work when I dropped in a controller (got angular error), until I removed `$scope` from the controller that was being injected (which created problems of its own). So I think the proper way is to use a `service` intermediary to pass data and calls between the controllers. – BuildTester1 Sep 21 '14 at 20:16

2 Answers2

1

Ok let's try this - you should also check out Injecting $scope into an angular service function()

The Message service:

module.service('MessageService', function ($timeout) {
    var messageQueue = [];
    var DISPLAY_TIME = 5000; // each message will be displayed for 5 seconds

    function startTimer() {
        $timeout(function() {
                // Remove the first message in the queue
                messageQueue.shift();
                // Start timer for next message (if there is one)
                if (messageQueue.length > 0) startTimer();
            }, DISPLAY_TIME);
    }

    function add(message) {
        messageQueue.push(message);
        // If this is the only message in the queue you need to start the timer
        if (messageQueue.length==0) startTimer();
    }

    function get() {
        if (messageQueue.length==0) return "";
        else return messageQueue[0];
    }

    return { add: add, get: get };
});

You can still use this ApiService as well:

module.service('ApiService', ['$http', function ($http) {
    return {
        get: function(url) {
            return $http.get(url);
        }
    };
}]);

Your Search controller:

module.controller('SearchController', ['$scope', 'ApiService', 'MessageService', function ($scope, api, messages) {
    api.get('/yelp').
    success(function(data){
        messages.add('success');
    }).
    error(function(data){
        messages.add('failed');
    });
}]);

Your Alert controller:

module.controller('AlertController', ['$scope', 'MessageService', function ($scope, messages) {
    $scope.getMessage = function() { messages.get(); }
}]);

So in your html you can have:

<div ng-controller="AlertController">
    <div>{{ getMessage() }}</div>
</div>
Community
  • 1
  • 1
Constantinos
  • 1,138
  • 9
  • 18
  • Hey, thanks. But I don't think this is grabbing at the root of my question. My trouble is I'm trying to separate the model from the controller, so I can use the data from that model within several controllers. ie. I want to push/save an alert messages into a model queue object from SearchController, then pull/read those messages from within AlertController, so that AlertController can update/display the alerts (and ie. after 5 seconds, hide the alerts one-by-one, and then update/delete the messages queue to clear the old message). But not sure how to setup a service to act as this model. – BuildTester1 Sep 21 '14 at 04:41
  • Perfect! Exactly what I needed to see. Thank you so much! 1. Didn't understand why services used the return{} but now I see how it works. 2. Didn't know a view could use call a function for output. – BuildTester1 Sep 21 '14 at 19:05
  • No probs - I just noticed that `messageQueue.push(message);` needs to be executed before `startTimer()` so I've swapped those 2 lines (just in case it gave you any trouble). – Constantinos Sep 21 '14 at 21:08
  • I got a display issue. How do I use getMessage() in an `ng-repeat` statement? ie. `ng-repeat="message in getMessages()`, because I want getMessages() to return the entire object, instead of one message at a time. For some reason, it doesn't want to bind. AlertController calls the messages.get() on init. But after that, it doesn't update. Can I just pass the variable directly, or does it have to go through functions on each end? – BuildTester1 Sep 21 '14 at 23:49
  • I got it working. The one downside is I can't do `{{ng-show="messages().length"}}` in the view, which would have been possible if I passed a json instead of a function [from the service to a $scope var in the controller]. I have a view that uses an `ng-repeat="message in messages()"` and I wanted to hide the entire block is there are 0 messages, but couldn't do it this way directly. – BuildTester1 Sep 22 '14 at 05:06
  • That's strange, I don't know why messages().length wouldn't work. Can you post a plunker with your new code? – Constantinos Sep 22 '14 at 05:33
  • Wow that's weird. I made a plunkr and it actually works in there when I do `messages().length`. Strange, I wonder if my AngularJS file is outdated. Anyway, thanks for all your help! http://plnkr.co/edit/cbSEZ62PXZSaCSDzqav6?p=preview – BuildTester1 Sep 23 '14 at 01:06
0

here is how you make factory

    module.factory('appService', ['$window', '$http', '$q', function(win, $http, $q) {
    return{
        backendcall: function(){
            var deferred = $q.defer();
            $http.get('/yelp').
                success(function(data){
                    deferred.resolve(data);
                }).
                error(function(data){
                    deferred.resolve(status);
                });

            return deferred.promise;
        }
    }
  }]);

and your controller will be like this

module.controller('AlertController', ['$scope', 'appService', function ($scope, appService) {
    appService.backendcall().then(function(response){
            $scope.message = {
            show_message: true,
            type: 'info',
            message: "Display message!"
        };  
    })

}]);
khizar naeem
  • 296
  • 2
  • 6