AngularJS ui-router $ state.go('^')只更改地址栏中的URL,但不加载控制器

Ada*_*abo 10 javascript angularjs angular-ui-router

我正在尝试用angularjs创建一个"Todo应用程序" ui-router.它有2列:

  • 第1列:Todos列表
  • 第2列:Todo详细信息或Todo编辑表单

保存Todo后,在编辑和创建控制器中,我想重新加载列表以显示相应的更改.问题:打完电话后$state.go('^')创建或更新待办事项时,在浏览器的地址改回/api/todo,但不执行的ListCtrl,即$scope.search不叫,因此待办列表(与更改的项目)未检索到,也不是第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('^');
        });
    };
};
Run Code Online (Sandbox Code Playgroud)

Rad*_*ler 5

我想举一个例子(草案)中如何嵌套editdetail.好吧,首先让我们修改模板.

Detail模板,包含了详细的完整定义.此外,它现在包含属性ui-view="editView".这将确保编辑将从可见性角度"替换" 细节 - 而编辑范围将继承所有细节设置.这就是ui-router的强大功能

<section ui-view="editView">
  <!-- ... here the full description of the detail ... -->
</section>
Run Code Online (Sandbox Code Playgroud)

所以,其次,让我们将编辑 移动state细节中

// 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'
        }
    }
})
Run Code Online (Sandbox Code Playgroud)

通过这种调整 statetemplate映射,我们确实有很多.现在我们可以从ui-router充分的力量中获利.

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

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()
};
Run Code Online (Sandbox Code Playgroud)

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

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

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('^');
    };
};
Run Code Online (Sandbox Code Playgroud)

这应该给出一些想法,如何在父/子状态之间导航并强制重新加载.

实际上注意,而不是Angular.copy()我使用lo-dash_.cloneDeep()但两者都应该工作


Ada*_*abo 5

非常感谢RadimKöhler指出这$scope是继承的.通过2次小改动,我设法解决了这个问题.看下面的代码,我评论了我添加了额外的行.现在它就像一个魅力.

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.
        });
    };
};
Run Code Online (Sandbox Code Playgroud)