Javascript AngularJS ui路由器$state.go(';^';)仅更改地址栏中的URL,但不加载控制器

Javascript AngularJS ui路由器$state.go(';^';)仅更改地址栏中的URL,但不加载控制器,javascript,angularjs,angular-ui-router,Javascript,Angularjs,Angular Ui Router,我正在尝试用angularjsui路由器创建一个“Todo应用程序”。它有两列: 第1列:待办事项列表 第2列:待办事项详细信息或待办事项编辑表单 在保存Todo后的编辑和创建控制器中,我希望重新加载列表以显示相应的更改。问题:在创建或更新Todo时,调用$state.go(“^”)后,浏览器中的URL会更改回/api/Todo,但不会执行ListCtrl,即未调用$scope.search,因此不会检索Todo列表(包含更改的项目),第2列中也没有显示第一个Todo的详细信息(而是变为空白

我正在尝试用angularjs
ui路由器创建一个“Todo应用程序”。它有两列:

  • 第1列:待办事项列表
  • 第2列:待办事项详细信息或待办事项编辑表单
在保存Todo后的编辑和创建控制器中,我希望重新加载列表以显示相应的更改。问题:在创建或更新Todo时,调用
$state.go(“^”)
后,浏览器中的URL会更改回
/api/Todo
,但不会执行ListCtrl,即未调用
$scope.search
,因此不会检索Todo列表(包含更改的项目),第2列中也没有显示第一个Todo的详细信息(而是变为空白)

我甚至尝试了
$state.go('^',$stateParams,{reload:true,inherit:false,notify:false}),运气不好

如何进行状态转换以最终执行控制器?

资料来源:

var TodoApp = angular.module('TodoApp', ['ngResource', 'ui.router'])
    .config(function ($stateProvider, $urlRouterProvider) {
        $urlRouterProvider.otherwise('/api/todo');

        $stateProvider
            .state('todo', {
                url: '/api/todo',
                controller: 'ListCtrl',
                templateUrl: '/_todo_list.html'
            })
            .state('todo.details', {
                url: '/{id:[0-9]*}',
                views: {
                    'detailsColumn': {
                        controller: 'DetailsCtrl',
                        templateUrl: '/_todo_details.html'
                    }
                }
            })
            .state('todo.edit', {
                url: '/edit/:id',
                views: {
                    'detailsColumn': {
                        controller: 'EditCtrl',
                        templateUrl: '/_todo_edit.html'
                    }
                }
            })
            .state('todo.new', {
                url: '/new',
                views: {
                    'detailsColumn': {
                        controller: 'CreateCtrl',
                        templateUrl: '/_todo_edit.html'
                    }
                }
            })
        ;

    })
;

TodoApp.factory('Todos', function ($resource) {
    return $resource('/api/todo/:id', { id: '@id' }, { update: { method: 'PUT' } });
});

var ListCtrl = function ($scope, $state, Todos) {
    $scope.todos = [];

    $scope.search = function () {
        Todos.query(function (data) {
            $scope.todos = $scope.todos.concat(data);
            $state.go('todo.details', { id: $scope.todos[0].Id });
        });
    };

    $scope.search();
};

var DetailsCtrl = function ($scope, $stateParams, Todos) {
    $scope.todo = Todos.get({ id: $stateParams.id });
};

var EditCtrl = function ($scope, $stateParams, $state, Todos) {
    $scope.action = 'Edit';

    var id = $stateParams.id;
    $scope.todo = Todos.get({ id: id });

    $scope.save = function () {
        Todos.update({ id: id }, $scope.todo, function () {
            $state.go('^', $stateParams, { reload: true, inherit: false, notify: false });
        });
    };
};

var CreateCtrl = function ($scope, $stateParams, $state, Todos) {
    $scope.action = 'Create';

    $scope.save = function () {
        Todos.save($scope.todo, function () {
            $state.go('^');
        });
    };
};

我可能遇到过类似的问题,我采用的方法是使用
$location.path(data.path).search(data.search)
重定向页面,然后在控制器中捕获$locationChangeSuccess事件。换句话说,我使用
$location.path(…).search(…)
作为
$state.go(…)
的对应项,然后捕获$locationChangeSuccess事件,该事件将在匹配路由和调用控制器之前发生位置更改时触发

var TodoApp = angular.module('TodoApp', ['ngResource', 'ui.router'])
    .config(function ($stateProvider, $urlRouterProvider) {
        $urlRouterProvider.otherwise('/api/todo');

        $stateProvider
            .state('todo', {
                url: '/api/todo',
                controller: 'ListCtrl',
                templateUrl: '/_todo_list.html'
            })
            .state('todo.details', {
                url: '/{id:[0-9]*}',
                views: {
                    'detailsColumn': {
                        controller: 'DetailsCtrl',
                        templateUrl: '/_todo_details.html'
                    }
                }
            })
            .state('todo.edit', {
                url: '/edit/:id',
                views: {
                    'detailsColumn': {
                        controller: 'EditCtrl',
                        templateUrl: '/_todo_edit.html'
                    }
                }
            })
            .state('todo.new', {
                url: '/new',
                views: {
                    'detailsColumn': {
                        controller: 'CreateCtrl',
                        templateUrl: '/_todo_edit.html'
                    }
                }
            })
        ;

    })
;

TodoApp.factory('Todos', function ($resource) {
    return $resource('/api/todo/:id', { id: '@id' }, { update: { method: 'PUT' } });
});

var ListCtrl = function ($scope, $state, Todos, todo.details) {
    /*here is where i would make the change*/        
    $scope.$on('$locationChangeSuccess', function () {
          $scope.search();
          $route.reload();
    });

        $scope.todos = [];

        $scope.search = function () {
            Todos.query(function (data) {
                $scope.todos = $scope.todos.concat(data);
            });
        };

    $scope.search();
};

var DetailsCtrl = function ($scope, $stateParams, Todos) {
    $scope.todo = Todos.get({ id: $stateParams.id });
};

var EditCtrl = function ($scope, $stateParams, $state, Todos, $location) {
    $scope.action = 'Edit';

    var id = $stateParams.id;
    $scope.todo = Todos.get({ id: id });

    $scope.save = function () {
        Todos.update({ id: id }, $scope.todo, function () {
           //here is where I would make a change
                $location.path('todo.details').search($stateParams);
        });
    };
};

var CreateCtrl = function ($scope, $stateParams, $state, Todos, $location) {
    $scope.action = 'Create';

    $scope.save = function () {
        Todos.save($scope.todo, function () {
           //here is where I would make a change
                $location.path('todo.details');
        });
    };
};
$LOCATIONCHANGESSUCCESS事件发生在匹配路由和调用控制器之前

我将给出一个示例(草稿),说明如何将
编辑
嵌套到
详细信息中。首先,让我们修改模板

详细信息
模板包含详细信息的完整定义。另外,它现在包含属性
ui view=“editView”
。这将确保编辑将从可见性角度“替换”细节,而编辑范围将继承所有细节设置。这就是ui路由器的威力

有了这个调整的
状态
模板
映射,我们确实有很多。现在我们可以充分利用
ui路由器

我们将在
DetailCtrl
上定义一些方法(记住,在继承编辑状态下可用)

好的,现在应该很清楚了,我们确实有一个
模型
,带有
model.todos
项及其备份
model.original

编辑控制器可以有两个操作:
Save()
Cancel()

这应该会让我们知道如何在父/子状态之间导航,以及如何强制重新加载


请注意,事实上,我使用的不是Angular.copy(),而是Angular.copy(),但两者都应该可以工作

非常感谢Radim Köhler指出,
$scope
是继承的。通过两个小改动,我成功地解决了这个问题。请参阅下面的代码,我在添加额外行的地方进行了注释。现在它就像一个符咒

var TodoApp = angular.module('TodoApp', ['ngResource', 'ui.router'])
    .config(function ($stateProvider, $urlRouterProvider) {
        $urlRouterProvider.otherwise('/api/todo');

        $stateProvider
            .state('todo', {
                url: '/api/todo',
                controller: 'ListCtrl',
                templateUrl: '/_todo_list.html'
            })
            .state('todo.details', {
                url: '/{id:[0-9]*}',
                views: {
                    'detailsColumn': {
                        controller: 'DetailsCtrl',
                        templateUrl: '/_todo_details.html'
                    }
                }
            })
            .state('todo.edit', {
                url: '/edit/:id',
                views: {
                    'detailsColumn': {
                        controller: 'EditCtrl',
                        templateUrl: '/_todo_edit.html'
                    }
                }
            })
            .state('todo.new', {
                url: '/new',
                views: {
                    'detailsColumn': {
                        controller: 'CreateCtrl',
                        templateUrl: '/_todo_edit.html'
                    }
                }
            })
        ;

    })
;

TodoApp.factory('Todos', function ($resource) {
    return $resource('/api/todo/:id', { id: '@id' }, { update: { method: 'PUT' } });
});

var ListCtrl = function ($scope, $state, Todos) {
    $scope.todos = [];

    $scope.search = function () {
        Todos.query(function (data) {
            $scope.todos = $scope.todos(data); // No concat, just overwrite
            if (0 < $scope.todos.length) { // Added this as well to avoid overindexing if no Todo is present
                $state.go('todo.details', { id: $scope.todos[0].Id });
            }
        });
    };

    $scope.search();
};

var DetailsCtrl = function ($scope, $stateParams, Todos) {
    $scope.todo = Todos.get({ id: $stateParams.id });
};

var EditCtrl = function ($scope, $stateParams, $state, Todos) {
    $scope.action = 'Edit';

    var id = $stateParams.id;
    $scope.todo = Todos.get({ id: id });

    $scope.save = function () {
        Todos.update({ id: id }, $scope.todo, function () {
            $scope.search(); // Added this line
            //$state.go('^'); // As $scope.search() changes the state, this is not even needed.
        });
    };
};

var CreateCtrl = function ($scope, $stateParams, $state, Todos) {
    $scope.action = 'Create';

    $scope.save = function () {
        Todos.save($scope.todo, function () {
            $scope.search(); // Added this line
            //$state.go('^'); // As $scope.search() changes the state, this is not even needed.
        });
    };
};
var TodoApp=angular.module('TodoApp',['ngResource','ui.router']))
.config(函数($stateProvider,$urlRouterProvider){
$urlRouterProvider。否则('/api/todo');
$stateProvider
.州(‘待办事项’{
url:“/api/todo”,
控制器:“ListCtrl”,
templateUrl:“/\u todo\u list.html”
})
.state('todo.details'{
url:“/{id:[0-9]*}”,
观点:{
“详情栏”:{
控制器:“DetailsCtrl”,
templateUrl:“/\u todo\u details.html”
}
}
})
.state('todo.edit'{
url:“/edit/:id”,
观点:{
“详情栏”:{
控制器:“EditCtrl”,
templateUrl:“/\u todo\u edit.html”
}
}
})
.state('todo.new'{
url:“/new”,
观点:{
“详情栏”:{
控制器:“CreateCtrl”,
templateUrl:“/\u todo\u edit.html”
}
}
})
;
})
;
TodoApp.factory('Todos',函数($resource){
返回$resource('/api/todo/:id',{id:'@id'},{update:{method:'PUT'}});
});
var ListCtrl=函数($scope、$state、Todos){
$scope.todos=[];
$scope.search=函数(){
Todos.query(函数(数据){
$scope.todos=$scope.todos(数据);//没有concat,只是覆盖
如果(0<$scope.todos.length){//也添加了此项,以避免在没有Todo时过度索引
$state.go('todo.details',{id:$scope.todos[0].id});
}
});
};
$scope.search();
};
var DetailsCtrl=函数($scope、$stateParams、Todos){
$scope.todo=Todos.get({id:$stateParams.id});
};
var EditCtrl=函数($scope、$stateParams、$state、Todos){
$scope.action='Edit';
var id=$stateParams.id;
$scope.todo=Todos.get({id:id});
$scope.save=函数(){
update({id:id},$scope.todo,函数(){
$scope.search();//添加了此行
//$state.go('^');//当$scope.search()更改状态时,甚至不需要这样做。
});
};
};
var CreateCtrl=function($scope、$stateParams、$state、Todos){
$scope.action='Create';
$scope.save=函数(){
保存($scope.todo,函数(){
$scope.search();//添加了此行
//$state.go('^');//当$scope.search()更改状态时,甚至不需要这样做。
});
};
};

我想说,这是对各州的误解。检查。当应用程序处于特定sta时
// keep detail definition as it is
.state('todo.details', {
    url: '/{id:[0-9]*}',
    views: {
        'detailsColumn': {
            controller: 'DetailsCtrl',
            templateUrl: '/_todo_details.html'
        }
    }
})
// brand new definition of the Edit
.state('todo.details.edit', { // i.e.: url for detail like /todo/details/1/edit
    url: '/edit',
    views: {
        'editView': {    // inject into the parent/detail view
            controller: 'EditCtrl',
            templateUrl: '/_todo_edit.html'
        }
    }
})
var DetailsCtrl = function ($scope, $stateParams, Todos) {

    $scope.id =  $stateParams.id // keep it here

    // model will keep the item (todos) and a copy for rollback
    $scope.model = {
        todos : {},
        original : {},
    }

    // declare the Load() method

    $scope.load = function() {
        Todos
          .get({ id: $stateParams.id })
          .then(function(response){

              // item loaded, and its backup copy created
              $scope.model.todos = response.data;
              $scope.model.original = angular.copy($scope.model.todos);

          });
    };

    // also explicitly load, but just once,
    // not auto-triggered when returning back from Edit-child
    $scope.load()
};
var EditCtrl = function ($scope, $stateParams, $state, Todos) {
    $scope.action = 'Edit';

    // ATTENTION, no declaration of these, 
    // we inherited them from parent view !
    //$scope.id ..     // we DO have them
    //$scope.model ...

    // the save, then force reload, and return to detail
    $scope.save = function () {
        Todos
           .update({ id: id })
           .then(function(response){

              // Success
              $scope.load(); 
              $state.go('^');
           },
           function(reason){

             // Error
             // TODO 
           });
    };

    // a nice and quick how to rollback
    $scope.cancel = function () {
         $scope.model.todos = Angular.copy($scope.model.original);
         $state.go('^');
    };
};
var TodoApp = angular.module('TodoApp', ['ngResource', 'ui.router'])
    .config(function ($stateProvider, $urlRouterProvider) {
        $urlRouterProvider.otherwise('/api/todo');

        $stateProvider
            .state('todo', {
                url: '/api/todo',
                controller: 'ListCtrl',
                templateUrl: '/_todo_list.html'
            })
            .state('todo.details', {
                url: '/{id:[0-9]*}',
                views: {
                    'detailsColumn': {
                        controller: 'DetailsCtrl',
                        templateUrl: '/_todo_details.html'
                    }
                }
            })
            .state('todo.edit', {
                url: '/edit/:id',
                views: {
                    'detailsColumn': {
                        controller: 'EditCtrl',
                        templateUrl: '/_todo_edit.html'
                    }
                }
            })
            .state('todo.new', {
                url: '/new',
                views: {
                    'detailsColumn': {
                        controller: 'CreateCtrl',
                        templateUrl: '/_todo_edit.html'
                    }
                }
            })
        ;

    })
;

TodoApp.factory('Todos', function ($resource) {
    return $resource('/api/todo/:id', { id: '@id' }, { update: { method: 'PUT' } });
});

var ListCtrl = function ($scope, $state, Todos) {
    $scope.todos = [];

    $scope.search = function () {
        Todos.query(function (data) {
            $scope.todos = $scope.todos(data); // No concat, just overwrite
            if (0 < $scope.todos.length) { // Added this as well to avoid overindexing if no Todo is present
                $state.go('todo.details', { id: $scope.todos[0].Id });
            }
        });
    };

    $scope.search();
};

var DetailsCtrl = function ($scope, $stateParams, Todos) {
    $scope.todo = Todos.get({ id: $stateParams.id });
};

var EditCtrl = function ($scope, $stateParams, $state, Todos) {
    $scope.action = 'Edit';

    var id = $stateParams.id;
    $scope.todo = Todos.get({ id: id });

    $scope.save = function () {
        Todos.update({ id: id }, $scope.todo, function () {
            $scope.search(); // Added this line
            //$state.go('^'); // As $scope.search() changes the state, this is not even needed.
        });
    };
};

var CreateCtrl = function ($scope, $stateParams, $state, Todos) {
    $scope.action = 'Create';

    $scope.save = function () {
        Todos.save($scope.todo, function () {
            $scope.search(); // Added this line
            //$state.go('^'); // As $scope.search() changes the state, this is not even needed.
        });
    };
};