คอนโทรลเลอร์หลายตัวพร้อม AngularJS ในแอพหน้าเดียว


102

ฉันต้องการทราบวิธีการใช้คอนโทรลเลอร์หลายตัวสำหรับแอปพลิเคชันหน้าเดียว ฉันพยายามคิดออกและพบคำถามที่คล้ายกับของฉันมาก แต่มีคำตอบที่แตกต่างกันมากมายในการแก้ปัญหาเฉพาะที่คุณไม่ได้ใช้คอนโทรลเลอร์หลายตัวสำหรับแอปหน้าเดียว

นั่นเป็นเพราะการใช้ตัวควบคุมหลายตัวในหน้าเดียวคงไม่เป็นการดีใช่หรือไม่? หรือมันเป็นไปไม่ได้?

สมมติว่าฉันมีตัวควบคุมภาพหมุนแบบเตะตูดที่ทำงานในหน้าหลักแล้ว แต่จากนั้นฉันก็เรียนรู้วิธี (สมมติว่า) ใช้โมดอลและฉันต้องการตัวควบคุมใหม่สำหรับสิ่งนั้นเช่นกัน (หรือสิ่งอื่นใดที่ฉันต้องการตัวควบคุม) แล้วฉันจะทำอะไร?

ฉันเคยเห็นคำตอบของคำถามอื่น ๆ ที่พวกเขาถามเกือบจะเหมือนกับฉันและมีคนตอบว่า "* OMG ทำไมคุณถึงทำอย่างนั้นเพียงแค่ทำสิ่งนี้ ... "

วิธีที่ดีที่สุดคืออะไรหรือทำอย่างไร?

แก้ไข

หลาย ๆ ท่านกำลังตอบรับเพียงแค่ประกาศคอนโทรลเลอร์สองตัวจากนั้นใช้ ng-controller เพื่อเรียกใช้งาน ฉันใช้โค้ดด้านล่างนี้แล้วเรียก MainCtrl ด้วย ng-controller

app.config(function($routeProvider, $locationProvider) {                        
  $routeProvider                                                                
       .when('/', {                                            
         templateUrl: "templates/main.html",                                               
         controller:'MainCtrl',                                
        })                                                                      
        .otherwise({                      
            template: 'does not exists'   
        });      
});

ทำไมฉันถึงต้องตั้งคอนโทรลเลอร์ที่นี่ถ้าฉันสามารถใช้ ng-controller ได้โดยไม่ต้องใช้มัน นี่คือสิ่งที่ทำให้ฉันสับสน (และคุณไม่สามารถเพิ่มตัวควบคุมสองตัวด้วยวิธีนี้ฉันคิดว่า ... )


ฉันไม่คิดว่าฉันสามารถประกาศคอนโทรลเลอร์ 2 ตัวสำหรับไฟล์. html เดียวได้หรือไม่ เป็นอย่างไรบ้าง? when: /home, controller: MainCtrl. ไม่สามารถเพิ่มอะไรได้มากกว่านั้นหรือคุณหมายถึงแค่เรียกมันด้วย ng-controller?

3
@ โมโชคุณขั้นที่ 1 ขั้นตอนที่ 2 เสร็จแล้ว แต่ไม่อธิบายว่าทำอย่างไรหรือทำไม ถ้ามันง่ายขนาดนั้นโปรดอธิบายว่า เหมือนกับการพูดว่าใช้ AngularJS เสร็จแล้ว อธิบาย / อธิบายได้ไหม หรือตั้งแต่เดือนมิถุนายนพวกเขาอาจไม่ตอบกลับคนอื่นช่วยอธิบายได้ไหม
redfox05

คำตอบ:


96

อะไรคือปัญหา? ในการใช้คอนโทรลเลอร์หลายตัวให้ใช้คำสั่ง ngController หลายตัว:

<div class="widget" ng-controller="widgetController">
    <p>Stuff here</p>
</div>

<div class="menu" ng-controller="menuController">
    <p>Other stuff here</p>
</div>

คุณจะต้องมีตัวควบคุมในโมดูลแอปพลิเคชันของคุณตามปกติ

วิธีพื้นฐานที่สุดในการทำเช่นนี้อาจทำได้ง่ายๆเพียงแค่ประกาศฟังก์ชันคอนโทรลเลอร์ดังนี้:

function widgetController($scope) {
   // stuff here
}

function menuController($scope) {
   // stuff here
}

2
นี่คือวิธีการทำ? ฉันใช้ที่when /home, controller: MainCtrl

8
หากคุณนำตัวอย่างที่ใส่ "ng-app" ไว้ในแต่ละ DIV ถัดจาก "ng-controller" ของคุณให้ลองย้าย "ng-app" เพียงตัวเดียวไปที่แท็ก "body" (และลบต่อ div " ng-app ") หากมีเพียงคอนโทรลเลอร์แรกของคุณเท่านั้นที่ใช้งานได้ (ฉันจำสิ่งนี้ได้ตั้งแต่สมัยยังเป็นมือใหม่ของ Angular)
ftexperts

1
ปัญหาเดียวที่ฉันเคยกับการใช้ng-controllerในองค์ประกอบ DOM หลายคือพูดในสถานการณ์ที่ฉันมีหลายรายการที่พิมพ์ไป DOM ng-repeatผ่าน ng-controller="myControllerสมมติว่าแต่ละเหล่านี้ทำให้การเรียกไปยัง จากบันทึกคอนโซลบางส่วนที่ฉันเคยเห็นในแอปพลิเคชันของฉันmyControllerเริ่มต้นใหม่ด้วยองค์ประกอบ EACH ที่แสดงผลใน DOM ที่เรียกใช้ .... บางทีฉันอาจทำบางอย่างผิดพลาดในการใช้งานเฉพาะของฉันหรืออาจเกินขอบเขตของ OP แต่อยากรู้ว่าคนอื่น ๆ เคยมีประสบการณ์แบบนั้นหรือ
เปล่า

91

ฉันคิดว่าคุณไม่มีความหมาย "แอปหน้าเดียว"

นั่นไม่ได้หมายความว่าคุณจะมี. html เพียงไฟล์เดียว แต่คุณจะมีไฟล์หลักหนึ่งindex.htmlไฟล์และไฟล์. html หลายไฟล์ ทำไมแอปหน้าเดียว? เนื่องจากวิธีนี้คุณไม่ได้โหลดหน้าด้วยวิธีมาตรฐาน (เช่นการเรียกเบราว์เซอร์ที่รีเฟรชหน้าเต็มทั้งหมด) แต่คุณเพิ่งโหลดส่วนเนื้อหาโดยใช้ Angular / Ajax เนื่องจากคุณไม่เห็นการกะพริบระหว่างการเปลี่ยนแปลงของหน้าคุณจึงรู้สึกว่าคุณไม่ได้ย้ายออกจากหน้า ดังนั้นคุณรู้สึกเหมือนอยู่ในหน้าเดียว

ตอนนี้ฉันสมมติว่าคุณต้องการมีหลายเนื้อหาสำหรับแอป SINGLE PAGE ของคุณ: (เช่น) บ้านรายชื่อผลงานและร้านค้า แอปเนื้อหาหน้าเดียว / หลายหน้าของคุณ (ทางเชิงมุม) จะได้รับการจัดระเบียบดังนี้:

  • index.html: มีส่วนหัว<ng-view>และส่วนท้าย
  • contacts.html: มีแบบฟอร์มการติดต่อ (ไม่มีส่วนหัวไม่มีส่วนท้าย)
  • portfolio.html: มีข้อมูลพอร์ตโฟลิโอ (ไม่มีส่วนหัวไม่มีส่วนท้าย)
  • store.html: มีร้านค้าไม่มีส่วนหัวไม่มีส่วนท้าย

คุณอยู่ในดัชนีคุณคลิกที่เมนูที่เรียกว่า "รายชื่อ" แล้วจะเกิดอะไรขึ้น? Angular แทนที่<ng-view>แท็กด้วยcontacts.htmlโค้ด

คุณจะบรรลุสิ่งนั้นได้อย่างไร? ด้วยngRouteในขณะที่คุณกำลังทำคุณจะมีสิ่งที่ชอบ:

app.config(function($routeProvider, $locationProvider) {                        
  $routeProvider                                                                
       .when('/', {                                            
         templateUrl: "templates/index.html",                                               
         controller:'MainCtrl',                                
        })
        .when('/contacts', {                                            
         templateUrl: "templates/contacts.html",                                               
         controller:'ContactsCtrl',                                
        })                                                                 
        .otherwise({                      
            template: 'does not exists'   
        });      
});

สิ่งนี้จะเรียก html ที่ถูกต้องผ่านตัวควบคุมที่ถูกต้องไป (โปรดทราบ: อย่าระบุng-controllerคำสั่งในcontacts.htmlกรณีที่คุณใช้เส้นทาง )

จากนั้นคุณสามารถประกาศคำสั่ง ng-controller ได้มากเท่าในหน้า contacts.html ของคุณ สิ่งเหล่านี้จะเป็นผู้ควบคุมลูกของContactCtrl(ซึ่งสืบทอดมาจากมัน) แต่สำหรับเส้นทางเดียวrouteProviderคุณสามารถประกาศ Controller ตัวเดียวที่จะทำหน้าที่เป็น "Father controller of the partial view"

แก้ไขลองนึกภาพแม่แบบ / contacts.html ต่อไปนี้

<div>
    <h3>Contacts</h3>
    <p>This is contacts page...</p>
</div>

ข้างต้นrouteProviderจะฉีดคอนโทรลเลอร์ลงใน div ที่มีของคุณ โดยทั่วไป html อัตโนมัติข้างต้นจะกลายเป็น:

<div ng-controller="ContactsCtrl">
    <h3>Contacts</h3>
    <p>This is contacts page...</p>
</div>

เมื่อฉันบอกว่าคุณสามารถมีคอนโทรลเลอร์อื่นได้หมายความว่าคุณสามารถเสียบคอนโทรลเลอร์เข้ากับองค์ประกอบ DOM ภายในได้ดังต่อไปนี้:

<div>
    <h3>Contacts</h3>
    <p ng-controller="anotherCtrl">Hello {{name}}! This is contacts page...     
    </p>
</div>

ฉันหวังว่าสิ่งนี้จะให้ความกระจ่าง


ดังนั้นถ้าคุณประกาศเช่น<div ng-controller="FancyStuffController">ในแท็กร่างกายที่มีตัวควบคุมบังคับอยู่แล้วเช่น<body ng-controller="BodyController">จะได้ผล? ฉันได้รับข้อผิดพลาด$apply already in progressเมื่อฉันทำสิ่งนี้ แต่ฉันคิดว่ามันเกี่ยวข้องกับ dpd.js เพื่อไม่ให้เข้าไปในนั้นฉันคิดว่ามันแค่โหลดสองครั้งหรือบางอย่างไม่แน่ใจว่าเป็นอย่างไร แต่การใช้คอนโทรลเลอร์ของฉันอาจพยายามโหลดซ้ำ
ตำหนิ

1
@BrianThomas แน่นอนว่าน่าจะได้ผล ระวัง: หากคุณต้องการฉีดคอนโทรลเลอร์ในมุมมองให้ใช้ $ routeProvider อย่าเขียน ng-controller บนแท็ก div
Adhara

9

ฉันกำลังอยู่ในขั้นตอนการสร้างแอปพลิเคชันแบบหน้าเดียว นี่คือสิ่งที่ฉันมีจนถึงตอนนี้ซึ่งฉันเชื่อว่าจะตอบคำถามของคุณได้ ฉันมีเทมเพลตพื้นฐาน (base.html) ที่มี div พร้อมng-viewคำสั่งอยู่ในนั้น คำสั่งนี้จะบอกตำแหน่งเชิงมุมที่จะนำเนื้อหาใหม่เข้ามาโปรดทราบว่าฉันยังใหม่กับ angularjs ด้วยตัวเองดังนั้นฉันจึงไม่ได้บอกว่านี่เป็นวิธีที่ดีที่สุดที่จะทำ

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

app.config(function($routeProvider, $locationProvider) {                        
  $routeProvider                                                                
       .when('/home/', {                                            
         templateUrl: "templates/home.html",                                               
         controller:'homeController',                                
        })                                                                      
        .when('/about/', {                                       
            templateUrl: "templates/about.html",     
            controller: 'aboutController',  
        }) 
        .otherwise({                      
            template: 'does not exists'   
        });      
});

app.controller('homeController', [              
    '$scope',                              
    function homeController($scope,) {        
        $scope.message = 'HOME PAGE';                  
    }                                                
]);                                                  

app.controller('aboutController', [                  
    '$scope',                               
    function aboutController($scope) {        
        $scope.about = 'WE LOVE CODE';                       
    }                                                
]); 

base.html

<html>
<body>

    <div id="sideMenu">
        <!-- MENU CONTENT -->
    </div>

    <div id="content" ng-view="">
        <!-- Angular view would show here -->
    </div>

<body>
</html>

แน่นอนฉันยังใช้ ng-view เพื่อที่ฉันจะสามารถใช้ main.html ใน index.html ของฉันได้ แต่คุณมี / home และ / about และตัวควบคุมสองตัวนั้นมีไว้สำหรับแต่ละตัว ฉันมีเพียง index.html ที่มี ng-view ไปยัง main.html ของฉัน ฉัน cannet ตั้งค่าตัวควบคุมสองตัวสำหรับ main.html เหมือนที่คุณทำกับwhen /home

ดูคำตอบแรกจากโพสต์นี้: stackoverflow.com/questions/17354568/…
Austin

ดีฉันรู้วิธีการตั้งค่าอื่น ๆ อีกมากมายwhen's ฉันต้องการตัวควบคุมสองตัวสำหรับเทมเพลตเดียว หรือ maby ฉันเข้าใจผิดในสิ่งที่คุณพยายามจะบอกฉัน?

แทนที่จะใช้คอนโทรลเลอร์ให้ลองใช้คำสั่ง คุณสามารถใช้หลายคำสั่งในเทมเพลตเดียว หากคุณยังต้องการใช้คอนโทรลเลอร์ของคุณนี่คือวิดีโอเกี่ยวกับวิธีที่คำสั่งสามารถเชื่อมโยงกับคอนโทรลเลอร์: egghead.io/lessons/angularjs-directives-talking-to-controllers
Austin

6
<div class="widget" ng-controller="widgetController">
    <p>Stuff here</p>
</div>

<div class="menu" ng-controller="menuController">
    <p>Other stuff here</p>
</div>
///////////////// OR ////////////


  <div class="widget" ng-controller="widgetController">
    <p>Stuff here</p>
    <div class="menu" ng-controller="menuController">
        <p>Other stuff here</p>
    </div>
</div>

menuController สามารถเข้าถึงเมนู div และ widgetController สามารถเข้าถึงได้ทั้งสองอย่าง


ดูเหมือนจะตรงไปตรงมา แต่ไม่มีการโหวตเพิ่ม แนวทางปฏิบัติที่ดีที่สุดหรือไม่ดี?
redfox05

1
คุณจะทำอะไรถ้าคุณมีคอนโทรลเลอร์มากกว่า 100 หน้า! ...
ArifMustafa

3

เราสามารถประกาศ Controller มากกว่าหนึ่งตัวในโมดูลเดียวกันได้ นี่คือตัวอย่าง:

  <!DOCTYPE html>
    <html>

    <head>
       <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js">
       </script>
      <title> New Page </title>


    </head> 
    <body ng-app="mainApp"> <!-- if we remove ng-app the add book button [show/hide] will has no effect --> 
      <h2> Books </h2>

    <!-- <input type="checkbox" ng-model="hideShow" ng-init="hideShow = false"></input> -->
    <input type = "button" value = "Add Book"ng-click="hideShow=(hideShow ? false : true)"> </input>
     <div ng-app = "mainApp" ng-controller = "bookController" ng-if="hideShow">
             Enter book name: <input type = "text" ng-model = "book.name"><br>
             Enter book category: <input type = "text" ng-model = "book.category"><br>
             Enter book price: <input type = "text" ng-model = "book.price"><br>
             Enter book author: <input type = "text" ng-model = "book.author"><br>


             You are entering book: {{book.bookDetails()}}
     </div>

    <script>
             var mainApp = angular.module("mainApp", []);

             mainApp.controller('bookController', function($scope) {
                $scope.book = {
                   name: "",
                   category: "",
                   price:"",
                   author: "",


                   bookDetails: function() {
                      var bookObject;
                      bookObject = $scope.book;
                      return "Book name: " + bookObject.name +  '\n' + "Book category: " + bookObject.category + "  \n" + "Book price: " + bookObject.price + "  \n" + "Book Author: " + bookObject.author;
                   }

                };
             });
    </script>

    <h2> Albums </h2>
    <input type = "button" value = "Add Album"ng-click="hideShow2=(hideShow2 ? false : true)"> </input>
     <div ng-app = "mainApp" ng-controller = "albumController" ng-if="hideShow2">
             Enter Album name: <input type = "text" ng-model = "album.name"><br>
             Enter Album category: <input type = "text" ng-model = "album.category"><br>
             Enter Album price: <input type = "text" ng-model = "album.price"><br>
             Enter Album singer: <input type = "text" ng-model = "album.singer"><br>


             You are entering Album: {{album.albumDetails()}}
     </div>

    <script>
             //no need to declare this again ;)
             //var mainApp = angular.module("mainApp", []);

             mainApp.controller('albumController', function($scope) {
                $scope.album = {
                   name: "",
                   category: "",
                   price:"",
                   singer: "",

                   albumDetails: function() {
                      var albumObject;
                      albumObject = $scope.album;
                      return "Album name: " + albumObject.name +  '\n' + "album category: " + albumObject.category + "\n" + "Book price: " + albumObject.price + "\n" + "Album Singer: " + albumObject.singer;
                   }
                };
             });
    </script>

    </body>
    </html>

2

ฉันแค่ใส่คำประกาศง่ายๆของแอพเดียว

var app = angular.module("app", ["xeditable"]);

จากนั้นฉันก็สร้างหนึ่งบริการและตัวควบคุมสองตัว

สำหรับคอนโทรลเลอร์แต่ละตัวฉันมีบรรทัดใน JS

app.controller('EditableRowCtrl', function ($scope, CRUD_OperService) {

และใน HTML ฉันประกาศขอบเขตแอปใน div โดยรอบ

<div ng-app="app">

และขอบเขตตัวควบคุมแต่ละตัวแยกกันใน div รอบข้างของตัวเอง (ภายในแอพ div)

<div ng-controller="EditableRowCtrl">

สิ่งนี้ใช้ได้ดี


0

คุณยังสามารถฝังมุมมองเทมเพลตทั้งหมดของคุณลงในไฟล์ html หลักของคุณได้ ตัวอย่างเช่น:

<body ng-app="testApp">
  <h1>Test App</h1>
  <div ng-view></div>
  <script type = "text/ng-template" id = "index.html">
    <h1>Index Page</h1>
    <p>{{message}}</p>
  </script>
  <script type = "text/ng-template" id = "home.html">
    <h1>Home Page</h1>
    <p>{{message}}</p>
  </script>
</body>

ด้วยวิธีนี้หากแต่ละเทมเพลตต้องการคอนโทรลเลอร์ที่แตกต่างกันคุณยังสามารถใช้เราเตอร์เชิงมุมได้ ดูตัวอย่างการใช้งาน http://plnkr.co/edit/9X0fT0Q9MlXtHVVQLhgr?p=preview

วิธีนี้เมื่อแอปพลิเคชันถูกส่งจากเซิร์ฟเวอร์ไปยังไคลเอนต์ของคุณแอปพลิเคชันจะอยู่ในตัวเองโดยสมบูรณ์โดยสมมติว่าไม่จำเป็นต้องร้องขอข้อมูลใด ๆ เป็นต้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.