将状态加载为AngularJS中的模态叠加

时间:2015-04-01 15:10:59

标签: javascript jquery angularjs

我想将状态加载为模态,以便我可以覆盖状态而不影响我的应用程序中的任何其他状态。例如,如果我有一个类似的链接:

<a ui-sref="notes.add" modal>Add Note</a>

然后我想使用指令中断状态更改:

.directive('modal', ['$rootScope', '$state', '$http', '$compile',
    function($rootScope, $state, $http, $compile){
        return {
            priority: 0,
            restrict: 'A',
            link: function(scope, el, attrs) {  
                $rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
                    event.preventDefault();
                }); 
                el.click(function(e){
                    $http
                    .get('URL HERE')
                    .then(function(resp){
                        $('<div class="modal">' + resp.data + '</div>').appendTo('[ui-view=app]');
                        setTimeout(function(){
                            $('.wrapper').addClass('showModal');
                        },1);
                    });
                }); 
            }   
        }
    }
])

这会成功阻止状态更改并加载URL并将其作为模式附加到应用程序。 问题是它再次加载整个应用程序......

我如何只加载状态?例如模板文件和相邻的控制器。

状态如下:

.state('notes.add',
{
    parent: 'notes',
    url: '/add',
    views: {
        'content': {
            templateUrl: 'partials/notes/add.html',
            controller: 'NotesAddCtrl'
        }
    }
})

使用jQuery如何工作的示例:http://dev.driz.co.uk/AngularModal

了解如何通过AJAX访问StateA和StateB,使用History API更改URL以反映当前状态更改。

无论我是否在索引,StateA或StateB,我都可以将StateA或StateB作为模态加载(即使我已经在该状态上)并且它不会更改URL或者当前的内容,它只是覆盖了州内容。

这是我希望在AngularJS中能够做到的。

注意。此示例不能与浏览器后退和前进按钮一起使用,因为它是一个快速示例,而不是正确使用历史记录api。

3 个答案:

答案 0 :(得分:2)

我几天前已经看过你的问题了,尝试设置一些可行的东西似乎很有趣。

我已将uiSref指令作为开头,并修改代码以使用angular-bootstrap的$ modal来显示所需的状态。

angular.module('ui.router.modal', ['ui.router', 'ui.bootstrap'])
.directive('uiSrefModal', $StateRefModalDirective);

function parseStateRef(ref, current) {
  var preparsed = ref.match(/^\s*({[^}]*})\s*$/), parsed;
  if (preparsed) ref = current + '(' + preparsed[1] + ')';
  parsed = ref.replace(/\n/g, " ").match(/^([^(]+?)\s*(\((.*)\))?$/);
  if (!parsed || parsed.length !== 4) throw new Error("Invalid state ref '" + ref + "'");
  return { state: parsed[1], paramExpr: parsed[3] || null };
}

function stateContext(el) {
  var stateData = el.parent().inheritedData('$uiView');

  if (stateData && stateData.state && stateData.state.name) {
    return stateData.state;
  }
}

$StateRefModalDirective.$inject = ['$state', '$timeout', '$modal'];

function $StateRefModalDirective($state, $timeout, $modal) {
  var allowedOptions = ['location', 'inherit', 'reload'];

  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      var ref = parseStateRef(attrs.uiSrefModal, $state.current.name);
      var params = null, url = null, base = stateContext(element) || $state.$current;
      var newHref = null, isAnchor = element.prop("tagName") === "A";
      var isForm = element[0].nodeName === "FORM";
      var attr = isForm ? "action" : "href", nav = true;

      var options = { relative: base, inherit: true };
      var optionsOverride = scope.$eval(attrs.uiSrefModalOpts) || {};

      angular.forEach(allowedOptions, function(option) {
        if (option in optionsOverride) {
          options[option] = optionsOverride[option];
        }
      });

      var update = function(newVal) {
        if (newVal) params = angular.copy(newVal);
        if (!nav) return;

        newHref = $state.href(ref.state, params, options);

        if (newHref === null) {
          nav = false;
          return false;
        }
        attrs.$set(attr, newHref);
      };

      if (ref.paramExpr) {
        scope.$watch(ref.paramExpr, function(newVal, oldVal) {
          if (newVal !== params) update(newVal);
        }, true);
        params = angular.copy(scope.$eval(ref.paramExpr));
      }
      update();

      if (isForm) return;

      element.bind("click", function(e) {
        var button = e.which || e.button;
        if ( !(button > 1 || e.ctrlKey || e.metaKey || e.shiftKey || element.attr('target')) ) {
          e.preventDefault();

          var state = $state.get(ref.state);
          var modalInstance = $modal.open({
            template: '<div>\
              <div class="modal-header">\
                <h3 class="modal-title">' + ref.state + '</h3>\
              </div>\
              <div class="modal-body">\
                <ng-include src="\'' + state.templateUrl + '\'"></ng-include>\
              </div>\
            </div>',
            controller: state.controller,
            resolve: options.resolve
          });

          modalInstance.result.then(function (selectedItem) {
            $scope.selected = selectedItem;
          }, function () {
            console.log('Modal dismissed at: ' + new Date());
          });
        }
      });
    }
  };
}

您可以像<a ui-sref-modal="notes.add">Add Note</a>

一样使用它

指令要求angular-bootstrap解析模态对话框。您需要在应用中使用ui.router.modal模块。

答案 1 :(得分:1)

由于被要求提供我的评论的例子,

示例指令

  myapp.directive('openModal', function ($modal) {
    return function(scope, element, attrs) {
      element[0].addEventListener('click', function() {
        $modal.open({
          templateUrl : attrs.openModal,
          controller: attrs.controller,
          size: attrs.openModalSize,
          //scope: angular.element(element[0]).scope()
        });
      });
    };
  });

示例Html

<button 
  open-modal='views/poc/open-modal/small-modal.html'
  open-modal-size='sm' 
  controller="MyCtrl">modal small</button>

上述指令方法与使用状态没有太大区别,该状态包含templateUrlcontroller,但url不会更改。

.state('state1.list', {
  url: "/list",
  templateUrl: "partials/state1.list.html",
  controller: function($scope) {
    $scope.items = ["A", "List", "Of", "Items"];
  }
})

答案 2 :(得分:-1)

显然存在Ui-sref not generating hash in URL (Angular 1.3.0-rc.3)引用的问题 https://github.com/angular-ui/ui-router/issues/1397

似乎根据评论修正了。

我个人不喜欢html5mode因为它需要在您的服务器上进行额外的工作而没有明显的优势(我不认为将“更美丽的网址”作为证明额外工作的合理优势)。

使用路由器时还有另一个性能问题,即每次路由更改时都会重新创建视图DOM。我提到了一个很简单的解决方案 在this answer


作为旁注,http://dev.driz.co.uk/AngularModal/中的示例表现不佳。它不记录历史,所以我不能回去。此外,如果单击索引或模式等链接,然后重新加载,则不会获得相同的页面。


更新。 从评论中可以看出,打开模态时不需要路线更改。在这种情况下,最简单的解决方案是不要将ui-sref放在打开按钮上,让模态指令一起处理它。