【问题标题】:Angular ngClick cannot access variable in a different scopeAngular ngClick 无法访问不同范围内的变量
【发布时间】:2014-01-15 09:58:13
【问题描述】:

我对 Javascript 尤其是 AngularJs 完全陌生。这是我的问题,我需要在 ng-repeat 中调用 ng-click 函数来隐藏它之外的一些 html。

据我了解,问题是因为所有变量(在这种情况下特别是变量“位置”)都在另一个我无法访问的范围内。任何人都可以用最短的方法帮助我解决这个问题吗?

到目前为止,我已经几乎完成了我的网站,只使用了 html 角度标签(这意味着我真的不需要编写任何自定义函数),这绝对是最后一块。

另外,据我所知,每当创建一个新的 Angular 控制器时,它都有自己的范围。在这种情况下,所有调用(除了我遇到问题的调用)都是在没有初始化任何控制器的情况下进行的,那么如何访问变量呢?有没有像“默认范围”这样的东西?我知道 rootScope 对我不起作用。

提前谢谢你。

<div id="top_nav">
    <div id="top_nav_right">    
        <div id="page_header" ng-show="checked" ng-switch on="page">
        </div>  
        <a href="#" ng-click="checked = ! checked">
        </a>
    </div>      
</div>  
<div id="main_sidebar" class="check-element animate-hide" ng-show="checked">
    <ul class="menu" ng-show="!locations">
    </ul>
    <ul class="menu" ng-show="locations">
    </ul>
</div>

<div id="sub_sidebar" ng-show="checked" ng-switch on="page">
        <div ng-switch-default "check-element animate-hide">
                <div id="latest_trips_container">       
                    <div ng-controller="PostsCtrlAjax">  
                                <ul id="latest_trips" ng-controller="MyCtrl">   
                                    <li ng-repeat="post in travels">
                                                <div id="trip_details">
                                                    <a id="details" href="#/details" ng-click="locations =! locations"></a>
                                                </div>
                                    </li>
                                </ul>
                    </div>  
                </div>
        </div>              
</div>

【问题讨论】:

  • 为什么 rootscope 不起作用?你试过什么?
  • 我真的不知道。就好像变量根本不在 rootScope 中一样。

标签: javascript html angularjs angularjs-scope


【解决方案1】:

您必须围绕两个 HTML 片段创建一个控制器:

<div ng-controller="Ctrl">
    <!-- YOUR CODE HERE -->
</div>

控制器将定义位置属性,但另一个对象(我们称之为viewState):

app.controller("Ctrl", function($scope) {
    $scope.viewState = {
        locations: false
    };
};

然后绑定到内部locations

<ul class="menu" ng-show="!viewState.locations">
</ul>
<ul class="menu" ng-show="viewState.locations">
</ul>
...
<a id="details" href="#/details" ng-click="viewState.locations = !viewState.locations">

造成这种情况的原因,以及为什么它不适用于 $rootScope 的原因是作用域如何通过 Javascript 的原型继承来继承其父级的属性。粗略地,真的很快:

当你从一个作用域读取一个属性并且该作用域不包含这个属性时,JS 会查看它的原型(再次非常粗略地说,作用域的父作用域)。链一直延续到$rootScope。因此,将locations 放入$rootScope 将导致成功读取此属性。

每当您将变量写入到作用域时,它都会直接写入该作用域,无论它是从哪里读取的。所以在内部范围内更改locations 对外部范围没有影响(例如$rootScope)。

将变量放入对象中会导致读取对象,解析到正确的范围,然后将属性写入正确的对象。

【讨论】:

  • 谢谢。我有一种感觉(因为我正在搜索有关它的更多信息),我只是不愿意这样做,因为这意味着我使用 angular 的方式本身就是错误的。但再次感谢。我很清楚。
  • 说实话,我不喜欢在视图中混合应用程序逻辑。我总是尝试将逻辑与视图分开。
【解决方案2】:

这就是我最终使用的。这看起来非常简单,但也许它也会帮助其他初学者。这基本上是使值在不同控制器中可访问的代码。如果我理解正确,这与 Nikos 建议的相同。

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

    myApp.value('Pages',{page:"My Profile"});
    myApp.value('Menu',{show:false});
    myApp.value('Menu2',{show2:false});

    myApp.controller('MainMenu', function($scope,Menu,Pages) {
        $scope.menu = Menu;
        $scope.pages = Pages;
    });

    myApp.controller('MainSidebar', function($scope,Menu,Menu2,Pages) {
        $scope.menu = Menu;
        $scope.menu2 = Menu2;
        $scope.pages = Pages;
    });

    myApp.controller('SecondSidebar', function($scope,Menu,Menu2,Pages) {
        $scope.menu = Menu;
        $scope.menu2 = Menu2;
        $scope.pages = Pages;
    });


    myApp.controller('TripsFx', function($scope,Menu2,Pages) {

        $scope.menu2 = Menu2;
        $scope.pages = Pages;
    })

【讨论】:

    【解决方案3】:

    这就是我为拥有一个可访问的 Rootscope 所做的。

    在app.run中设置Rootscope:(别忘了注入$rootScope)

        var myApp = angular.module('ProGen', []);
        myApp.run(function($rootScope) {
          //setup Rootscope
          $rootScope.locations = false;
        })
    

    使用改变 Rootscope 的函数创建一个 Controller(也注入 $rootscope)

        function someCtrl($rootScope, $scope) {
          $scope.travels = [
            {dest: 'Rome'},
            {dest: 'London'}
            ];
    
          $scope.flipMenu = function() {
            $rootScope.locations = !$rootScope.locations;
          }
    
        }
    

    所以这是html:

        <html ng-app>
                {...}
        <body>
          <div id="main_sidebar">
            <ul class="menu" ng-show="!locations">
              <li>x1</li>
              <li>x2</li>
              <li>x3</li>
              <li>x4</li>
            </ul>
            <ul class="menu" ng-show="locations">
              <li>y1</li>
              <li>y2</li>
              <li>y3</li>
              <li>y4</li>
            </ul>
          </div>
    
          <div ng-click="locations =! locations">Change me (no Controller)</div>
    
          <div ng-controller="someCtrl">
            <ul>
              <li ng-repeat="post in travels">
                <div ng-bind="post.dest" ng-click="flipMenu()"></div>
              </li>
            </ul>
          </div>
    
        </body>
    
        </html>
    

    这是 JS:

      var myApp = angular.module('ProGen', []);
      myApp.run(function($rootScope) {
        //setup Rootscope
        $rootScope.locations = false;
      })
    
    function someCtrl($rootScope, $scope) {
      $scope.travels = [
        {dest: 'Rome'},
        {dest: 'London'}
        ];
    
      $scope.flipMenu = function() {
        $rootScope.locations = !$rootScope.locations;
      }
    }
    

    你会在这里找到一个工作的 Plunker:http://plnkr.co/edit/ygLlIoE55aI5q8Wkicc5?p=preview

    不确定这是否是您想要的。但我希望它无论如何都会有所帮助。 (不要对我大喊这是反对 Angular Zen,因为原因:-)

    【讨论】:

    • 感谢您的帮助。我猜我用所谓的工厂解决了这个问题。 :) 问题是使用 $rootScope 和创建具有可访问值的工厂的逻辑基本相同,所以我只是按照我理解的更传统的方式进行。 :) 我试图使用 $rootScope 所以我会避免重写我的角度背后的整个逻辑,但无论如何我必须这样做,所以我为我使用的所有块创建单独的控制器,并在需要的地方传递必要的值.但再次感谢您的努力:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-05
    • 2013-02-14
    • 1970-01-01
    相关资源
    最近更新 更多