【问题标题】:Why sharing data across controllers doesn't work in AngularJS为什么跨控制器共享数据在 AngularJS 中不起作用
【发布时间】:2013-07-02 15:05:05
【问题描述】:

我正在尝试构建一个简单的用户名登录系统。这只是为了记录我可以在我的各种控制器中使用的用户名。

但是,由于某种原因,我无法在abcController 中获得$scope.userName

这个问题的本质是在控制器之间共享数据。

controller.js

app.controller('userNameController',function ($scope, $log, Config, Session)
{
  Session.updateSession($scope.userName);
});

app.controller('abcController',function ($scope, $log, Config, Session)
{
    $scope.userName=Session.data.username;
     //some other code
});

resource.js

app.factory('Session', function() {
    var Session = {
        data: {},
        updateSession: function(userName) {
            Session.data = { "username": userName }
        }
    };
    return Session;
});

一旦用户点击登录按钮,就会出现一个 twitter-bootstrap modal(popup) 并要求用户输入他们的用户名。

index.html

<div ng-controller="userNameController">
<button class="btn" id="enterUsernameBtn" href="#userNameModal" role="button" class="btn" data-toggle="modal" title="Enter Username">Login</button>
</div>

    <!-- UserName Modal -->
    <div id="userNameModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="userNameModalLabel"  aria-hidden="true">
        <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
            <h3 id="userNameModalLabel">Enter your username</h3>
        </div>
        <div class="modal-body">
            <p><b>UserId</b></p>
            <div class="input-append">
                <input class="pull-left" id="userIdTextBox" type="text" style="left:8px; width:160px" ng-controller="userNameController" ng-model="userName">
            </div>
        </div>
        <div class="modal-footer">
            <button class="btn" data-dismiss="modal" aria-hidden="true">Submit</button>
        </div>
    </div>

如果有更好的方法来做我上面想做的事情,请随时提出建议。

【问题讨论】:

  • 这不是因为您的 abcController 在您的 userNameController 设置 userName 属性时已经运行了吗?大概 $scope.userName === 在 abcController 中未定义。如果在需要时直接使用 Session.data.username 会发生什么?您可能需要将 Session 资源附加到您的 abcController $scope。
  • 你可能会觉得这篇文章很有趣blog.jdriven.com/2013/03/…
  • @cirrus,你是对的。这就是可能发生的事情。我在 app.js 中写了app.run(function(Session) {}); //bootstrap session;,它在任何其他 .js 文件之前被引用。那没有帮助。我不是已经将 Session 资源附加到 abcController 了吗?请帮忙,angularJS noob在这里。
  • 您也可以使用 $rootScope 但我认为您的资源方法要好得多。

标签: javascript twitter-bootstrap angularjs


【解决方案1】:

这样定义资源有帮助吗?

app.factory('Session', function() {
     var Session = {
        data: { username: undefined }, // ensure object ref to attach to
        updateSession: function(userName) {
            Session.data.username = userName; // do NOT recreate the object above
        }
    };
    return Session;
});

我认为可能会发生什么(而且我看不到您的所有代码),但我认为当您在 abcController 中引用时没有设置 username。通过首先在对象架构中定义一个共享引用,abcController 可以附加到该引用,它将在稍后调用 updateSession() 时反映更改。

这是一个使用您的服务理念的工作example

【讨论】:

  • 我在某处读到过,应该在app.js 中写app.run(function(Session) {}); //bootstrap session; 会有所帮助吗?
  • 顺便说一句,我按照你的建议定义了我的资源,但没有帮助。
  • 可以肯定的是,console.log() 在两个控制器中,以便您可以看到顺序,并将用户名设置为初始虚拟值,例如“xxxx”。当您更改值时,您应该会看到它反映在 abcController 中,但请记住您需要一个 '.'参考。如果您更改底层引用,您将打破两者之间的联系。在您之前的代码中,您已完全重新分配数据,因此 abcController 绑定到不同的数据{} 对象,更不用说未定义的用户名属性。
  • 我将 console.log() 放在两个控制器中。在 abcController 中,最初的用户名值是未定义的。但是,如果我将$scope.userName=Session.data.username; 放在我在点击临时按钮后调用的临时函数下,我可以看到用户名值从 userNameController 传播,现在我必须弄清楚如何获取当前用户名,以便在视图中我可以做到{{username}} 来自 abcController。我尝试将 $scope.$watch('Session.data.username', function(){$scope.username=Session.data.username}) 放入 abcController,但没有成功。
  • 让服务版本正常工作。 jsfiddle.net/cWkP2/1 请注意“。”在 data.username 中
【解决方案2】:

我找到了使用emitbroadcast 的替代解决方案。 jsfiddle 中的完整代码示例

app.js

app.run(function($rootScope) {
    /*
     Receive emitted message and broadcast it.
     Event names must be distinct or browser will blow up!
     */
    $rootScope.$on('handleEmit', function(event, args) {
        $rootScope.$broadcast('handleBroadcast', args);
    });
});

controller.js

app.controller('userNameController',function ($scope, $log, Config)
{

  $scope.submitUserName= function ()
  {
      // Session.updateSession($scope.userName);
      $scope.$emit('handleEmit', {username: $scope.userName});
  };

});

app.controller('abcController',function ($scope, $log, Config)
{
    $scope.$on('handleBroadcast', function(event, args) {
        $scope.userName = args.username;
      });
     //some other code
});

【讨论】:

  • 实际上,再想一想,这可能是您必须要做的,否则您的摘要循环将不会在其他控制器中运行。因此,除非在 userNameController 中发生某些事情时触发 abcController 中的摘要循环,否则即使 if 您会看到它,您也不会看到 userName 的变化。我的建议将使 userName 通过您的服务传播 OK,但您需要一些其他机制来触发 abcController 的 $digest。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-10
  • 2013-09-06
  • 1970-01-01
  • 2015-12-15
  • 2014-03-22
  • 2014-12-14
  • 2013-05-28
相关资源
最近更新 更多