2016-03-15 105 views
-1

我有一個非常簡單的AngularJS SPA,使用UI路由器在兩個視圖之間切換。點擊主頁鏈接後,用戶將看到一行文字。關於鏈接也應該這樣做,但它的路由配置爲使用templateUrl而不是一個模板字符串:AngularJS UI路由器:何處包含控制器腳本

$stateProvider 
    .state("home", { 
    url: "/home", 
    template: "<h3>This is the Home content</h3>" 
    }) 
    .state("about", { 
    url: "/about", 
    templateUrl: "about.html", 
    controller: "aboutController" 
    }); 

about.html是因爲它可以是一樣簡單:

<!DOCTYPE HTML> 
<html ng-app="simpleApp"> 
<head> 
    <title>About</title> 
    <script src="aboutcontroller.js"></script> 
</head> 
<body ng-controller="aboutController"> 
    <h3>{{message}}</h3> 
</body> 
</html> 

。 ..和它的控制器也是純做作的樣板:

console.log("Registered aboutController"); /////////// 
angular.module("simpleApp") 
.controller("aboutController", ["$scope", function ($scope) { 
    console.log("Created aboutController"); /////////// 
    $scope.message = "This is the About content!"; 
}]); 

注意兩個控制檯陳述,幫我診斷問題。

問題:當控制器腳本文件執行時,控制器本身永遠不會被調用。所以也看不到文本,用戶只要看到:

{{消息}}

這似乎是我包括在模板文件(有關該腳本文件中涉及到的事實。 HTML)。如果我將腳本標記移到index.html,問題就會消失,一切都按預期工作。

Here's a plunker that shows my problem and workaround.

真正的問題: 在這個非常簡單的和人爲的例子,它是合理的,包括在SPA的主要頁面的所有控制器的腳本。但即使是一個非常簡單的Web應用程序,也可能有幾十個頁面和數十個控制器。將所有控制器添加到主頁面並不能很好地提升性能,並且不能很好地進行維護。

那麼設置它的適當方法是什麼?控制器腳本應該如何/包括在哪裏?

編輯:我忘了提及我收到的錯誤(是的,我知道)。隨着about.html script標籤,我收到一條消息說

參數「aboutController」不是一個函數,得到了不確定

這直接發生在控制檯消息「註冊aboutController」之後。如果我將腳本標記移動到index.html中以包含控制器,則不顯示任何錯誤。同樣,對我來說,這表示控制器根本無法及時撥打電話。移動到index.html,它在需要時被完全註冊。

+0

如果您在頁面上看到字面意思是「{{message}}」,那意味着該模板根本沒有被處理。如果Angular沒有處理模板,如果沒有填充「消息」,則只會看到任何內容。這指出產生致命錯誤的事物。你有沒有檢查你的Javascript控制檯的錯誤? – deceze

+0

爲什麼你的模板包含整個HTML文件?它應該只包含與特定視圖相關的片段。你也不能在文件中使用'ng-controller',因爲你已經在路由器中使用'controller:...'了。您必須將帶有控制器的文件包含在您的主文件中,作爲您的主模塊的依賴項,否則路由器在嘗試加載您的路由時找不到控制器。 – deceze

+0

@deceze我花了一些時間在plunker的readme.md文檔中製作了一個更完整的描述,並且忘記了在這裏提到錯誤。是的,有一個關於控制器不是一個函數的錯誤。這會在我的控制檯消息「Registered aboutController。」後直接顯示。如果我將腳本標記移至index.html,則消息將消失。所以即使註冊控制器的腳本及時執行,實際的控制器也不能被創建。我會把這個添加到問題中。感謝您指出。 –

回答

1

經過數小時的研究,我發現了它。這些是我需要做的事情:

  1. requireJS,允許我在運行時輕鬆加載腳本。由於需要動態加載所有,我需要爲我們所有的指令和第三方控件設置依賴關係,因此結束了大量的工作。你可以沒有requireJS,但它根本不值得麻煩。
  2. 更改狀態調用以使用resolve()提供控制器。這實際上是一種黑客攻擊,因爲resolve()函數實際上是爲了加載控制器的依賴關係,但是在這一點上加載控制器的腳本工作得很好。這樣做的更簡單的方法涉及使用angularAMD,它提供了一個簡單的包裝看起來像下面的代碼片段。不幸的是,它並沒有給你機會從參數動態構建控制器名稱,所以我最終自己決定了重寫決定。如果您的需求更簡單,那麼使用angularAMD是明顯的選擇。

這裏是什麼樣子時,通常指定的觀點類似:

$stateProvider.state("home", { 
    url: "", 
    views: { 
    // Other views... 
     "client": { 
     templateUrl: "clientselection.html", 
     controller: "ClientSelectController", 
     controllerUrl: "Controllers/ClientSelect.controller" 
     } 
    } 
    }); 

下面是與angularAMD同樣的事情。不同的是,控制器現在按需加載:

$stateProvider.state("home", { 
    url: "", 
    views: { 
    // Other views... 
     "client": angularAMD.route({ 
     templateUrl: "clientselection.html", 
     controller: "ClientSelectController", 
     controllerUrl: "Controllers/ClientSelect.controller" 
     }) 
    } 
    }); 

榮譽提名必須去Dan Wahlin's terrific blog post。它不使用UI路由器,但概念是可轉移的。不幸的是,這篇文章只給出了不完整的片段。剩下的部分你需要從他在Github上傳的一個龐大的樣本項目中挑選出來。我不追蹤爲什麼這是必要的,但博客文章仍然值得閱讀。

0

對於角路由,你應該使用routeProvider它,那麼你可以使用它像這樣導航:

var app = angular.module('moduleName', [ 
'ngRoute', 
'angularModalService' 
]); 

app.config(['$routeProvider', 
function($routeProvider) { 
    $routeProvider. 
     when('/home', { 
     templateUrl: 'partials/home.html', 
     controller: 'homeController' 
    }).otherwise({ 
     redirectTo: '/home' 
    }); 

在這裏,您綁定的HomeController到整個家庭。HTML,但是如果你需要有綁定到頁面的一小部分的控制器,你可以像這樣將它綁定:

<div class="row" ng-controller="homeController"> 
    //Further HTML 
</div> 

控制器將是僅此專區內提供。

對於包含部分,我通常定義</body>標籤上方的所有腳本。我分開它們,首先是像jQuery和AngularJS這樣的庫,下面是第一個app.js(帶有routeProvoder的文件),控制器,然後是服務/工廠和最後的指令

+0

問題是關於ui路由器,正是因爲這是我選擇用於ngRoute的地方。谷歌可以給你所有的理由,但在我看來,主要是因爲需要多個命名的視圖。 –

0

要回答你的問題,Angular是以這樣一種方式設計的,即加載所有的js文件並將控制權賦予角度。加載Js文件時,所有控制器,服務等都在ngApp中註冊。這就是爲什麼建議在index.html中提供所有腳本文件的原因。

如果您認爲在單個index.html中提供所有文件都很笨拙,那麼您可以將應用程序拆分爲模塊,然後加載它們。這是讓您的應用看起來不那麼笨拙的更好方法。