Response from command with signal

maciekrei's Avatar

maciekrei

16 Nov, 2012 12:33 AM

Hello,
I started to switch from Events to Signals and I have little architecture problem.

Let's say:
1) I have UrlRequestService, which sends url request to given url with some arguments
2) I handle it with SendRequestCommand
3) And I call SendRequestCommand command with SendRequestEvent

When I send request, by calling command with event, I'ld like to get some response. In Event era, I just passed through SendRequestEvent local type strings for response and error events, which command caller listened to. When I've got response or error from called request, I removed listeners from commands caller and everything seemed to be clean ( command caller didnt have any listeners after command resolved).

However, when I wanted to change events to signals I've got some problem.

Let's say I have points 1 and 2 the same and:
3) I call SendRequestCommand command with injected SendRequestSignal

In this case, I initiate in commands caller temporary signals, which are sent through SendRequestSignal when I call SendRequestCommand. After SendRequestCommand resolves, commands caller response or error signal will be dispatched. The problem occurs, when I whant to remove listeners from command caller signals.

I can use signal.addOnce function. However, when response occurs, response signal will remove its listener, but error signal will still listen for error, which will never occur. The same in situtation when error occurs.

I want to avoid the situtation, when I have to assign those signals as class variables. They should be temporary listeners which are removed after response or error occurs.

I could send themselves in dispatched response or error, but that doesnt sound good.

Is there any other solution to my command response problem? Did I miss some robotlegs native functionality or forget about some major pattern?

  1. Support Staff 1 Posted by Ondina D.F. on 16 Nov, 2012 10:20 AM

    Ondina D.F.'s Avatar

    Hey Maciej,

    Let’s see if I understood the use case.

    In SomeClass you dispatch SomeEvent.DATA_REQUESTED, that triggers a command-> service.

    SomeClass added 2 listeners:
    1. SomeEvent.DATA_RECEIVED and a handler onDataReceived
    2. SomeEvent.REQUEST_FAILED and a handler onRequestFailed
    3. In onDataReceived() you do something with the data and then call, say, removeRequestEvents(). In this method you remove both events, 1 + 2. Same for onRequestFailed, you do something with the error mesagge (or not), then you call removeRequestEvents().

    That’s what you can do with signals, too, remove both listeners, when one of the 2 signals has been handled.

    Of course, that’s possible if both handlers are in the same class. If one class listens for SomeEvent.DATA_RECEIVED and another class for REQUEST_FAILED, one of the handlers won’t be called.

    Now, the question is, are you handling both signals within the same class? If the answer is yes, would my suggestion from above work for you?

    Ondina

  2. 2 Posted by maciekrei on 16 Nov, 2012 12:50 PM

    maciekrei's Avatar

    Hey Odina,
    yes, your assumtions are correct. I do exactly like you listed in points 1-3 and handlers are in the same class. But how can I remove listeners from signals? In events I've got targets instance, so removing it's listeners wasnt a problem. Bt here I need instance of both signals wich I dont have. E.g.:

    [Inject]
    public var commandCaller:Signal;
    
    private function callCommand():void {
        var response:Signal = new Signal(Object);
        response.addOnce(onResponse);
    
        var error:Signal = new Signal(String);
        error.addOnce(onError); 
    
        callCaler.dispatch(response,error);
    }
    
    private function onResponse(message:Object):void 
        //response listener is already removed but what about error listener?
    }
    
    private function onError(error:String):void 
        //error listener is already removed but what about response listener?
    }
    

    I could send their instance through response/error along with message/error parameter, but that doesnt seem pretty.

  3. Support Staff 3 Posted by Ondina D.F. on 16 Nov, 2012 02:45 PM

    Ondina D.F.'s Avatar

    A Mediator

            [Inject]
            public var sendRequestSignal:SendrequestSignal;
    
            [Inject]
            public var signalDataVO:SignalDataVO;
    
            private var response:Signal;
            private var error:Signal;
    
            override public function onRegister():void
            {                    
                response = new Signal(Object);
                response.add(onResponse);
    
                error = new Signal(String);
                error.add(onError);
    
                signalDataVO.responseSignal = response;
                signalDataVO.errorSignal = error;
                
                sendRequestSignal.dispatch(signalDataVO);
            }
    
            private function onResponse(message:String):void
            {
                trace("onResponse(message) " + message);
                removeSignalsListeners();
            }
    
            private function onError(error:String):void
            {
                trace("onError(error) " + error);
                removeSignalsListeners();
             }
    
            private function removeSignalsListeners():void
            {
                error.removeAll();
                response.removeAll();
                trace("error.numListeners " + error.numListeners + " response.numListeners " + response.numListeners);
            }
    

    VO

    package yourdomain.models.vo
    {
        import org.osflash.signals.Signal;
    
        public class SignalDataVO
        {
            private var _responseSignal:Signal;
            private var _errorSignal:Signal;
            
            public function SignalDataVO()
            {
            }
    
            public function get errorSignal():Signal
            {
                return _errorSignal;
            }
    
            public function set errorSignal(value:Signal):void
            {
                _errorSignal = value;
            }
    
            public function get responseSignal():Signal
            {
                return _responseSignal;
            }
    
            public function set responseSignal(value:Signal):void
            {
                _responseSignal = value;
            }
        }
    }
    

    Signal

    package yourdomain.controllers.signals
    {
        import org.osflash.signals.Signal;
        
        import yourdomain.models.vo.SignalDataVO;
        
        public class SendrequestSignal extends Signal
        {
            public function SendrequestSignal()
            {
                super(SignalDataVO);
            }
        }
    }
    

    Command

    package yourdomain.controllers.commands
    {
        import org.robotlegs.mvcs.Command;
    
        import yourdomain.models.vo.SignalDataVO;
    
        public class SendRequestCommand extends Command
        {
            [Inject]
            public var signalDataVO:SignalDataVO;
    
            public function SendRequestCommand()
            {
            }
    
            override public function execute():void
            {
                trace("SendRequestCommand.execute() ");
                //say, you dispatch one of them:
                signalDataVO.responseSignal.dispatch("data");
                //signalDataVO.errorSignal.dispatch("error");
            }
        }
    }
    

    Would that be a solution for you?

  4. 4 Posted by maciekrei on 17 Nov, 2012 11:34 AM

    maciekrei's Avatar

    Yes, it is solution for me. Although I was strugling before with this implementation, because it some times can cause a lot of response signals. All in all, thank you for your contribution.

  5. Support Staff 5 Posted by Ondina D.F. on 20 Nov, 2012 10:07 AM

    Ondina D.F.'s Avatar

    Hi Maciek,

    Yes, it is solution for me. Although I was strugling before with this implementation, because it some times can cause a lot of response signals. All in all, thank you for your contribution.

    You’re welcome.
    You’ll have to decide what’s best for you, using the request/response signal pairs, or 2 signals, an ErrorSignal and a ResponseSignal (with names of your choice), which you’d inject into your command as well.

    Cheers,
    Ondina

  6. Ondina D.F. closed this discussion on 20 Nov, 2012 10:07 AM.

Comments are currently closed for this discussion. You can start a new one.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac