使用控制器初始化角度服务的正确方法

Sha*_*anu 6 javascript jquery-mobile angularjs

我来自一个静态类型的面向对象背景(C#),一般来说是Angular和Javascript的新手.我正在尝试使用Angular和JQueryMobile构建一个应用程序,并且面临的情况是服务不像单例一样 - 即使它们已经在一个控制器中初始化一次,服务中的属性也不会存储它们所属的任何状态设置为传递到另一个控制器或服务时.此外,当我尝试调试下面描述的代码时,我遇到了一些意外的行为:

我的设置:

  • 我正在使用JQueryMobile单页模板,该页面模板将应用程序的所有页面作为div放在同一个html页面上,并使用"href ="#DivName"模式进行重定向
  • 应用程序的每个div(页面)都有一个关联的控制器和服务
  • 控制器根据需要注入多个服务,并且注入的服务应保持在其他控制器中初始化的状态.
  • 我没有使用路由和模板 - 整个html在一个页面中

相关代码大纲如下:

HTML:

<div data-role="page" id="PageA" data-ng-controller="PageAController">      

<!-- page content and UI elements-->    

</div>


<div data-role="page" id="PageB" data-ng-controller="PageBController">

<!-- page content and UI elements-->    

</div>
Run Code Online (Sandbox Code Playgroud)

服务:

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

App.service('serviceA', function () {

    var propA;

    //objectX is an array of objects with each object containing a hashtable and some other properties 

    propA = [{},{}];  //hardcoded value for objectX gets returned properly

    return {

        initialize: function(objectX){          

            propA = objectX; // Dynamically initialized objectX value is returned as "undefined" by the getPropA function below
        },                 

        getPropA: function () {               

            return propA;
        }
    };
});

App.service('serviceB', function (serviceA) {

    var propB;

    return {

        initialize: function(){         

            propB = serviceA.getPropA();    //THIS DOES NOT WORK AS THE VALUE RETURNED IS UNDEFINED     
        },                 

        processPropB: function () {               

            //logic for processing of propB
        }
    };
});
Run Code Online (Sandbox Code Playgroud)

控制器:

App.controller('ControllerA', ['$scope', 'ServiceA',
function ($scope, ServiceA) {    

    $scope.UITriggeredAction = function(){          
        ServiceA.initialize(objectX);
    };    

}]);

//This controller gets invoked at a later point during the user interaction where ServiceA is supposed to be initialised and injected


App.controller('ControllerB', ['$scope', 'ServiceB', 'ServiceA',
function ($scope, ServiceB, ServiceA,) {    

    var returnedPropA = ServiceA.getPropA(); //THIS RETURNS UNDEFINED TOO

    //process logic to use serviceB depending on valu of returnedPropA

}]);
Run Code Online (Sandbox Code Playgroud)

问题:

  • 在上面的serviceA代码中,如果我通过在返回块之前对其进行硬编码来初始化propA的值,则在执行getPropA()方法时会返回该值.请解释这是如何工作的.

  • 我还想知道在Angular中调用javascript代码的顺序 - 我的理解是角度运行时在浏览器中加载相关页面时调用适当的控制器函数,而控制器代码又调用服务方法.但是,如果我在不同的控制器和/或服务中发出警报并加载页面,即使不应该调用页面或控制器/服务,也会立即显示警报.更奇怪的是,当执行它们的实际控制器或服务方法执行时,警报不会被执行.似乎所有控制器都在页面加载时执行.

请让我知道如何设置我的代码,以便我可以在不同的控制器中传递服务,而不会在执行期间的任何地方初始化或更新时丢失其状态.

谢谢,Shantanu

编辑:

我认为答案就在于我的第二个问题.对我来说 - 执行代码的控制流程并不清楚.以下是我认为问题所在:

基本上,两个角度控制器都是通过角度运行时在页面加载上执行,而不是在应用程序中加载和使用它们的顺序执行 - 尽管这可能只是一个JQMobile事物.

在用户界面操作上执行赋值操作时,将成功设置服务中的相应变量.但角度运行时不会重新评估所有控制器,以确保新分配反映在所有控制器上.

因此,另一个控制器继续返回初始化时设置的内容 - 未定义.

但是如果变量是在页面加载本身设置的 - 那就是在初始化发生时返回的值,并且一切正常.

根据要求,我还在下面创建了一个简单的插件来显示上述评论点:http: //plnkr.co/edit/yBOL0P3ycsoNzVrydaMs

作为问题的解决方案,下面是我认为应该工作的:

  • 以某种方式确保控制器仅在需要时初始化,而不是在页面加载时一次性初始化,以便初始化可以按照先前操作中设置的状态进行.我认为可以通过模板和路由实现,这样只有在所需的路由和模板被称为foe时才会调用控制器.我不确定这是不是它的工作方式.

  • 第二个选项是在设置控制器中发布事件,并在需要的地方订阅它们以保持同步.这似乎是一种更好的方法.

如果有效,我会确认并发布答案.

请让我知道你的想法.

对不起,长篇帖子:)

Ste*_*how 4

这是 javascript 异步特性的一个例子。基本上所有内容都是在页面加载时实例化的,因此该值可能会也可能不会被填充。Angular 为我们提供的一个很棒的解决方案是使用 Promise - $q - 或者我们可以使用 $timeout 来轮询,但这只是草率的。

这是您的代码,承诺提供救援!

首先是骗子的链接:http://plnkr.co/edit/OCgL8jATTdScRbYubt9W

一些代码要看:

控制器:

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

app.controller('ControllerA', ['$scope','serviceA',function($scope, serviceA) {

  $scope.initializeA = function(){          
        serviceA.initialize("Chris");
    };  
}]);


app.controller('ControllerB', ['$scope', 'serviceB', 'serviceA', function($scope, serviceB, serviceA) {

  $scope.initializeB = function(){          

        serviceA.getPropA().then(function(data) {
          alert("ControllerB : " + data);
        });

        serviceB.initialize();

        serviceB.processPropB();

    };

    /////////////////////////////    
    //Controller Initialization//
    /////////////////////////////

        serviceA.getPropA().then(function(data) {
          alert('now i have the data: ' + data)
        });

        serviceB.initialize();

        serviceB.processPropB();

}]);
Run Code Online (Sandbox Code Playgroud)

现在,它们已设置为在承诺得到解决时处理其代码。

现在我们做出承诺:

服务:

服务A:

 app.service('serviceA', function ($q) {

    var 
      propA,
      deferred = $q.defer()
    ;

    return {

        initialize: function(name){          

            propA = name; 
            deferred.resolve(propA);
        },                 

        getPropA: function () {               

            return deferred.promise;
        }
    };
});
Run Code Online (Sandbox Code Playgroud)

服务B:

app.service('serviceB', function (serviceA, $q) {

    var 
      propB,
      deferred = $q.defer()
    ;

    return {

        initialize: function(){         

            serviceA.getPropA().then(function(data) {
              propB = data;
              deferred.resolve();
            }); 
        },                 

        processPropB: function () {               
            deferred.promise.then(function() {
                 alert("ServiceB: " + propB);
            })

        }
    };
});
Run Code Online (Sandbox Code Playgroud)

对于刚开始使用 JS 和/或 Angular 的人来说,这可能是一个非常令人困惑的问题,但我们有这个很棒的武器来应对这种情况 - “THE $q!” - 一旦我们学会正确运用它,我们的异步噩梦就会再次变成蓬松的云彩和蝴蝶。