<div ng-if="!profile.detail"><button ui-sref=".profile({profileId:profile.id})">更多</button>{{ profile.name }}<div ng-if="profile.detail"><button ui-sref=".">少</button>{{ profile.detail |json }}一些有趣的部分要提到:我们只是使用内置的 ui-sref 和相对路径 def ui- 而不是一些 ng-clicksref=".profile({profileId:profile.id})" - 这将调用子状态 profile.一旦孩子被加载,我们可以通过重新调用父ui-sref="." (wow...)2) 我们的 detail 状态将做两件事通过 ID 加载详细信息//GetById 在服务器上调用休假清理//恢复列表原样//从父集合中查找配置文件var profile = _.find($scope.profiles, {id : $stateParams.profileId});$http.get("detail.json")//getById.then(函数(响应){//将只包含 id 的详细信息...这里我们过滤var detail = _.find(response.data, {id : $stateParams.profileId});//分配细节profile.detail = 详细信息;});//清理 - 删除细节var 清理 = 函数(){删除 profile.detail;}$scope.$on("$destroy", 清理);有几点需要提及:我们钩住了 $scope 事件destroy".一旦我们回到父级,这将被解雇.这就是我们清理 ui-router detail 状态往返过程中所有足迹的地方...3) 详细视图没有.没有,因为我们不需要模板.好吧,实际上我们仍然需要视图锚点,详细信息状态放在哪里...并且DetailController 被调用! .state('profiles.profile', {url: '/:profileId',意见:{'profile-details': {//没有模板控制器:'ProfileDetailsCtrl'}}});所以父级中的某处必须有视图锚点:<div ui-view="profile-details"></div>工作代码示例:看看那个解决方案这里...应该是清除(以下是为什么多次触发控制器的答案的原始部分)答案的原始部分控制器被实例化的次数与其视图被注入页面的次数一样多.你确实注入了视图3次.这里是个人资料的来源$scope.profiles = [{ id: '100', name: 'Misko Hevery' },{ id: '101', name: 'Igor Minar' },{ id: '102', name: 'Vojta Jina' },];这里我们创建了具有相同 ui-view 名称的锚点/目标://对于我们数组中的每个配置文件<div ui-view="profile-summary"></div><div ui-view="profile-details"></div>//我们注入这个名为 profile-details 的视图最后,我们要求将我们的视图注入这(3)个父/子视图目标:.state('profiles.profile', {url: '/:profileId',意见:{'profile-details': {//父视图目标出现 3 次templateUrl: 'profile-details.html',控制器:'ProfileDetailsCtrl'}}});解决方案:这不应该发生.我们不应多次使用一个 ui-view="viewName".这是工作.但这不是我们可以正确管理的...只需从中继器中移动目标...在这里扩展我更新了plunker,我把profiles.html做成这样//这里没有中继器<div ui-view="profile-summary"></div><div ui-view="profile-details"></div>我在摘要中进行迭代:{{ profile.name }}<button ng-click="showProfileDetails(profile.id)">更多</button>所以现在,每个 ui-view只有一次...看到它在行动 这里I have a list of profiles, where each profile can be either in a summary or in a detailed view. Only one profile can have a detailed view at any time.profiles.html<div ng-repeat="profile in profiles"> <div ui-view="profile-summary"></div> <div ui-view="profile-details"></div></div>profile-summary.html<div ng-if="$state.params.profileId !== profile.id"> {{ profile.name }} <button ng-click="showProfileDetails(profile.id)">More</button></div>profile-summary-controller.js$scope.showProfileDetails = function(profileId) { $state.go('profiles.profile', { profileId: profileId });};profile-details .html<div ng-if="$state.params.profileId === profile.id"> Detailed profile of {{ profile.name }} <button ng-click="hideProfileDetails()">Less</button></div>profile-details-controller.js$scope.hideProfileDetails = function() { $state.go('profiles.profile', { profileId: null });};ui-router configuration$stateProvider .state('profiles', { url: '/profiles?keywords', views: { 'profiles': { templateUrl: 'profiles.html', controller: 'ProfilesCtrl' }, 'profile-summary@profiles': { templateUrl: 'profile-summary.html', controller: 'ProfileSummaryCtrl' } } }) .state('profiles.profile', { url: '/:profileId', views: { 'profile-details': { templateUrl: 'profile-details.html', controller: 'ProfileDetailsCtrl' } } });Questions I have:When the button is clicked, ProfileDetailsCtrl is instantiated 3 times. How could I instantiate it only for profile that is extended?Am I utilizing the ui-router flexibility properly, or there is a better way to implement this? (Note: When profile is expanded, it should be reflected in the URL (to make it bookmarkable)) 解决方案 Extend with detail ReplaceAfter discussion in comments below, there is a different solution for the basic (required) concept: Inside a list - How to replace a row (on-click), with more details - using ui-router?I.e. let's start with this: basic info1 basic info2 // click more here basic info2getting this when is clicked (ang getting back if is clicked next) basic info1 very detailed information loaded with ui-router state machine... basic info2This would be the solution:1) The list view template, would have ng-if, checking if there is some detail info, or not:<div ng-repeat="profile in profiles"> <div ng-if="!profile.detail"> <button ui-sref=".profile({profileId:profile.id})">More</button> {{ profile.name }} </div> <div ng-if="profile.detail"> <button ui-sref=".">Less</button> {{ profile.detail | json }} </div></div>A few fancy parts to mention: instead of some ng-click we just do use the built in ui-sref with a relative path def ui-sref=".profile({profileId:profile.id})" - That will call the child state profile.Once child is loaded, we can just get back by re-calling the parent ui-sref="." (wow...)2) Our detail state will be doing two thingsload the detail by ID // GetById called on a Servercleanup on leave // Restoring the list as it was// find a profile from parent collectionvar profile = _.find($scope.profiles, {id : $stateParams.profileId});$http .get("detail.json") // getById .then(function(response){ // would contain just a detail for id... here we filter var detail = _.find(response.data, {id : $stateParams.profileId}); // assign the detail profile.detail = detail;});// cleanup - remove the details var cleanup = function(){ delete profile.detail; } $scope.$on("$destroy", cleanup);A few things to mention: we hook on the $scope event "destroy". This will be fired, once we go back to the parent. And that's the place where we clean all the foot prints made during the ui-router detail state round-trip...3) the detail viewThere is NONE. None, becuase we do not need a template. Well in fact we still need the view anchor, where is the detail state placed... and the DetailController is called! .state('profiles.profile', { url: '/:profileId', views: { 'profile-details': { // NO template controller: 'ProfileDetailsCtrl' } } });so there must be the view anchor somewhere in the parent:<div ui-view="profile-details"></div>Working code example:Take a look a that solution here... it should be clear(below is the original part of the answer why multiple times fired controller)Original part of the answerThe controller is instantiated as many times, as many times is its view injected into the page. And you do inject the view 3 times.Here is the source of the profiles$scope.profiles = [ { id: '100', name: 'Misko Hevery' }, { id: '101', name: 'Igor Minar' }, { id: '102', name: 'Vojta Jina' },];Here we do create anchors/targets with the same ui-view name:<div ng-repeat="profile in profiles"> // for each profile in our array <div ui-view="profile-summary"></div> <div ui-view="profile-details"></div> // we inject this view named profile-details</div>And finally, we ask to inject our view into these (3) parent/child view-targets:.state('profiles.profile', { url: '/:profileId', views: { 'profile-details': { // the parent view-target is there 3 times templateUrl: 'profile-details.html', controller: 'ProfileDetailsCtrl' } } });Solution: this should not happen. We should not use one ui-view="viewName" moret than once. It is working. but it is not what we can correctly manage... simply move the targets from repeater...EXTEND here I updated the plunker, I made the profiles.html like this// NO repeater here<div ui-view="profile-summary"></div><div ui-view="profile-details"></div>And I do iterate inside fo the summary:<div ng-repeat="profile in profiles"> {{ profile.name }} <button ng-click="showProfileDetails(profile.id)">More</button></div>So now, each ui-view is there only once... see that in action here 这篇关于Angular ui-router 多次实例化子控制器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云! 07-24 19:46