假设我在同一页面上有以下元素:
我想实现以下逻辑:
/appliedOptionA/appliedOptionB
)第一个想法:配置ng-router,获取过滤数据作为参数,将数据转换为模型,构建过滤器面板,加载项,构造项面板。 主要问题:当用户更改过滤器时应该如何工作?如果我更新URL,它将触发具有不同参数的相同控制器并重复该过程 - >获取过滤数据作为参数,将数据转换为模型,构建过滤器面板,项目等。我不需要它 - 我的模型和UI已经是最新的。
我的问题:
保持模型和URL同步的正确方法是什么? URL管理模型(ng-route
)或模型更改管理URL(如何?)?
答案 0 :(得分:1)
我的建议是使用angular-ui-router并使用ng-router
代替angular-ui-router
,因为"appCtrl"
为您提供了更大的灵活性,在我看来,更容易使用。
鉴于您的“主要问题”,听起来您希望有一个应用程序控制器(让我们将其称为appCtrl
)处理所有更改并对其模型进行必要的更改。这种方法的主要缺点是它迫使你在appCtrl
内维护“filteredItems”模型,这不好玩,可能导致不必要的麻烦。接近它的一种更简单的方法是让另一个控制器处理对url的更改,而不是angular-ui-router
本身。话虽如此,让我告诉你如何实现这一目标。
*警告:帖子很长! (但希望有帮助)*
正因为如此,我还创建了一个演示我即将讨论的所有内容,以防你“只想要代码”:
由于我们正在创建一个全新的应用程序,让我们从创建和配置应用程序开始。
注意:请记住将var myApp = angular.module('myApp', ["ui.router"]);
脚本加载到您的应用程序中并添加依赖项。
app.js
app
现在我们有<body ng-app="myApp"></body>
,让我们使用ngApp directive将其添加到index.html。
的index.html
"filteredItems"
应用程序到位后,让我们看一下您在问题中解决的问题:
您要做的是创建state。实质上,基于url模式激活/停用状态。给定一个特定的模式,您可以告诉应用程序如何操作(使用控制器)和看起来像什么(使用模板)。在继续之前,请务必参考url routing,这将有助于网址模式。
我们需要:
home
)让我们配置应用程序,以及:
filteredItems
州myApp.config(function($stateProvider, $urlRouterProvider){
// default url - used if url pattern is not recognized
$urlRouterProvider.otherwise('/');
$stateProvider
.state('home', { // default state
url: '/'
})
.state('filteredItems', { // give the state a name
url: "/:appliedOptionA/:appliedOptionB", // provide the url pattern
controller: 'FilteredItemsCtrl', // controller to use for this state
templateUrl: "filteredItems.html" // url for the template
});
});
州app.js
appliedOptionA
我们现在已经配置了州的网址来获取参数(appliedOptionB
和filteredItemsCtrl
)。使用$stateParams service
,我们可以创建itemService
并负责过滤数据。
但在我们这样做之前,我们应该创建一项服务。使用Angular时, AVOID 使用控制器来维护数据,因为它们可以被创建/销毁。最佳做法是使用服务。话虽如此,让我们创建一个惊人的angular.module('myApp').factory('itemService', itemService);
function itemService (){
var items = {
appliedOptionA: [ 'Item 1', 'Item 2', 'Item 3' ],
appliedOptionB: [ 'Item 4', 'Item 5', 'Item 6' ]
};
function getItems (){
return items;
}
return {
getItems: getItems
}
}
:
<强> itemService.js 强>
FilteredItemsCtrl
华丽吧?我很高兴你这么想!
现在我们有了服务,我们可以创建itemService
。我们还将新创建的FilteredItemsCtrl
注入$stateParams
,以便能够访问数据。
注意:请记住将angular.module('myApp').controller('FilteredItemsCtrl', filteredItemsCtrl);
filteredItemsCtrl.$inject = ['$stateParams', '$scope', 'itemService'];
function filteredItemsCtrl ($stateParams, $scope, itemService){
var items = itemService.getItems(); // get items from service
// filter items
$scope.appliedOptionA = items.appliedOptionA.filter(function (item){
if ($stateParams.appliedOptionA){
return item.toLowerCase().indexOf($stateParams.appliedOptionA) > -1 ||
item.indexOf($stateParams.appliedOptionA) > -1
}
});
$scope.appliedOptionB = items.appliedOptionB.filter(function (item){
if ($stateParams.appliedOptionB){
return item.toLowerCase().indexOf($stateParams.appliedOptionB) > -1 ||
item.indexOf($stateParams.appliedOptionB) > -1
}
});
}
服务作为依赖项注入!
filteredItemsCtrl.js
url: "/:appliedOptionA/:appliedOptionB"
当我们定义州的网址时,我们将其设置为:$stateParams
。这意味着将使用appliedOptionA,appliedOptionB属性填充filteredItemsCtrl
。这也意味着每次更改网址时,都会创建 新 <div>
<div>
<span>Filtered Option A Items:</span>
<ul>
<li ng-repeat="optionItemA in appliedOptionA">
{{ optionItemA }}
</li>
</ul>
</div>
<div>
<span>Filtered Option B Items:</span>
<ul>
<li ng-repeat="optionItemB in appliedOptionB">
{{ optionItemB }}
</li>
</ul>
</div>
</div>
,因此您无需维护应用程序的模型!
在我们忘记之前,我们还需要为此状态创建模板。
filteredItems.html
ui-view
在创建state,filteredItemCtrl和视图的情况下,剩下的就是包含 <body ng-app="myApp"
ng-controller="MyAppCtrl">
<div>
<div>
Applied Option A: <input ng-model="appliedOptionA" />
</div>
<div>
Applied Option B: <input ng-model="appliedOptionB" />
</div>
<button type="button"
ng-click="filter()">Search</button>
</div>
<!-- where the state template goes -->
<div ui-view></div>
</body>
指令,以便正确显示状态模板:
的index.html
{{1}}
这就是它的全部!对于这篇长篇文章感到抱歉,但希望您发现这篇文章内容丰富!如果您有任何问题,请告诉我!
答案 1 :(得分:0)
如果您希望搜索关键字反映在URL中(因此可以将它们加入书签并直接进行处理),我建议不要强制模型的每次更改(这都是在每次击键后),而是等待提交表格。然后你重写URL(通过$ location.path和/或$ location.search),ngRoute将启动。
NgRoute将(重新)加载/刷新页面,就像它是第一次一样,并且与包含搜索关键字的可直接寻址页面的想法相匹配。我不建议您在收到提交后立即获取数据,因为正如您所述,ngRoute将刷新页面。