Controller multipli con AngularJS in un'app a pagina singola


102

Voglio sapere come utilizzare più controller per un'applicazione a pagina singola. Ho provato a capirlo e ho trovato domande molto simili alle mie, ma ci sono solo un sacco di risposte diverse che risolvono un problema specifico in cui finisci per non utilizzare più controller per un'app a pagina singola.

È perché non sarebbe saggio utilizzare più controller per una singola pagina? O semplicemente non è possibile?

Diciamo che ho già un controller carousel di immagini kick-ass funzionante nella pagina principale, ma poi imparo come (diciamo) usare i modali e ho bisogno di un nuovo controller anche per quello (o qualsiasi altra cosa di cui ho bisogno un controller). Cosa farò allora?

Ho visto alcune risposte ad altre domande in cui chiedono quasi le stesse cose di me e le persone rispondono "* OMG. Perché dovresti farlo, fallo e basta ...".

Qual è il modo migliore o come lo fai?

modificare

Molti di voi stanno rispondendo solo per dichiarare due controller e poi usano ng-controller per chiamarlo. Uso questo bit di codice di seguito e quindi chiamo MainCtrl con ng-controller.

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

Perché ho anche bisogno di impostare un controller qui se posso semplicemente usare ng-controller senza di esso? Questo è ciò che mi ha confuso. (e non puoi aggiungere due controller in questo modo, penso ...)


Non penso di poter dichiarare 2 controller per un singolo file .html? come si fa? when: /home, controller: MainCtrl. non posso aggiungere altro, o du intendi chiamarlo semplicemente con ng-controller?

3
@ Mosho, passaggio 1, passaggio 2, fatto, ma non spiegare come o perché. Se è così semplice, spiega come. È come dire usa AngularJS, Fatto. puoi elaborare / spiegare? O poiché è di giugno, potrebbero non rispondere, qualcun altro può spiegare?
redfox05

Risposte:


96

Qual è il problema? Per utilizzare più controller, basta utilizzare più direttive ngController:

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

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

Dovrai avere i controller disponibili nel modulo dell'applicazione, come al solito.

Il modo più semplice per farlo potrebbe essere semplice come dichiarare le funzioni del controller in questo modo:

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

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

2
È così che si fa? Lo sto usandowhen /home, controller: MainCtrl

8
Se stai uscendo da esempi che mettono "ng-app" in ogni DIV accanto al tuo "ng-controller", prova a spostare solo un "ng-app" nel tag "body" (ed elimina il per-div " ng-app ") se funziona solo il primo controller. (Ricordo questo dai miei giorni da
novellino

1
L'unico problema che ho riscontrato con l'utilizzo ng-controllerdi più elementi DOM è stato, ad esempio, uno scenario in cui MOLTI elementi vengono stampati sul DOM tramite ng-repeat. Diciamo che ognuno di questi fa una chiamata a ng-controller="myController. Da alcuni dei registri della console che ho visto nella mia applicazione, myControllersi reinizializza con OGNI elemento renderizzato nel DOM che lo chiama ... Forse ho sbagliato qualcosa nel mio utilizzo particolare, o forse oltre lo scopo degli OP domanda, ma sono curioso di
sapere

91

Penso che ti manchi il significato di "app a pagina singola".

Ciò non significa che ne avrai fisicamente un .html, ma ne avrai uno principale index.html file .html e diversi .html NESTED. Allora perché app a pagina singola? Perché in questo modo non carichi le pagine nel modo standard (cioè la chiamata del browser che aggiorna completamente la pagina intera) ma carichi solo la parte del contenuto usando Angular / Ajax. Dato che non vedi lo sfarfallio tra i cambi di pagina, hai l'impressione di non esserti mosso dalla pagina. Quindi, ti senti come se fossi su una singola pagina.

Ora, presumo che tu voglia avere più contenuti per la tua app a PAGINA SINGOLA: (es. Casa, contatti, portfolio e negozio. La tua app a pagina singola / a più contenuti (in modo angolare) sarà organizzata in questo modo:

  • index.html: contiene intestazione <ng-view>e piè di pagina
  • contacts.html: contiene il modulo di contatto (senza intestazione, senza piè di pagina)
  • portfolio.html: contiene i dati del portfolio (nessuna intestazione, nessun piè di pagina)
  • store.html: contiene il negozio, nessuna intestazione né piè di pagina.

Sei in indice, fai clic sul menu denominato "contatti" e cosa succede? Angular sostituisce il <ng-view>tag con il contacts.htmlcodice

Come ci riesci? con ngRoute, mentre stai facendo, avrai qualcosa come:

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

Questo chiamerà l'html giusto passandogli il controller giusto (nota: non specificare la ng-controllerdirettiva in contacts.htmlse stai usando rotte )

Quindi, ovviamente, puoi dichiarare quante più direttive ng-controller all'interno della tua pagina contatti.html. Quelli saranno i controllori figlio di ContactCtrl(ereditando quindi da esso). Ma per una singola route, all'interno di routeProvider, è possibile dichiarare un solo Controller che fungerà da "Controller padre della vista parziale".

MODIFICA Immagina i seguenti modelli / contatti.html

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

quanto sopra routeProviderinietterà un controller nel tuo div contenitore. Fondamentalmente l'html sopra diventa automaticamente:

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

Quando dico che puoi avere altri controller, significa che puoi collegare i controller agli elementi DOM interni, come segue:

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

Spero che questo chiarisca un po 'le cose.

UN


Quindi se dichiari un esempio <div ng-controller="FancyStuffController">all'interno di un tag body a cui è già applicato un controller, ad esempio <body ng-controller="BodyController">, funzionerà? $apply already in progressottengo errori su quando lo faccio, ma penso che sia correlato a dpd.js. Non per entrare in questo, penso che sia solo caricarlo due volte o qualcosa del genere, non sono sicuro di come, ma il mio utilizzo del controller potrebbe provare a ricaricarlo.
blamb

1
@BrianThomas Certo, dovrebbe funzionare. Attenzione: se vuoi iniettare un controller in una vista, usa $ routeProvider, non scrivere ng-controller sul tag div.
Adhara

9

Attualmente sto creando un'applicazione a pagina singola. Ecco cosa ho finora che credo possa rispondere alla tua domanda. Ho un modello di base (base.html) che ha un div con la ng-viewdirettiva in esso. Questa direttiva dice ad angular dove inserire il nuovo contenuto. Si noti che io stesso sono nuovo ad angularjs, quindi non sto affatto dicendo che questo è il modo migliore per farlo.

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>

in effetti, sto anche usando ng-view in modo da poter usare un main.html nel mio index.html. ma hai / home e / about ei due controller sono per ciascuno. Ho solo index.html con ng-view nel mio main.html. Non posso impostare due controller per main.html come hai fatto conwhen /home

Dai un'occhiata alla prima risposta da questo post: stackoverflow.com/questions/17354568/…
Austin

beh, so come impostare di più when. Voglio due controller per un unico modello. O maby ho frainteso quello che stavi cercando di dirmi?

Invece di usare i controller, prova a usare le direttive. Puoi usare molte direttive su un singolo modello. Se vuoi ancora usare i tuoi controller, ecco un video su come le direttive possono collegarsi ai controller: 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 ha accesso per menu div. E widgetController ha accesso a entrambi.


Sembra semplice, ma non ha voti positivi. Questa è la migliore pratica o è cattiva?
redfox05

1
cosa farai, se hai molte pagine 100+ controller! ... pratica ambigua.
ArifMustafa

3

Possiamo semplicemente dichiarare più di un controller nello stesso modulo. Ecco un esempio:

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

Ho solo messo una semplice dichiarazione dell'app

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

Poi ho costruito un servizio e due controller

Per ogni controller avevo una linea nel JS

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

E nell'HTML ho dichiarato l'ambito dell'app in un div circostante

<div ng-app="app">

e ogni ambito del controller separatamente nel proprio div circostante (all'interno del div dell'app)

<div ng-controller="EditableRowCtrl">

Ha funzionato bene


0

Potresti anche aver incorporato tutte le viste del tuo modello nel tuo file html principale. Per esempio:

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

In questo modo, se ogni modello richiede un controller diverso, puoi comunque utilizzare il router angolare. Guarda questo plunk per un esempio funzionante http://plnkr.co/edit/9X0fT0Q9MlXtHVVQLhgr?p=preview

In questo modo, una volta che l'applicazione viene inviata dal server al tuo client, è completamente autonoma presumendo che non sia necessario effettuare richieste di dati, ecc.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.