Javascript AngularJS:如何从服务向dom添加和编译指令

Javascript AngularJS:如何从服务向dom添加和编译指令,javascript,angularjs,Javascript,Angularjs,我认为我试图做的是相当简单的,但我似乎无法使用Angular来确定正确的体系结构 我想要一个消息中心,这样任何控制器或其他角度代码都可以添加消息。我认为正确的方法是使用MessageCenter服务。我会在需要的地方注入服务,并调用MessageCenter.add()。我遇到的问题是如何编译克隆的DOM指令,因为$compile需要一个$scope,而我在服务中没有 这就是我正在尝试的。我不知道正确的方法是什么 <div> <div id="msg-proto" mess

我认为我试图做的是相当简单的,但我似乎无法使用Angular来确定正确的体系结构

我想要一个消息中心,这样任何控制器或其他角度代码都可以添加消息。我认为正确的方法是使用MessageCenter服务。我会在需要的地方注入服务,并调用MessageCenter.add()。我遇到的问题是如何编译克隆的DOM指令,因为$compile需要一个$scope,而我在服务中没有

这就是我正在尝试的。我不知道正确的方法是什么

<div>
  <div id="msg-proto" message-center-msg class="alert alert-success"></div>
</div>
我正在注射并呼叫服务:

.controller('SomeCtrl', function(MessageCenter) {
  MessageCenter.add('some msg');
});
我定义了一个
messagecenter msg
指令,它向元素添加了一些行为。但是它必须是
$compile
'd才能实现,我不知道如何使这一切都能工作。我只会在服务中出现“错误:参数'scope'是必需的”

如何设置一个全局消息中心,以克隆/添加消息并处理消息dom元素上的指令?

您可以敞开心扉:)

在调用MessageCenter时,将$scope作为参数移动,如MessageCenter.add(“,$scope)


或者。。。您可以在启动时将MessageCenter全局公开到作用域中—您的服务不应该像您试图做的那样直接与DOM交互。如果我设计这样一个系统,我会:

  • 提供一个服务,它可以简单地接收消息并将它们放入一个数组中(如果您想支持整个消息列表),或者简单地记住最后一条消息(如果您只想支持一条消息)
  • 拥有一个控制器,该控制器将消息服务注入其中,并将来自服务的消息绑定到其作用域中
  • 然后使用一点HTML(或自定义指令)使用上述控制器迭代消息并显示它们
  • 这就是我的意思(砰的一声:)

    index.html:

    <!doctype html>
    <html>
      <head>
        <script src="bower_components/angular/angular.js"></script>
        <script src="scripts/app.js"></script>  
        <script src="scripts/controllers/messages.js"></script>
        <script src="scripts/controllers/click.js"></script>
        <script src="scripts/services/messageService.js"></script>
    </head>
      <body ng-app="messagesApp">
        <h1>Messages</h1>
        <div ng-controller="MessagesCtrl"> 
          <ul  ng-repeat="message in messages">
            <li>{{message}}</li>
          </ul>
        </div>
        <a ng-href="#" ng-controller="ClickCtrl" ng-click="addMessage()" >Add a new message!</a>
      </body>
    </html>
    
    messages.js:

    angular.module('messagesApp')
      .controller('MessagesCtrl', function ($scope, messageService) {
        $scope.messages = messageService.messages;
      });
    
    click.js:

    angular.module('messagesApp')
      .controller('ClickCtrl', function ($scope, messageService) {
        var count = 0;
    
        $scope.addMessage = function() {
            messageService.add('Test message ' + count++);
        }
      });
    
    app.js:

    angular.module('messagesApp', [])
      .config(function ($routeProvider) {
        $routeProvider
          .otherwise({
            redirectTo: '/'
          });
      });
    

    正如我所说,如果您需要一些复杂的交互,您可以用自定义指令替换处理消息的HTML,但重要的是,您不要试图破坏服务中的视图。该服务应该只与定义良好的模型交互。

    我不久前实现了一些非常相同的东西,最近将其作为bower组件公开。 也许您可以使用或使用它:


    快乐编码

    MessageCenter需要的$scope不是调用者的$scope。具有任何$scope的任何控制器都可以注入和调用MessageCenter.add()。任何上下文中的$scope都是调用者的名称。但是,MessageCenter需要将作用域放在它最终应该放置新消息的位置。这与调用者无关。你能创建一个Plunker吗?我试过了,但我不能让它工作。如果没有$apply(),我也不清楚这其中的任何一项是如何工作的。在click.js中,您正在推送MessageService数组,但是MessagesCtrl中的绑定将如何得知这一点?添加到数组的原因会立即反映在UI中,这是angular.js的魔力。它会自动监视绑定到您的范围内的内容,并且依赖于它们的任何内容都会立即更新。通过messageService公开getMesages()而不是直接公开消息数组也可以更好地封装该示例。以前,我是从一个指令更新一个scope属性的,我必须将更新包装在一个$apply()调用中。现在我不知道为什么这不管用,但这确实管用。例如,这是在指令的postLink函数中:
    scope.$apply(function(){scope.data.haspoption=true;})
    但是没有$apply包装器,Angular没有看到变化,HTML中的ng类表达式也没有相应地更新。但是为什么不需要$apply()?我现在对此相当困惑。引用O'Reilly Angular.js的书:“不要一直调用它[scope.$apply]。当AngularJS之外的控件(DOM事件、jQuery UI控件等)调用AngularJS函数时,一定要调用它”。由于我的代码以“角度方式”处理点击等操作,因此无需调用scope.$apply.ok,下面是完整的代码片段。也许这就是为什么我需要$apply(),因为我使用的事件处理程序在技术上超出了Angular(对吗?):
    ele.find(#myEle”).on('click',function(){scope.data.haspoption=true;})好的,那么如果您没有使用单击示例呢?我希望一个控制器能够将一条消息发布到MessageCenter,然后仍然可以执行您演示的所有其他操作。我想这就是我最初的要求。因此不涉及任何问题。
    
    angular.module('messagesApp')
      .controller('ClickCtrl', function ($scope, messageService) {
        var count = 0;
    
        $scope.addMessage = function() {
            messageService.add('Test message ' + count++);
        }
      });
    
    angular.module('messagesApp', [])
      .config(function ($routeProvider) {
        $routeProvider
          .otherwise({
            redirectTo: '/'
          });
      });