AngularJS尝试使用ng-click和ng-switch,但是ng-switch没有切换我的div

时间:2014-08-06 01:53:45

标签: angularjs angularjs-ng-repeat angularjs-routing angularjs-ng-click ng-switch

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

//Here I set the initial value
    $scope.page = 'Comfort Homes of Athens';

但是当我点击具有ng-click的范围时。我一无所获。我开始认为这是一个范围问题,但是当我只放了一个ng-click =' alert()'它什么也没做。

我已阅读其他帖子,但大多数似乎都是在ng-switch内部进行ng-click而不是相反。并且他们的例子中也没有使用路由。角度还是新的,也许是我还没遇到过的东西。

应用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';
});

3 个答案:

答案 0 :(得分:4)

不幸的是,ng-repeat创建了子级范围,这些范围是父级控制器(ng-controller="nav")的父级控制器(<section>)的兄弟姐妹,而ng-switch所在的ng-controller="nav" < strong>不是 AppCtrl的子范围,但是ng-click="$parent.$parent.page=item.name"

您可以尝试<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> 只是为了理解角度范围。

model

我不推荐使用此解决方案,因为它非常难看。 @ link64的解决方案更好,但我认为<span ng-repeat='item in webProjects' ng-click="$emit('pageChange',item.name)">{{item.name}}</span> 的继承是如此隐式并创建一个紧密耦合的代码。在这里,我提出另一个解决方案,我希望通过发布一个事件来更好:

$emit('pageChange',item.name)

我不确定angular是否能够解析模板中的<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; } }); 中,收听活动并更新页面。

{{1}}

答案 1 :(得分:1)

除了@ KhanhTo的答案之外,我还想指出你使用另一种工具来代替ngRoute; UI的路由器。这不是您原始问题的答案,但它是一个更好的解决方案,完全避免您的问题。

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都有一个父级。当您在视图中请求对象时,它将查看其$ scope以查找引用。如果它没有引用,它将遍历到其父作用域并再次查看。这种情况发生在你到达$ rootScope之前。

如果在视图中为$ scope分配内容,它会将其分配给当前的$ scope,而不是搜索现有属性的$ scope链。这就是ng-click="model.page = ..."有效的原因;它查找模型的$ scope chaing然后分配给页面属性,而ng-click="page = ..."直接分配给当前的$ scope。

关于控制器重复使用的注意事项

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

答案 2 :(得分:-1)

我认为这可能与对范围如何运作的误解有关。

ng-repeat创建自己的范围。尝试设置page时,angular会在ng-repeat的范围内创建它。

AppCtrl中,在范围内创建一个对象,如下所示:

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

点击后,请参阅model.page而不是页面。然后,Angular将遍历范围以查找model.page,而不是仅在ng-repeat的本地范围内创建属性。

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

此外,每次更改页面时都会重新创建AppCtrl。您可能应该使用服务在页面更改之间保持状态