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

TarkaDaal
źródło
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
}
J. Bruni
źródło
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

Adhara
źródło
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>
Austin
źródło
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.

Muhammad Awais
źródło
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>
Abdallah Okasha
źródło
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

pat capozzi
źródło
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.

Daimonos
źródło