简体   繁体   中英

How can I execute a function in an angularJS controller from a backbone controller

I am working on a application originally created with backbone and jQuery, however due to client requirement, new modules are built with angular. Routing of the application is handled with backbone route and we have successfully integrated angular modules.

The actual problem is, I need to retrieve the current instance of a module in angular and execute a function from the controller of that module based on actions handled by a backbone controller.

Here is what my angular module and controller looks like:

//In chat.module.js
( function () {
angular
    .module( 'chat.module', [] );
})();

//In chat.controller.js
(function () {
angular
        .module('chat.module')
        .controller('chat.controller', ['profileFactory', '$filter', '$q', '$timeout', 'Position', 'Chat', chat]);

function chat(profileFactory, $filter,  $q, $timeout, Position, Chat) {
    var vm = this;
    vm.initChatFlag = false;

    vm.initChat = initChat;
    vm.setInformation = setInformation;


    function setInformation() {
        //handle business logic here
    }

    ...

In backbone, the module is created as follows:

        chatmodule: function () {
        var self = this;
        var element = angular.element(document.querySelector('#modalCallback'));
        var chat = angular.element(document.querySelector('#chatModule'));
        var isInitializedChat = chat.injector();

        var isInitialized = element.injector();
        if (!isInitialized) {
            angular.bootstrap($('#modalCallback'), ['app']);
        }
        if (!isInitializedChat) {
            angular.bootstrap($('#chatModule'), ['app']);
        }

        //TODO: chat.controller.setInformation() get access to fields like chat.controller.initChatFlag etc

The main app module is defined thus:

    (function(){
    angular
        .module('app',[
            'callback',
            'ui.bootstrap',
            '720kb.datepicker',
            'ngLocale',
            'directives.module',
            'interceptor',
            'directive.loading',
            'angularUtils.directives.dirPagination',
            'blog.module',
            'profile.module',
            'filters.module',
            'chat.module',
            'ui.toggle',
        ]);
})();

The AngularJS $injector is where a lot of the magic happens, so if you expose that outside of the AngularJS code you can hook it up to non-AngularJS code like the following:

//A simple AngularJS service:
app.service('myService', function() {
  this.message = "This is my default message.";
});

//Expose the injector outside the angular app.
app.run(function($injector, $window) {
  $window.angularInjector = $injector;
});

//Then use the injector to get access to the service.
//Make sure to wrap the code in a `$apply()` so an 
//AngularJS digest cycle will run
function nonAngularEventHandler() {
  angularInjector.invoke(function(myService, $rootScope) {    
    $rootScope.$apply(function() {
      myService.message = "Now this is my message."
    });
  });
}

Edit: Alternatively, simplify the call like so.

//Instead of exposing the $injector directly, wrap it in a function
//which will do the $apply() for you.
app.run(function($injector, $window, $rootScope) {

  $window.callInMyAngularApp = function(func) {
    $rootScope.$apply(function() {
      $injector.invoke(func);
    });
  }

});

//Then call that function with an injectable function like so.
function nonAngularClick() {
  callInMyAngularApp(function(myService) {    
      myService.message = "Now this is my message."
  });
}

//And remember if you're minifying, you'll want the minify-safe
//version of the injectable function like this
function nonAngularClick() {
  callInMyAngularApp(['myService', function(myService) {    
      myService.message = "Now this is my message."
  }]);
}

Update: (last one I promise!) The above will work fine, but you might want to consider exposing a well-defined API instead of a generic injectable interface. Consider the following.

//Now I have a limited API defined in a service
app.service("myExternalApi", function($rootScope, myService) {
  this.changeMyMessage = function(message) {
    $rootScope.$apply(function() {
      myService.message = message;
    });
  };
});

//And I just expose that API
app.run(function($window, myExternalApi) {
  $window.myExternalApi = myExternalApi;
});

//And the call from outside of angular is much cleaner.
function nonAngularClick() {
  myExternalApi.changeMyMessage("Now this is my message.");
}

I was able to get access to the controller using answer from this post - https://stackoverflow.com/a/21997129/7411342

    var Chat = angular.element(document.querySelector('#chatModule')).scope();

    if(!Chat) return;

    if(Chat.chatCtrl.initChatFlag) {
        Chat.chatCtrl.setInformation();
    }else{
        console.log('Chat has not been initialized');
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM