AngularJS和UI-Router:保持控制器加载

时间:2015-03-19 14:26:05

标签: angularjs angular-ui-router

我正在为我们的客户支持构建一个Web应用程序。其中一个需求是能够同时打开多张票 我能够使用制表系统和UI-Router轻松完成第一部分。 但是,在我当前的实现中,每次更改活动选项卡时,都会卸载先前当前的选项卡,并加载当前的选项卡(因为它是在先前的选项卡更改时卸载的)。

这根本不是预期的行为。我已经花了几天时间试图找到实现这一目标的方法,没有任何运气。 我能够做的最接近的事情是使用UI-Router中的多视图系统,但我需要同一视图的多个实例保留在内存中(如果打开多个票证,它们都在同一个视图中,相同的控制器,但不同的范围)

这是我目前的实施方式: supportApp.js:     var app = angular.module(" supportApp",[" ui.router"," ui.bootstrap"]);

app.config(function($stateProvider, $urlRouterProvider, $httpProvider){
    $urlRouterProvider.otherwise("/");
    $stateProvider
        .decorator('d', function(state, parent){
            state.templateUrl = generateTemplateUrl(state.self.templateUrl);
            return state;
        })
        .state("main", {
            abtract: true,
            templateUrl: "main.html",
            controller: "mainController"
        })
        .state("main.inbox", {
            url: "/",
            templateUrl: "inbox.html",
            controller: "inboxController"
        })
        .state('main.viewTicket', {
            url: '/ticket/{id:int}',
            templateUrl: "viewTicket.html",
            controller: "ticketController"
        })
    ;
});

mainController.js :(处理其他内容,这里的代码最少)

app.controller("mainController", function($rootScope, $http, $scope, $state, $interval){
    // Tabs system
    $scope.tabs = [
        { heading: "Tickets", route:"main.inbox", active:false, params:{} }
    ];

    var addTabDefault = {
        heading: '',
        route: null,
        active: false,
        params: null,
        closeable: false
    };

    $rootScope.addTab = function(options){
        if(!options.hasOwnProperty('route') || !options.route)
        {
            throw "Route is required";
        }

        var tabAlreadyAdded = false;
        for(var i in $scope.tabs)
        {
            var tab = $scope.tabs[i];
            if(tab.route == options.route && angular.equals(tab.params, options.params))
            {
                tabAlreadyAdded = true;
                break;
            }
        }
        if(!tabAlreadyAdded)
        {
            $scope.tabs.push($.extend({}, addTabDefault, options));
        }
        if(options.hasOwnProperty('active') && options.active === true)
        {
            $state.go(options.route, options.hasOwnProperty('params')?options.params:null);
        }
    };

    $scope.removeTab = function($event, tab){
        $event.preventDefault();
        if($scope.active(tab.route, tab.params))
        {
            $scope.go($scope.tabs[0].route, $scope.tabs[0].params);
        }
        $scope.tabs.splice($scope.tabs.indexOf(tab), 1);
    };

    $scope.go = function(route, params){
        $state.go(route, params);
    };
    $scope.active = function(route, params){
        return $state.is(route, params);
    };

    $scope.$on("$stateChangeSuccess", function() {
        $scope.tabs.forEach(function(tab) {
            tab.active = $scope.active(tab.route, tab.params);
        });
    });
});

main.html中:

<div class="container-fluid" id="sav-container">
    <div class="row-fluid">
        <div class="col-lg-2">
            <form role="form" id="searchForm" action="#">
                <div class="form-group has-feedback">
                    <input class="form-control" type="search" />
                    <span class="glyphicon glyphicon-search form-control-feedback"></span>
                </div>
            </form>
        </div>
        <div class="col-lg-10" id="support_main_menu">
            <ul class="nav nav-tabs">
                <li ng-repeat="t in tabs" ng-click="go(t.route, t.params)" ng-class="{active: t.active, closeable: t.closeable}" style="max-width: calc((100% - 128px) / {{tabs.length}});">
                    <a href class="nav-tab-text">
                        <button ng-show="t.closeable" ng-click="removeTab($event, t)" class="close" type="button">&times;</button>
                        <span>{{t.heading}}</span>
                    </a>
                </li>
            </ul>
        </div>
    </div>
    <div class="row-fluid">
        <div class="tab-content" ui-view></div>
    </div>
</div>

在我看来,我问的是非常标准的,但我遗憾地在互联网上找不到任何有用的东西

1 个答案:

答案 0 :(得分:1)

基本思想是在服务中存储状态(即票证列表)而不是控制器。服务在应用程序的生命周期中徘徊。有一些关于此的文章。我还在开发自己的方法,但这里有一个例子:

var RefereeRepository = function(resource)
{
  this.resource = resource; // angular-resource

  this.items = []; // cache of items i.e. tickets

  this.findAll = function(reload)
  {
    if (!reload) return this.items;

    return this.items = this.resource.findAll(); // Kicks off actual json request
  };
  this.findx = function(id) 
  { 
    return this.resource.find({ id: id }); // actual json query
  };

  this.find = function(id) // Uses local cache
  {
    var itemx = {};

    // Needs refining
    this.items.every(function(item) {
      if (item.id !== id) return true;
      itemx = item; 
      return false; 
    });
    return itemx;
  };
  this.update = function(item)
  {
    return this.resource.update(item);
  };
};

refereeComponent.factory('refereeRepository', ['$resource',
function($resource)
{
  var resource = 
  $resource('/app_dev.php/referees/:id', { id: '@id' }, {
    update: {method: 'PUT'},
    findAll:  { 
      method: 'GET' , 
      isArray:true,
      transformResponse: function(data)
      {
        var items = angular.fromJson(data);
        var referees = [];
        items.forEach(function(item) {
          var referee = new Referee(item); // Convert json to my object
          referees.push(referee);
        });
        return referees;
      }
    },
    find:  { 
      method: 'GET',
      transformResponse: function(data)
      {
        var item = angular.fromJson(data);
        return new Referee(item);
      }
    }
});
var refereeRepository = new RefereeRepository(resource);

// Load items when service is created
refereeRepository.findAll(true);

return refereeRepository;
}]);

基本上我们制作了一个refereeRepository服务,它向Web服务器查询裁判列表,然后缓存结果。然后控制器将使用缓存。

refereeComponent.controller('RefereeListController', 
  ['$scope', 'refereeRepository',
  function($scope, refereeRepository) 
  {
    $scope.referees = refereeRepository.findAll();
  }
]);