2015-04-01 2 views
3

Я хочу загрузить состояние как модальное, чтобы я мог наложить состояние без каких-либо других состояний в моем приложении. Так, например, если у меня есть ссылка, как:Загрузка состояния как модального наложения в 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

Смотрите, как я могу получить доступ к StateA и StateB загрузку через AJAX, который использует API истории изменить URL-адрес, чтобы отразить текущее изменение состояния.

И независимо от того, являюсь ли я на индексе, StateA или StateB, я могу загрузить StateA или StateB как модальный (даже если я уже нахожусь в этом состоянии) и не изменяет URL или текущий контент, он просто накладывает содержимое штата.

Это то, что я хочу, чтобы иметь возможность делать в AngularJS.

Примечание. этот пример не работает с кнопками браузера назад и вперед из-за того, что он является быстрым примером и не использует историю api правильно.

+0

Похоже, вы перешли на другой URL-адрес, и какое состояние вы пытаетесь загрузить точно? –

+0

Да, состояние notes.add. Который можно получить в браузере через URL-адрес или получить доступ через JS в модальном режиме (без изменения URL-адреса (все это происходит, но оно загружает все приложение снова). – Cameron

+0

Вы пробовали предлагаемое здесь решение? Http: // stackoverflow .com/questions/21883559/open-a-modal-in-a-route-in-angularjs-with-angular-ui-bootstrap –

ответ

-1

Видимо есть проблема Ui-sref not generating hash in URL (Angular 1.3.0-rc.3) отсылая к https://github.com/angular-ui/ui-router/issues/1397

Это, кажется, фиксируется в соответствии с комментариями.

Мне лично не нравится html5mode, потому что он требует дополнительной работы на вашем сервере без видимых преимуществ (я не считаю, что «более красивый URL-адрес» является осязаемым преимуществом, чтобы оправдать дополнительную работу).

При использовании маршрутизаторов возникает другая проблема с производительностью, что при каждом изменении маршрута объект DOM воссоздается. Я упомянул очень простое решение в this answer.


В качестве побочного замечания, пример в http://dev.driz.co.uk/AngularModal/ не ведет себя достаточно хорошо. Он не записывает историю, поэтому я не могу вернуться. Кроме того, если вы нажимаете на такие ссылки, как Index или modals, а затем перезагружаете, вы не получаете одну и ту же страницу.


ОБНОВЛЕНИЕ. Кажется, из комментариев, что изменение маршрута не требуется при открытии модального. В этом случае самым простым решением является не поставить ui-sref на кнопку открытия, и пусть модальная директива будет обрабатывать его.

+0

Я заявил в вопросе, что пример был просто быстрым и грязным примером для объяснения концепции. И модальности не должны появляться при перезагрузке по дизайну. – Cameron

+0

Я не мог видеть никаких утверждений, что пример был «грязным», и эта функция об модалях в вашем вопросе. Помогает ли это решить вашу проблему? –

+0

См. Примечание в конце моего вопроса об этом, не используя историю api правильно. В любом случае ... Я не получаю ваш ответ? Можете ли вы показать пример кода, как загрузить состояние в оверлей? – Cameron

2

Я видел ваш вопрос несколько дней назад, и это казалось достаточно интересным, чтобы попытаться создать что-то, что сработает.

Я принял директиву uiSref в качестве начала и модифицировал код, чтобы использовать модальное выражение для модального бутстрапа, чтобы показать желаемое состояние.

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 в вашем приложении.

+0

Если вы хотите добавить запись histoyAPI, вы должны сделать это после открытия модального. –

+0

Это выглядит хорошо. Как насчет контроллеров? Как обычно, я связываю состояние с контроллером в '$ stateProvider' ... – Cameron

+0

вы можете передать контроллер модальному экземпляру, я думаю, он должен быть доступен на объекте' options' 'var modalInstance = $ modal. open ({ template: ..., controller: options.controller, resolve: options.resolve }); ' –

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> 

выше директива подход, не очень отличается от использования состояния, в котором имеет templateUrl и controller, за исключением того, что URL-адрес не изменяется.

.state('state1.list', { 
    url: "/list", 
    templateUrl: "partials/state1.list.html", 
    controller: function($scope) { 
    $scope.items = ["A", "List", "Of", "Items"]; 
    } 
}) 
Смежные вопросы