単一ページアプリにAngularJSを備えた複数のコントローラー


102

私が知りたいのは、単一ページのアプリケーションに複数のコントローラーを使用する方法です。私はそれを理解しようとしましたが、私のものと非常によく似た質問を見つけましたが、単一のページアプリに複数のコントローラーを使用しないという特定の問題を解決するためのさまざまな答えがあります。

1つのページに複数のコントローラーを使用するのは賢明ではないからでしょうか。それとも不可能ですか?

メインページで動作するキックアスイメージカルーセルコントローラーが既にあるとしましょう。その後、モーダルの使用方法(例を挙げましょう)を習得し、そのための新しいコントローラーも必要です(またはコントローラーに必要な他のすべてのもの)。それから私は何をしますか?

他の質問に対するいくつかの回答を見てきました。彼らは私とほとんど同じことについて尋ね、人々は「* OMG。なぜあなたはそれをするのですか、これをしてください...」と答えます。

最良の方法は何ですか、またはどのように行いますか?

編集する

あなたの多くは、2つのコントローラーを宣言し、ng-controllerを使用してそれを呼び出すだけで答えています。以下のコードを使用して、ng-controllerでMainCtrlを呼び出します。

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

ng-controllerを使わずにコントローラーをここで設定する必要があるのはなぜですか?これが私を混乱させたものです。(この方法で2つのコントローラーを追加することはできないと思います...)


1つの.htmlファイルに対して2つのコントローラーを宣言できると思いませんか?それはどのように行われますか?when: /home, controller: MainCtrl。それ以上追加することはできません、または単にng-controllerでそれを呼び出すつもりですか?

3
@Mosho、ステップ1、ステップ2を完了しましたが、方法や理由は説明しません。簡単な場合は、その方法を説明してください。これは、AngularJSを使用する、と言っているようなものです。詳しく説明できますか?または、6月以降は返信がない可能性があります。
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-appler」を「ng-controller」の横にある各DIVに配置する例から外れている場合は、「ng-app」を1つだけ「body」タグに移動してみてください(divごとに削除します) ng-app "タグ)。最初のコントローラーのみが機能する場合。(私はAngular初心者の日からこれを覚えています。)
ftexperts 2014年

1
ng-controller複数のDOM要素での使用に関して私が持っていた唯一の問題は、多くのアイテムがを介してDOMに印刷されているシナリオでの発言ng-repeatです。これらのそれぞれがを呼び出すとしましょうng-controller="myController。私のアプリケーションで見たコンソールログの一部から、myControllerそれを呼び出すDOMにレンダリングされる各要素で再初期化します...多分私は特定の使用法で何かをめちゃくちゃにしたり、OPの範囲を超えたりするかもしれません質問、しかし他の人がそれをまったく経験していないかどうか興味があります...
twknab 2017

91

「シングルページアプリ」という意味が欠けていると思います。

これは、物理的に1つの.htmlがあることを意味するのではなく、1つのメインindex.htmlといくつかのネストされた.htmlファイルを持つことになります。では、なぜ単一ページアプリなのでしょうか。この方法では、標準的な方法(つまり、ページ全体を完全に更新するブラウザー呼び出し)ではなく、Angular / Ajaxを使用してコンテンツ部分をロードするだけです。ページの変更の間にちらつきが見られないため、ページから移動しなかったように見えます。したがって、1ページにとどまっているように感じます。

ここで、シングルページアプリに複数のコンテンツ(たとえば、自宅、連絡先、ポートフォリオ、ストア)が必要だと想定しています。単一ページ/複数コンテンツアプリ(角度のある方法)は次のように編成されます。

  • 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ください)

そしてもちろん、contacts.htmlページ内でng-controllerディレクティブをいくつでも宣言できます。それらはContactCtrl(したがって、それから継承する)の子コントローラーになります。ただし、1つのルートの場合、内でrouteProvider、「部分ビューの父のコントローラ」として機能する1つのコントローラを宣言できます。

編集次のtemplates / 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タグ内でegを宣言すると、<body ng-controller="BodyController">これは機能しますか?$apply already in progressこれを行うとエラーが発生しますが、dpd.jsに関連していると思います。それに入るのではなく、私はそれを2回または何かをロードするだけだと思いますが、方法はわかりませんが、コントローラの使用はそれを再ロードしようとしている可能性があります。
blamb

1
@BrianThomasもちろん、動作するはずです。注意:ビューにコントローラーを挿入する場合は、$ routeProviderを使用し、divタグにng-controllerを記述しないでください。
Adhara 2015年

9

現在、単一ページのアプリケーションを作成中です。これが私があなたの質問に答えるだろうと私が信じているものです。ng-viewディレクティブが含まれたdivが含まれているベーステンプレート(base.html)があります。このディレクティブは、angularに新しいコンテンツをどこに配置するかを指示します。私は自分自身が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も使用しているので、index.htmlでmain.htmlを使用できます。しかし、/ homeと/ aboutがあり、2つのコントローラーはそれぞれに対応しています。私のmain.htmlにng-viewを付けたindex.htmlしかありません。私はあなたがしたようにmain.htmlに2つのコントローラを設定することができますwhen /home


まあ、私はもっと設定する方法を知っています whenの。1つのテンプレートに2つのコントローラーが必要です。それともマビー私があなたが私に伝えようとしていたことを誤解しましたか?

コントローラを使用する代わりに、ディレクティブを使用してみてください。1つのテンプレートで多くのディレクティブを使用できます。それでもコントローラーを使用したい場合は、ディレクティブがコントローラーとどのようにリンクできるかについてのビデオがここにあります。。egghead.io lessons angularjs
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

同じモジュールで複数のコントローラーを宣言するだけです。次に例を示します。

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

アプリの簡単な宣言を1つだけ入れます

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

次に、1つのサービスと2つのコントローラーを作成しました

各コントローラーについて、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>

このようにして、各テンプレートに異なるコントローラーが必要な場合でも、angular-routerを使用できます。実際の例については、このプランクを参照してください http://plnkr.co/edit/9X0fT0Q9MlXtHVVQLhgr?p=preview

この方法では、アプリケーションがサーバーからクライアントに送信されると、データ要求などを行う必要がないと想定して、完全に自己完結型になります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.