AngularJS试图使用ng-click和ng-switch,但ng-switch不能切换我的div



在这里。我有一些全局导航,它使用routeProvider来交换视图内的外部html页面。在视图中,我设置了一个列表类型的子导航(用ng-repeat创建),用于切换外部html文件中的div。如果我在apppctrl:

中手动设置,我可以让它加载页面
//Here I set the initial value
    $scope.page = 'Comfort Homes of Athens';

但是当我点击包含ng-click的span时。我什么也得不到。我开始认为这是一个范围问题,但当我只放一个ng-click='alert()'时,它也不做任何事情。

我读过其他的帖子,但大多数人似乎把一个ng-click放在一个ng-switch里面,而不是相反。在他们的例子中也没有使用路由。仍然是角的新手,所以可能是我还没有遇到过的东西。

HTML应用程序:

<body ng-app="app">
<header ng-include="header.url" ng-controller="nav"></header>
<article ng-view></article>
<footer ng-include="footer.url" ng-controller="nav"></footer>
    <script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular-route.js"></script>
    <script type="text/javascript" src="js/data.js"></script>
    <script type="text/javascript" src="js/model.js"></script>
</body>

外部HTML文件:

<div id="web" class="wrapper">
    <aside class="boxModel">
        <div id="controller" class="container">
            <div class="topBox bluebg subNavBar"><h1 class="white">Projects</h1></div>
            <div ng-controller="nav" id="controls" class="botBox whitebg">
                <span ng-repeat='item in webProjects' ng-click="page='{{item.name}}'">{{item.name}}</span>
            </div>
        </div>
    </aside><section ng-switch on="page" class="boxModel">
        <div ng-switch-when="Comfort Homes of Athens" id="sandbox" class="container round box whitebg">
           <h1>Here is link 1</h1>
        </div>
        <div ng-switch-when="Sealpak Incorporated" id="sandbox" class="container round box whitebg">
            <h1>here is Link 2</h1>
        </div>
    </section>
</div>

JS:

var app = angular.module("app", ["ngRoute"]);
function nav($scope) {
    $scope.templates = templates;
    $scope.header = $scope.templates[0];
    $scope.footer = $scope.templates[1];
    $scope.mainNav = mainNav;
    $scope.footNav = footNav;
}
app.config(function($routeProvider) {
    $routeProvider.when('/',{
        templateUrl: "templates/home.html",
        controller: "AppCtrl"
    }).when('/templates/web.html',{
        templateUrl: "templates/web.html",
        controller: "AppCtrl"
    }).when('/templates/seo.html',{
        templateUrl: "templates/seo.html",
        controller: "AppCtrl"
    }).otherwise({
        template: "This doesn't exist!"
    });
});
app.controller("AppCtrl", function($scope) {
    $scope.webProjects = webProjects;
    $scope.seoProjects = seoProjects;
//Here I set the initial value
    $scope.page = 'Comfort Homes of Athens';
});

不幸的是,ng-repeat创建的子作用域彼此是兄弟姐妹,是父控制器(ng-controller="nav")的子作用域,而ng-switch上的<section>不是您的ng-controller="nav"子作用域,而是AppCtrl

你可以尝试ng-click="$parent.$parent.page=item.name"来理解angular的作用域。

<div id="web" class="wrapper">
<aside class="boxModel">
    <div id="controller" class="container">
        <div class="topBox bluebg subNavBar"><h1 class="white">Projects</h1></div>
        <div ng-controller="nav" id="controls" class="botBox whitebg">
            <span ng-repeat='item in webProjects' ng-click="$parent.$parent.page=item.name">{{item.name}}</span>
        </div>
    </div>
</aside><section ng-switch on="page" class="boxModel">
    <div ng-switch-when="Comfort Homes of Athens" id="sandbox" class="container round box whitebg">
       <h1>Here is link 1</h1>
    </div>
    <div ng-switch-when="Sealpak Incorporated" id="sandbox" class="container round box whitebg">
        <h1>here is Link 2</h1>
    </div>
</section>

我不建议使用这个解决方案,因为它非常丑陋。@link64的解决方案更好,但我认为model的继承是如此的隐式,并创建一个紧密耦合的代码。在这里,我提出了另一个解决方案,我希望通过发出一个事件来更好地解决这个问题:

<span ng-repeat='item in webProjects' ng-click="$emit('pageChange',item.name)">{{item.name}}</span>

我不确定angular是否能够在模板中解析$emit('pageChange',item.name)表达式。如果你遇到任何问题,你可以在你的控制器里面写:

<span ng-repeat='item in webProjects' ng-click="setPageChange(item.name)">{{item.name}}</span>

在你的nav控制器:

$scope.setPageChange = function (pageName) {
         $scope.$emit("pageChange",pageName);
   }

在您的AppCtrl中,监听事件并更新页面。

app.controller("AppCtrl", function($scope) {
    $scope.webProjects = webProjects;
    $scope.seoProjects = seoProjects;
//Here I set the initial value
    $scope.page = 'Comfort Homes of Athens';
    $scope.$on("pageChange", function (event, newPage){
         $scope.page = newPage;
    }
});

除了@KhanhTo的答案,我想给你指出另一个工具来代替ngRoute;UI-Router。这不是你最初问题的答案,但这是一个更好的解决方案,完全避免了你的问题。

UI-Router增强了ngRoute的页面路由,更加以状态为中心。您将过渡到具有模板和可选控制器的状态。它发出自己的事件,如$stateChangeStart$stateChangeSuccess。你可以通过函数command $state.go(stateName)或者指令ui-sref="my.state({name: item.name})来调用这些状态转换

UI-Router是一个非常强大的工具,我不能在这里详细介绍所有的细节,但是它的文档和社区非常棒。

对代码的简单重写可能如下所示。

web.html模板

<div class="wrapper">
    <aside class="boxModel">
        <div id="controller" class="container">
            <div class="topBox bluebg subNavBar"><h1 class="white">Projects</h1></div>
            <div ng-controller="nav" id="controls" class="botBox whitebg">
                <span ng-repeat='item in webProjects' ui-sref="app.web.page({name: {{item.name}})">
                    {{item.name}}
                 </span>
            </div>
        </div>
    </aside> 
    <section class="boxModel">
        <div ui-view class="container round box whitebg">
           <!-- Page content will go here -->
        </div>
    </section>
</div>
JavaScript

app.config(function($stateProvider) {
     $stateProvider
          .state('app', {
            abstract: true,
            template: '<div ui-view></div>', //Basic template 
            controller: "AppCtrl",
        }).state('app.home', {
            templateUrl: "templates/home.html",
            url: '/home'
        }).state('app.web',{
            templateUrl: "templates/web.html",
            url: '/web'
        }).state('app.web.page',{
            templateUrl: "templates/page.web.html",
            url: '/web/page/:name' //Note here the ':' means name will be a parameter in the url
        }).state('app.seo',{
            templateUrl: "templates/seo.html",
            url: '/seo'
        });
    });
app.controller('AppCtrl', function($scope){
    $scope.webProjects = webProjects;
    $scope.seoProjects = seoProjects;
    $scope.$on("$stateChangeStart", function (event, toState, toParams, fromState, fromParams){
        if(newState.name == 'app.web.page'){
            var pageName = newStateParams.name; //Variable name matches 
            $scope.linkText = fetchPageContent(pageName);
        }
    });
});

page.web.html模板
<h1>{{linkText}}</h1>

通过这些更改,您将能够重用控制器的相同实例。除了允许分页内容更具可伸缩性之外。

$scopes

说明

除了$rootScope之外,每个$scope都有一个父级。当您请求视图中的对象时,它将查看其$作用域以查找引用。如果它没有引用,它将遍历到它的父作用域并再次查找。这种情况一直持续到您到达$rootScope。

如果你给视图中的$作用域赋值,它会把它赋值给当前的$作用域,而不是在$作用域链中查找现有的属性。这就是ng-click="model.page = ..."工作的原因;它查找$作用域的变化模型,然后分配给页面属性,而ng-click="page = ..."直接分配给当前$作用域。

控制器重用注意事项

据我所知,ngRoute不支持嵌套视图。当你转到一个新路由时,它会销毁$routeProvider中指定的当前视图和控制器,然后为新视图实例化一个新的控制器。UI-Router支持嵌套状态(即带有child $作用域的子状态)。这允许我们创建一个可以在所有子状态中重用的父控制器。

我认为这可能与对作用域如何工作的一些误解有关。

ng-repeat创建自己的作用域。当尝试设置page时,angular会在ng-repeat的作用域中创建它。

AppCtrl中,按如下方式在作用域上创建对象:

$scope.model = {};
$scope.model.page = 'Comfort Homes of Athens';//Default value

在你的ng-click上,参考model.page而不仅仅是页面。然后,Angular会遍历作用域来找到model.page,而不是仅仅在ng-repeat的局部作用域中创建一个属性。

<span ng-repeat='item in webProjects' ng-click="model.page='{{item.name}}'">{{item.name}}</span>

同时,你的AppCtrl将在每次你改变页面时被重新创建。您可能应该使用服务来保存页面更改之间的状态

相关内容

  • 没有找到相关文章

最新更新