Wiele kontrolerów z AngularJS w aplikacji jednostronicowej


102

Chcę wiedzieć, jak używać wielu kontrolerów dla jednej aplikacji strony. Próbowałem to rozgryźć i znalazłem pytania bardzo podobne do moich, ale jest tylko mnóstwo różnych odpowiedzi rozwiązujących konkretny problem, w którym nie używasz wielu kontrolerów dla jednej aplikacji strony.

Czy to dlatego, że nie byłoby mądrze używać wielu kontrolerów dla jednej strony? A może to po prostu niemożliwe?

Powiedzmy, że mam już niesamowity kontroler karuzeli obrazów działający na stronie głównej, ale potem uczę się (powiedzmy) używać modali i potrzebuję do tego nowego kontrolera (lub czegokolwiek innego, czego potrzebuję). Co wtedy zrobię?

Widziałem odpowiedzi na inne pytania, w których pytają o prawie to samo co ja, a ludzie odpowiadają „* OMG. Dlaczego w ogóle miałbyś to robić, po prostu zrób to ...”.

Jaki jest najlepszy sposób lub jak to robisz?

Edytować

Wielu z was odpowiada, aby po prostu zadeklarować dwa kontrolery, a następnie użyć ng-controller, aby to wywołać. Używam tego fragmentu kodu poniżej, a następnie wywołuję MainCtrl z kontrolerem ng.

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

Dlaczego w ogóle muszę tutaj ustawiać kontroler, skoro mogę po prostu używać ng-kontrolera bez niego? To mnie zdezorientowało. (i myślę, że nie można w ten sposób dodać dwóch kontrolerów ...)


Nie sądzę, żebym mógł zadeklarować 2 kontrolery dla jednego pliku .html? jak to się robi? when: /home, controller: MainCtrl. nie możesz dodać nic więcej, czy też masz na myśli po prostu wywołać to za pomocą kontrolera ng?

3
@Mosho, krok 1, krok 2, gotowe, ale nie wyjaśniaj, jak ani dlaczego. Jeśli to takie proste, wyjaśnij, jak to zrobić. To tak, jakby powiedzieć, użyj AngularJS, Gotowe. czy możesz rozwinąć / wyjaśnić? Albo jak jest od czerwca, mogą nie odpowiadać, czy ktoś inny może to wyjaśnić?
— redfox05

Odpowiedzi:


96

Jaki jest problem? Aby użyć wielu kontrolerów, po prostu użyj wielu dyrektyw ngController:

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

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

Jak zwykle będziesz musiał mieć dostępne kontrolery w module aplikacji.

Najprostszym sposobem, aby to zrobić, może być tak proste, jak zadeklarowanie funkcji kontrolera w następujący sposób:

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

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

2
Czy tak to się robi? Używam tegowhen /home, controller: MainCtrl

8
Jeśli wychodzisz z przykładów, które umieszczają „ng-app” w każdym DIV obok „ng-controller”, spróbuj przenieść tylko jedną „ng-app” do tagu „body” (i usuń element „per-div” ng-app ”), jeśli działa tylko twój pierwszy kontroler. (Pamiętam to z moich dni początkujących w Angular.)
— ftexperts

1
Jedynym problemem, jaki miałem z używaniem ng-controllerw wielu elementach DOM, jest scenariusz, w którym mam WIELE elementów drukujących do DOM za pośrednictwem ng-repeat. Powiedzmy, że każdy z nich nawiązuje połączenie ng-controller="myController. Z niektórych dzienników konsoli, które widziałem w mojej aplikacji, myControllerinicjuje się ponownie, gdy KAŻDY element jest renderowany w DOM, który go wywołuje ... Może coś spieprzyłem w moim konkretnym zastosowaniu, a może poza zakresem OP pytanie, ale ciekawi, czy inni też tego doświadczyli ...
— twknab

91

Myślę, że brakuje Ci znaczenia „aplikacja pojedynczej strony”.

Nie oznacza to, że będziesz mieć fizycznie jeden index.htmlplik .html, zamiast tego będziesz mieć jeden plik główny i kilka ZGNIEŻDZONYCH .html. Dlaczego więc aplikacja z jedną stroną? Ponieważ w ten sposób nie ładujesz stron w standardowy sposób (tj. Wywołanie przeglądarki, które całkowicie odświeża całą stronę), ale po prostu ładujesz część treści za pomocą Angular / Ajax. Ponieważ nie widzisz migotania między zmianami strony, masz wrażenie, że nie ruszyłeś się ze strony. W ten sposób czujesz się, jakbyś przebywał na jednej stronie.

Teraz zakładam, że chcesz mieć WIELE treści dla swojej aplikacji JEDNOSTRONNE: (np.) Dom, kontakty, portfolio i sklep. Twoja pojedyncza strona / aplikacja zawierająca wiele treści (w sposób kątowy) zostanie zorganizowana w ten sposób:

  • index.html: zawiera nagłówek <ng-view>i stopkę
  • contacts.html: zawiera formularz kontaktowy (bez nagłówka, bez stopki)
  • portfolio.html: zawiera dane portfela (bez nagłówka bez stopki)
  • store.html: zawiera sklep, bez nagłówka, bez stopki.

Jesteś w indeksie, klikasz na menu o nazwie "kontakty" i co się dzieje? Angular zastępuje <ng-view>tag contacts.htmlkodem

Jak to osiągasz? z ngRoute, jak to robisz, będziesz miał coś takiego:

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

Spowoduje to wywołanie odpowiedniego kodu HTML i przekazanie do niego odpowiedniego kontrolera (uwaga: nie określaj ng-controllerdyrektywy w, contacts.htmljeśli używasz tras )

Następnie możesz oczywiście zadeklarować tyle dyrektyw ng-controller na swojej stronie contacts.html. Będą to dzieci-kontrolerzy ContactCtrl(w ten sposób dziedziczący po nim). Ale dla pojedynczej trasy, wewnątrz routeProvider, możesz zadeklarować pojedynczego Kontrolera, który będzie działał jako „Ojciec kontroler częściowego widoku”.

EDYCJA Wyobraź sobie następujące szablony / contacts.html

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

powyższe routeProviderspowoduje wstrzyknięcie kontrolera do zawierającego div. Zasadniczo powyższy html automatycznie staje się:

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

Kiedy mówię, że możesz mieć inne kontrolery, oznacza to, że możesz podłączyć kontrolery do wewnętrznych elementów DOM, w następujący sposób:

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

Mam nadzieję, że to trochę wyjaśnia sprawę.

ZA


Więc jeśli zadeklarujesz np. <div ng-controller="FancyStuffController">Wewnątrz tagu body, do którego jest już dołączony kontroler, np. <body ng-controller="BodyController">To zadziała? Otrzymuję błędy o tym, $apply already in progresskiedy to robię, ale myślę, że jest to związane z dpd.js. Nie wchodząc w to, myślę, że po prostu ładuje go dwa razy lub coś w tym stylu, nie wiem jak, ale moje użycie kontrolera może próbować to przeładować.
— blamb

1
@BrianThomas Jasne, to powinno działać. Uważaj: jeśli chcesz wstawić kontroler do widoku, użyj $ routeProvider, nie pisz ng-controller na znaczniku div.
— Adhara

9

Obecnie jestem w trakcie tworzenia aplikacji jednostronicowej. Oto, co mam do tej pory, co moim zdaniem byłoby odpowiedzią na twoje pytanie. Mam szablon podstawowy (base.html), który zawiera element div z ng-viewdyrektywą w nim. Ta dyrektywa mówi angularowi, gdzie umieścić nową zawartość. Zauważ, że sam jestem nowy w angularjs, więc w żadnym wypadku nie mówię, że to najlepszy sposób na zrobienie tego.

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>

w istocie używam również ng-view, więc mogę używać main.html w moim index.html. ale masz / home i / about, a dwa kontrolery są dla każdego z nich. Mam tylko index.html z widokiem ng do mojego main.html. Mogę ustawić dwa kontrolery dla main.html, tak jak to zrobiłeśwhen /home

Spójrz na pierwszą odpowiedź z tego postu: stackoverflow.com/questions/17354568/…
— Austin

cóż, wiem, jak ustawić więcej when. Potrzebuję dwóch kontrolerów dla jednego szablonu. Albo może źle zrozumiałem, co próbujesz mi powiedzieć?

Zamiast używać kontrolerów spróbuj użyć dyrektyw. W jednym szablonie można użyć wielu dyrektyw. Jeśli nadal chcesz używać swoich kontrolerów, oto film pokazujący,
— 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 ma dostęp do menu div. A widgetController ma dostęp do obu.


Wydaje się to proste, ale nie ma pozytywnych głosów. Czy to najlepsza praktyka, czy zła?
— redfox05

1
co zrobisz, jeśli masz wiele stron ponad 100 kontrolerów! ... niejednoznaczna praktyka.
— ArifMustafa

3

Możemy po prostu zadeklarować więcej niż jeden kontroler w tym samym module. Oto przykład:

  <!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

Po prostu umieściłem jedną prostą deklarację aplikacji

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

Następnie zbudowałem jedną usługę i dwa kontrolery

Dla każdego kontrolera miałem wiersz w JS

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

W kodzie HTML zadeklarowałem zakres aplikacji w otaczającym go div

<div ng-app="app">

i każdy zakres kontrolera osobno w swoim własnym otaczającym div (w aplikacji div)

<div ng-controller="EditableRowCtrl">

To działało dobrze


0

Możesz także osadzić wszystkie widoki szablonu w głównym pliku HTML. Na przykład:

<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>

W ten sposób, jeśli każdy szablon wymaga innego kontrolera, nadal możesz używać routera kątowego. Zobacz ten działający przykład http://plnkr.co/edit/9X0fT0Q9MlXtHVVQLhgr?p=preview

W ten sposób, gdy aplikacja zostanie wysłana z serwera do klienta, jest całkowicie samowystarczalna przy założeniu, że nie musi wysyłać żadnych żądań danych itp.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.